diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml
index cdeb4e3624f4f6aa78a0e1a1f6c3cfaa3cb33d20..4d33cc34e54ec5818e14827803b14006029e5a4e 100644
--- a/.docker/docker-compose.yml
+++ b/.docker/docker-compose.yml
@@ -78,23 +78,26 @@ services:
     restart: "no"
     container_name: dbrepo-auth-service
     hostname: auth-service
-    image: bitnami/keycloak:26.0.0-debian-12-r1
+    image: bitnami/keycloak:24.0.5-debian-12-r8
     volumes:
       - ./config/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh
       - ./config/master-realm.json:/opt/keycloak/data/import/master-realm.json
       - ./config/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json
+      - ./config/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar
     ports:
       - "8080:8080"
     environment:
       KEYCLOAK_ENABLE_HTTPS: "false"
       KEYCLOAK_ENABLE_STATISTICS: "true"
-      KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true"
       KEYCLOAK_DATABASE_HOST: "auth-db"
       KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}"
       KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}"
       KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}/api/user"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+      SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}"
     healthcheck:
-      test: curl --head -fsS http://localhost:9000/health/ready
+      test: curl -fsS http://localhost:8080/realms/master
       interval: 10s
       timeout: 5s
       retries: 12
@@ -109,7 +112,8 @@ services:
   dbrepo-auth-service-init:
     init: true
     restart: "no"
-    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.1
+    container_name: dbrepo-auth-service-init
+    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
     environment:
       AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin}
       AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin}
@@ -130,7 +134,7 @@ services:
     restart: "no"
     container_name: dbrepo-metadata-service
     hostname: metadata-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
@@ -193,7 +197,7 @@ services:
     restart: "no"
     container_name: dbrepo-analyse-service
     hostname: analyse-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
     environment:
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
@@ -248,7 +252,7 @@ services:
     restart: "no"
     container_name: dbrepo-search-db
     hostname: search-db
-    image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.3
     healthcheck:
       test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP
       interval: 10s
@@ -272,7 +276,7 @@ services:
     restart: "no"
     container_name: dbrepo-search-service
     hostname: search-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
     environment:
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
@@ -296,11 +300,15 @@ services:
     restart: "no"
     container_name: dbrepo-ui
     hostname: ui
-    image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
     environment:
       NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}"
-      NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}"
+      NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://gateway-service}"
       NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}"
     depends_on:
       dbrepo-search-service:
         condition: service_healthy
@@ -311,6 +319,8 @@ services:
       interval: 10s
       timeout: 5s
       retries: 12
+    extra_hosts:
+      - "localhost:host-gateway"
     logging:
       driver: json-file
 
@@ -365,7 +375,7 @@ services:
     init: true
     container_name: dbrepo-search-service-init
     hostname: search-service-init
-    image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
     environment:
       LOG_LEVEL: ${LOG_LEVEL:-info}
       METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}
@@ -422,7 +432,7 @@ services:
     restart: "no"
     container_name: dbrepo-dashboard-service
     hostname: dashboard-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.3
     ports:
       - "3000:3000"
     volumes:
@@ -449,7 +459,7 @@ services:
     init: true
     container_name: dbrepo-storage-service-init
     hostname: storage-service-init
-    image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
     environment:
       S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-seaweedfsadmin}
       S3_BUCKET: "${S3_BUCKET:-dbrepo}"
@@ -479,6 +489,7 @@ services:
       AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}"
       AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}"
       AWS_REGION: "${STORAGE_REGION_NAME:-default}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}"
     depends_on:
       dbrepo-storage-service:
         condition: service_healthy
@@ -494,7 +505,7 @@ services:
     restart: "no"
     container_name: dbrepo-data-service
     hostname: data-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.1
+    image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
diff --git a/.docs/.openapi/api-analyse.yaml b/.docs/.openapi/api-analyse.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..25e15521d5474324eab5e43adb8baa0b90312949
--- /dev/null
+++ b/.docs/.openapi/api-analyse.yaml
@@ -0,0 +1,332 @@
+{
+  "components": {
+    "schemas": {
+      "AnalysisDto": {
+        "properties": {
+          "columns": {
+            "items": {
+              "properties": {
+                "column_name": {
+                  "$ref": "#/components/schemas/ColumnAnalysisDto"
+                }
+              }
+            },
+            "type": "array"
+          },
+          "line_termination": {
+            "example": "\r\n",
+            "type": "string"
+          },
+          "separator": {
+            "example": ",",
+            "type": "string"
+          }
+        },
+        "type": "object"
+      },
+      "ColumnAnalysisDto": {
+        "properties": {
+          "d": {
+            "example": 4,
+            "type": "integer"
+          },
+          "dfid": {
+            "example": null,
+            "type": "integer"
+          },
+          "enums": {
+            "example": null,
+            "properties": {
+              "type": "string"
+            },
+            "type": "array"
+          },
+          "null_allowed": {
+            "type": "boolean"
+          },
+          "sets": {
+            "example": null,
+            "properties": {
+              "type": "string"
+            },
+            "type": "array"
+          },
+          "size": {
+            "example": 10,
+            "type": "integer"
+          },
+          "type": {
+            "example": "decimal",
+            "type": "string"
+          }
+        },
+        "type": "object"
+      },
+      "ErrorDto": {
+        "properties": {
+          "message": {
+            "example": "Message",
+            "type": "string"
+          },
+          "success": {
+            "example": false,
+            "type": "boolean"
+          }
+        },
+        "type": "object"
+      },
+      "KeysDto": {
+        "properties": {
+          "keys": {
+            "items": {
+              "properties": {
+                "column_name": {
+                  "format": "int64",
+                  "type": "integer"
+                }
+              }
+            },
+            "type": "array"
+          }
+        },
+        "required": [
+          "keys"
+        ],
+        "type": "object"
+      }
+    },
+    "securitySchemes": {
+      "basicAuth": {
+        "in": "header",
+        "scheme": "basic",
+        "type": "http"
+      },
+      "bearerAuth": {
+        "bearerFormat": "JWT",
+        "in": "header",
+        "scheme": "bearer",
+        "type": "http"
+      }
+    }
+  },
+  "externalDocs": {
+    "description": "Sourcecode Documentation",
+    "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/"
+  },
+  "info": {
+    "contact": {
+      "email": "andreas.rauber@tuwien.ac.at",
+      "name": "Prof. Andreas Rauber"
+    },
+    "description": "Service that analyses data structures",
+    "license": {
+      "name": "Apache 2.0",
+      "url": "https://www.apache.org/licenses/LICENSE-2.0"
+    },
+    "title": "Database Repository Analyse Service API",
+    "version": "1.5"
+  },
+  "openapi": "3.0.0",
+  "paths": {
+    "/api/analyse/datatypes": {
+      "get": {
+        "consumes": [
+          "application/json"
+        ],
+        "description": "Determines MySQL 8 datatypes of a given dataset. Requires role `table-semantic-analyse`.",
+        "operationId": "analyse_datatypes",
+        "parameters": [
+          {
+            "example": "filename_s3_key",
+            "in": "query",
+            "name": "filename",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "example": ",",
+            "in": "query",
+            "name": "separator",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "example": "false",
+            "in": "query",
+            "name": "enum",
+            "required": false,
+            "schema": {
+              "type": "boolean"
+            }
+          },
+          {
+            "example": "2.5",
+            "in": "query",
+            "name": "enum_tol",
+            "required": false,
+            "schema": {
+              "type": "float"
+            }
+          }
+        ],
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "202": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/AnalysisDto"
+                }
+              }
+            },
+            "description": "Determined data types successfully"
+          },
+          "400": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ErrorDto"
+                }
+              }
+            },
+            "description": "Failed to determine data types"
+          },
+          "404": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ErrorDto"
+                }
+              }
+            },
+            "description": "Failed to find file in Storage Service"
+          },
+          "500": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ErrorDto"
+                }
+              }
+            },
+            "description": "Unexpected system error"
+          }
+        },
+        "security": [
+          {
+            "bearerAuth": []
+          },
+          {
+            "basicAuth": []
+          }
+        ],
+        "summary": "Determine datatypes",
+        "tags": [
+          "analyse-endpoint"
+        ]
+      }
+    },
+    "/api/analyse/keys": {
+      "get": {
+        "consumes": [
+          "application/json"
+        ],
+        "description": "Determines primary keys of a given dataset. Requires role `table-semantic-analyse`.",
+        "operationId": "analyse_keys",
+        "parameters": [
+          {
+            "example": "filename_s3_key",
+            "in": "query",
+            "name": "filename",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "example": ",",
+            "in": "query",
+            "name": "separator",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "202": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/KeysDto"
+                }
+              }
+            },
+            "description": "Determined keys successfully"
+          },
+          "400": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ErrorDto"
+                }
+              }
+            },
+            "description": "Failed to determine keys"
+          },
+          "404": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ErrorDto"
+                }
+              }
+            },
+            "description": "Failed to find file in Storage Service or is empty"
+          },
+          "500": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ErrorDto"
+                }
+              }
+            },
+            "description": "Unexpected system error"
+          }
+        },
+        "security": [
+          {
+            "bearerAuth": []
+          },
+          {
+            "basicAuth": []
+          }
+        ],
+        "summary": "Determine keys",
+        "tags": [
+          "analyse-endpoint"
+        ]
+      }
+    }
+  },
+  "servers": [
+    {
+      "description": "Generated server url",
+      "url": "http://localhost:5000"
+    },
+    {
+      "description": "Sandbox",
+      "url": "https://test.dbrepo.tuwien.ac.at"
+    }
+  ]
+}
diff --git a/.docs/.openapi/api-data.yaml b/.docs/.openapi/api-data.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bd14ba55057657c5a38d47cc29875d41e5cc1e71
--- /dev/null
+++ b/.docs/.openapi/api-data.yaml
@@ -0,0 +1,1877 @@
+openapi: 3.0.1
+info:
+  title: Database Repository Data Service API
+  description: Service that manages the data
+  contact:
+    name: Prof. Andreas Rauber
+    email: andreas.rauber@tuwien.ac.at
+  license:
+    name: Apache 2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0
+  version: 1.6.2
+externalDocs:
+  description: Sourcecode Documentation
+  url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6.2/system-services-metadata/
+servers:
+- url: http://localhost
+  description: Development instance
+- url: https://test.dbrepo.tuwien.ac.at
+  description: Staging instance
+paths:
+  /api/database/{databaseId}/view/{viewId}/data:
+    get:
+      tags:
+      - view-endpoint
+      summary: Get view data
+      description: "Gets data from a view of a database. For private databases, the\
+        \ user needs at least *READ* access to the associated database. Requires role\
+        \ `view-database-view-data`."
+      operationId: getData
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      responses:
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find view in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "409":
+          description: View schema could not be mapped
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Request pagination is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to retrieve view data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Retrieved view data
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of rows
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: string
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+    head:
+      tags:
+      - view-endpoint
+      summary: Get view data
+      description: "Gets data from a view of a database. For private databases, the\
+        \ user needs at least *READ* access to the associated database. Requires role\
+        \ `view-database-view-data`."
+      operationId: getData_1
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      responses:
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find view in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "409":
+          description: View schema could not be mapped
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Request pagination is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to retrieve view data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Retrieved view data
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of rows
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: string
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/table/{tableId}/data:
+    get:
+      tags:
+      - table-endpoint
+      summary: Get table data
+      description: "Gets data from a table with id. For a table in a private database,\
+        \ the user needs to have at least *READ* access to the associated database.\
+        \ Requests with HTTP method **GET** return the full dataset, requests with\
+        \ HTTP method **HEAD** only the number of tuples in the `X-Count` header."
+      operationId: getData_2
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Request pagination or table data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Get table data
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of rows
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: string
+        "403":
+          description: Not allowed to get table data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+    put:
+      tags:
+      - table-endpoint
+      summary: Update tuple
+      description: "Updates a data tuple into a table, then the table statistics are\
+        \ updated. The user needs to have at least *WRITE_OWN* access to the associated\
+        \ database. Requires role `insert-table-data`."
+      operationId: updateRawTuple
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Authorization
+        in: header
+        required: true
+        schema:
+          type: string
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/TupleUpdateDto"
+        required: true
+      responses:
+        "400":
+          description: Request pagination or table data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated table data
+        "403":
+          description: Update table data not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+    post:
+      tags:
+      - table-endpoint
+      summary: Insert tuple
+      description: "Inserts a data tuple into a table, then the table statistics are\
+        \ updated. The user needs to have at least *WRITE_OWN* access to the associated\
+        \ database. Requires role `insert-table-data`."
+      operationId: insertRawTuple
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Authorization
+        in: header
+        required: true
+        schema:
+          type: string
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/TupleDto"
+        required: true
+      responses:
+        "404":
+          description: Failed to find table in metadata database or blob in storage
+            service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Request pagination or table data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created table data
+        "503":
+          description: Failed to establish connection with the metadata service or
+            storage service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Create table data not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+    delete:
+      tags:
+      - table-endpoint
+      summary: Delete tuple
+      description: "Deletes a data tuple into a table, then the table statistics are\
+        \ updated. The user needs to have at least *WRITE_OWN* access to the associated\
+        \ database. Requires role `delete-table-data`."
+      operationId: deleteRawTuple
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Authorization
+        in: header
+        required: true
+        schema:
+          type: string
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/TupleDeleteDto"
+        required: true
+      responses:
+        "400":
+          description: Request pagination or table data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted table data
+        "403":
+          description: Delete table data not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+    head:
+      tags:
+      - table-endpoint
+      summary: Get table data
+      description: "Gets data from a table with id. For a table in a private database,\
+        \ the user needs to have at least *READ* access to the associated database.\
+        \ Requests with HTTP method **GET** return the full dataset, requests with\
+        \ HTTP method **HEAD** only the number of tuples in the `X-Count` header."
+      operationId: getData_3
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Request pagination or table data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Get table data
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of rows
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: string
+        "403":
+          description: Not allowed to get table data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/subset/{subsetId}/data:
+    get:
+      tags:
+      - subset-endpoint
+      summary: Get subset data
+      description: "Gets data of subset with id. For private databases, the user needs\
+        \ at least *READ* access to the associated database. Requests with HTTP method\
+        \ **GET** return the subset dataset, requests with HTTP method **HEAD** only\
+        \ the number of rows in the subset dataset in the `X-Count` header"
+      operationId: getData_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: subsetId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "503":
+          description: Failed to communicate with database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Retrieved subset data
+          headers:
+            Access-Control-Expose-Headers:
+              description: Reverse proxy exposing of custom headers
+              required: true
+              style: simple
+            X-Count:
+              description: Number of rows
+              style: simple
+            X-Id:
+              description: The subset id
+              required: true
+              style: simple
+            X-Headers:
+              description: The list of headers separated by comma
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: string
+        "400":
+          description: Invalid pagination
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database or query in query
+            store of the data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to retrieve subset data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    head:
+      tags:
+      - subset-endpoint
+      summary: Get subset data
+      description: "Gets data of subset with id. For private databases, the user needs\
+        \ at least *READ* access to the associated database. Requests with HTTP method\
+        \ **GET** return the subset dataset, requests with HTTP method **HEAD** only\
+        \ the number of rows in the subset dataset in the `X-Count` header"
+      operationId: getData_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: subsetId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "503":
+          description: Failed to communicate with database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Retrieved subset data
+          headers:
+            Access-Control-Expose-Headers:
+              description: Reverse proxy exposing of custom headers
+              required: true
+              style: simple
+            X-Count:
+              description: Number of rows
+              style: simple
+            X-Id:
+              description: The subset id
+              required: true
+              style: simple
+            X-Headers:
+              description: The list of headers separated by comma
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: string
+        "400":
+          description: Invalid pagination
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database or query in query
+            store of the data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to retrieve subset data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/subset/{queryId}:
+    put:
+      tags:
+      - subset-endpoint
+      summary: Persist subset
+      description: Persists a subset with id. Requires role `persist-query`.
+      operationId: persist
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: queryId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/QueryPersistDto"
+        required: true
+      responses:
+        "503":
+          description: Failed to communicate with database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Persisted subset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/QueryDto"
+        "403":
+          description: Not allowed to persist subset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "417":
+          description: Failed to persist subset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database or query in query
+            store of the data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Malformed select query
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/data/import:
+    post:
+      tags:
+      - table-endpoint
+      summary: Import dataset
+      description: Imports a dataset in a table. Then update the table statistics.
+        The user needs to have at least *WRITE_OWN* access to the associated database
+        when importing into a owned table. Otherwise *WRITE_ALL* access in needed.
+        Requires role `insert-table-data`.
+      operationId: importDataset
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Authorization
+        in: header
+        required: true
+        schema:
+          type: string
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ImportDto"
+        required: true
+      responses:
+        "202":
+          description: Imported dataset successfully
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Import table dataset not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Dataset and/or query are malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/subset:
+    get:
+      tags:
+      - subset-endpoint
+      summary: Find subsets
+      description: "Finds subsets in the query store. When the database schema is\
+        \ marked as hidden, the user needs to be authorized, have at least read-access\
+        \ to the database. The result can be optionally filtered by setting `persisted`.\
+        \ When set to *true*, only persisted queries are returned, otherwise only\
+        \ non-persisted queries are returned."
+      operationId: list
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: persisted
+        in: query
+        required: false
+        schema:
+          type: boolean
+      responses:
+        "503":
+          description: Failed to communicate with database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database or query in query
+            store of the data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found subsets
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/QueryDto"
+        "403":
+          description: Not allowed to find subsets
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+    post:
+      tags:
+      - subset-endpoint
+      summary: Create subset
+      description: Creates a subset in the query store of the data database. Can also
+        be used without authentication if (and only if) the database is marked as
+        public (i.e. when `is_public` = `is_schema_public` is set to `true`). Otherwise
+        at least read access is required.
+      operationId: create
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      - name: page
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ExecuteStatementDto"
+        required: true
+      responses:
+        "201":
+          description: Created subset
+          content:
+            application/json:
+              schema:
+                type: string
+        "503":
+          description: Failed to communicate with database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "501":
+          description: Failed to execute query as it contains non-supported keywords
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to find subset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database or query in query
+            store of the data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Malformed select query
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "417":
+          description: Failed to insert query into query store of data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/view/{viewId}/export:
+    get:
+      tags:
+      - view-endpoint
+      summary: Get view data
+      description: "Gets data from view with id as downloadable file. For tables in\
+        \ private databases, the user needs to have at least *READ* access to the\
+        \ associated database."
+      operationId: exportDataset
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      responses:
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Export view data not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find view in metadata database or export dataset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Exported view data
+          content:
+            application/json:
+              schema:
+                type: string
+                format: binary
+        "400":
+          description: Request pagination or view data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/table/{tableId}/history:
+    get:
+      tags:
+      - table-endpoint
+      summary: Get history
+      description: "Gets the insert/delete operations history performed. For tables\
+        \ in private databases, the user needs to have at least *READ* access to the\
+        \ associated database."
+      operationId: getHistory
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: size
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: Find table history not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find table history in data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: "Invalid pagination size request, must be > 0"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found table history
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/TableHistoryDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/table/{tableId}/export:
+    get:
+      tags:
+      - table-endpoint
+      summary: Get table data
+      description: "Gets data from table with id as downloadable file. For tables\
+        \ in private databases, the user needs to have at least *READ* access to the\
+        \ associated database."
+      operationId: exportDataset_1
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      responses:
+        "400":
+          description: Request pagination or table data select query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to establish connection with the metadata service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Exported table data
+          content:
+            application/json:
+              schema:
+                type: string
+                format: binary
+        "404":
+          description: Failed to find table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Export table data not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+  /api/database/{databaseId}/subset/{subsetId}:
+    get:
+      tags:
+      - subset-endpoint
+      summary: Find subset
+      description: "Finds a subset in the data database.  When the database schema\
+        \ is marked as hidden, the user needs to be authorized, have at least read-access\
+        \ to the database.  Requests with HTTP header `Accept=application/json` return\
+        \ the metadata, requests with HTTP header `Accept=text/csv` return the data\
+        \ as downloadable file."
+      operationId: findById
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: subsetId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Accept
+        in: header
+        required: true
+        schema:
+          type: string
+      - name: timestamp
+        in: query
+        required: false
+        schema:
+          type: string
+          format: date-time
+      responses:
+        "503":
+          description: Failed to communicate with database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to find subset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "406":
+          description: Failed to find acceptable representation
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found subset
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/QueryDto"
+            text/csv: {}
+        "404":
+          description: Failed to find database in metadata database or query in query
+            store of the data database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Malformed select query
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - basicAuth: []
+      - bearerAuth: []
+components:
+  schemas:
+    ApiErrorDto:
+      required:
+      - code
+      - message
+      - status
+      type: object
+      properties:
+        status:
+          type: string
+          example: NOT_FOUND
+          enum:
+          - 100 CONTINUE
+          - 101 SWITCHING_PROTOCOLS
+          - 102 PROCESSING
+          - 103 EARLY_HINTS
+          - 103 CHECKPOINT
+          - 200 OK
+          - 201 CREATED
+          - 202 ACCEPTED
+          - 203 NON_AUTHORITATIVE_INFORMATION
+          - 204 NO_CONTENT
+          - 205 RESET_CONTENT
+          - 206 PARTIAL_CONTENT
+          - 207 MULTI_STATUS
+          - 208 ALREADY_REPORTED
+          - 226 IM_USED
+          - 300 MULTIPLE_CHOICES
+          - 301 MOVED_PERMANENTLY
+          - 302 FOUND
+          - 302 MOVED_TEMPORARILY
+          - 303 SEE_OTHER
+          - 304 NOT_MODIFIED
+          - 305 USE_PROXY
+          - 307 TEMPORARY_REDIRECT
+          - 308 PERMANENT_REDIRECT
+          - 400 BAD_REQUEST
+          - 401 UNAUTHORIZED
+          - 402 PAYMENT_REQUIRED
+          - 403 FORBIDDEN
+          - 404 NOT_FOUND
+          - 405 METHOD_NOT_ALLOWED
+          - 406 NOT_ACCEPTABLE
+          - 407 PROXY_AUTHENTICATION_REQUIRED
+          - 408 REQUEST_TIMEOUT
+          - 409 CONFLICT
+          - 410 GONE
+          - 411 LENGTH_REQUIRED
+          - 412 PRECONDITION_FAILED
+          - 413 PAYLOAD_TOO_LARGE
+          - 413 REQUEST_ENTITY_TOO_LARGE
+          - 414 URI_TOO_LONG
+          - 414 REQUEST_URI_TOO_LONG
+          - 415 UNSUPPORTED_MEDIA_TYPE
+          - 416 REQUESTED_RANGE_NOT_SATISFIABLE
+          - 417 EXPECTATION_FAILED
+          - 418 I_AM_A_TEAPOT
+          - 419 INSUFFICIENT_SPACE_ON_RESOURCE
+          - 420 METHOD_FAILURE
+          - 421 DESTINATION_LOCKED
+          - 422 UNPROCESSABLE_ENTITY
+          - 423 LOCKED
+          - 424 FAILED_DEPENDENCY
+          - 425 TOO_EARLY
+          - 426 UPGRADE_REQUIRED
+          - 428 PRECONDITION_REQUIRED
+          - 429 TOO_MANY_REQUESTS
+          - 431 REQUEST_HEADER_FIELDS_TOO_LARGE
+          - 451 UNAVAILABLE_FOR_LEGAL_REASONS
+          - 500 INTERNAL_SERVER_ERROR
+          - 501 NOT_IMPLEMENTED
+          - 502 BAD_GATEWAY
+          - 503 SERVICE_UNAVAILABLE
+          - 504 GATEWAY_TIMEOUT
+          - 505 HTTP_VERSION_NOT_SUPPORTED
+          - 506 VARIANT_ALSO_NEGOTIATES
+          - 507 INSUFFICIENT_STORAGE
+          - 508 LOOP_DETECTED
+          - 509 BANDWIDTH_LIMIT_EXCEEDED
+          - 510 NOT_EXTENDED
+          - 511 NETWORK_AUTHENTICATION_REQUIRED
+        message:
+          type: string
+          example: Error message
+        code:
+          type: string
+          example: error.service.code
+    TupleUpdateDto:
+      required:
+      - data
+      - keys
+      type: object
+      properties:
+        data:
+          type: object
+          additionalProperties:
+            type: object
+            example:
+              key: value
+          example:
+            key: value
+        keys:
+          type: object
+          additionalProperties:
+            type: object
+            example:
+              id: 1
+          example:
+            id: 1
+    QueryPersistDto:
+      required:
+      - persist
+      type: object
+      properties:
+        persist:
+          type: boolean
+          example: true
+    CreatorBriefDto:
+      required:
+      - creator_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 11
+        affiliation:
+          type: string
+          example: Brown University
+        creator_name:
+          type: string
+          example: "Carberry, Josiah"
+        name_type:
+          type: string
+          example: Personal
+          enum:
+          - Personal
+          - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+          - ORCID
+          - ROR
+          - ISNI
+          - GRID
+        affiliation_identifier:
+          type: string
+          example: https://ror.org/05gq02987
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+          - ROR
+          - GRID
+          - ISNI
+    IdentifierBriefDto:
+      required:
+      - creators
+      - database_id
+      - id
+      - owned_by
+      - publication_year
+      - publisher
+      - status
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 2
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreatorBriefDto"
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierTitleDto"
+        doi:
+          type: string
+          example: 10.1038/nphys1170
+        publisher:
+          type: string
+          example: TU Wien
+        status:
+          type: string
+          example: draft
+          enum:
+          - draft
+          - published
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        view_id:
+          type: integer
+          format: int64
+          example: 1
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        owned_by:
+          type: string
+          format: uuid
+          example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5
+    IdentifierTitleDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        title:
+          type: string
+          example: Airquality Demonstrator
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          enum:
+          - AlternativeTitle
+          - Subtitle
+          - TranslatedTitle
+          - Other
+    QueryDto:
+      required:
+      - database_id
+      - execution
+      - id
+      - identifiers
+      - is_persisted
+      - owner
+      - query
+      - query_hash
+      - query_normalized
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        execution:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality`
+        type:
+          type: string
+          example: query
+          enum:
+          - query
+          - view
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierBriefDto"
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_normalized:
+          type: string
+          example: SELECT `id` FROM `air_quality`
+        query_hash:
+          type: string
+          example: 17e682f060b5f8e47ea04c5c4855908b0a5ad612022260fe50e11ecb0cc0ab76
+        is_persisted:
+          type: boolean
+          example: true
+        result_hash:
+          type: string
+          example: 17e682f060b5f8e47ea04c5c4855908b0a5ad612022260fe50e11ecb0cc0ab76
+        result_number:
+          type: integer
+          format: int64
+          example: 1
+    UserBriefDto:
+      required:
+      - id
+      - username
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+          example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4
+        username:
+          type: string
+          description: Only contains lowercase characters
+          example: jcarberry
+        name:
+          type: string
+          example: Josiah Carberry
+        orcid:
+          type: string
+          example: 0000-0002-1825-0097
+        qualified_name:
+          type: string
+          example: Josiah Carberry — @jcarberry
+        given_name:
+          type: string
+          example: Josiah
+        family_name:
+          type: string
+          example: Carberry
+    TupleDto:
+      required:
+      - data
+      type: object
+      properties:
+        data:
+          type: object
+          additionalProperties:
+            type: object
+            example:
+              key: value
+          example:
+            key: value
+    ImportDto:
+      required:
+      - header
+      - location
+      - separator
+      type: object
+      properties:
+        location:
+          type: string
+          example: file.csv
+        header:
+          type: boolean
+          description: "If true, the first line contains the column names, otherwise\
+            \ it contains only data"
+          example: true
+        separator:
+          type: string
+          example: ","
+        quote:
+          type: string
+          example: '"'
+        line_termination:
+          type: string
+          example: \r\n
+    ExecuteStatementDto:
+      required:
+      - statement
+      type: object
+      properties:
+        statement:
+          type: string
+          example: SELECT `id` FROM `air_quality`
+    TableHistoryDto:
+      required:
+      - event
+      - timestamp
+      - total
+      type: object
+      properties:
+        timestamp:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        event:
+          type: string
+        total:
+          type: integer
+          format: int64
+          example: 1
+    TupleDeleteDto:
+      required:
+      - keys
+      type: object
+      properties:
+        keys:
+          type: object
+          additionalProperties:
+            type: object
+            example:
+              id: 1
+          example:
+            id: 1
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+    bearerAuth:
+      type: http
+      scheme: bearer
+      bearerFormat: JWT
diff --git a/.docs/.openapi/api-metadata.yaml b/.docs/.openapi/api-metadata.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..18fb71db29de89369c93de29296e1d85abc58b37
--- /dev/null
+++ b/.docs/.openapi/api-metadata.yaml
@@ -0,0 +1,7243 @@
+openapi: 3.0.1
+info:
+  title: Database Repository Metadata Service API
+  description: Service that manages the metadata
+  contact:
+    name: Prof. Andreas Rauber
+    email: andreas.rauber@tuwien.ac.at
+  license:
+    name: Apache 2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0
+  version: 1.6.2
+externalDocs:
+  description: Sourcecode Documentation
+  url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6.2/system-services-metadata/
+servers:
+- url: http://localhost
+  description: Development instance
+- url: https://test.dbrepo.tuwien.ac.at
+  description: Staging instance
+paths:
+  /api/database:
+    get:
+      tags:
+      - database-endpoint
+      summary: List databases
+      description: "Lists all databases in the metadata database. Requests with HTTP\
+        \ method **GET** return the list of databases, requests with HTTP method **HEAD**\
+        \ only the number in the `X-Count` header."
+      operationId: list
+      parameters:
+      - name: internal_name
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "200":
+          description: List of databases
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of databases
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/DatabaseBriefDto"
+    post:
+      tags:
+      - database-endpoint
+      summary: Create database
+      description: Creates a database in the container with id. Requires roles `create-database`.
+      operationId: create_5
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateDatabaseDto"
+        required: true
+      responses:
+        "403":
+          description: Database create permission is missing or grant permissions
+            at broker service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "423":
+          description: Database quota exceeded
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Database create query is malformed or image is not supported
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to fin container/user/database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created a new database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "409":
+          description: Query store could not be created
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    head:
+      tags:
+      - database-endpoint
+      summary: List databases
+      description: "Lists all databases in the metadata database. Requests with HTTP\
+        \ method **GET** return the list of databases, requests with HTTP method **HEAD**\
+        \ only the number in the `X-Count` header."
+      operationId: list_1
+      parameters:
+      - name: internal_name
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "200":
+          description: List of databases
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of databases
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/DatabaseBriefDto"
+  /api/database/{databaseId}/access/{userId}:
+    get:
+      tags:
+      - access-endpoint
+      summary: Find/Check access
+      description: "Finds or checks access of a user with given id to a database with\
+        \ given id. Requests with HTTP method **GET** return the access object, requests\
+        \ with HTTP method **HEAD** only the status. When the user has at least *READ*\
+        \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\
+        \ or `check-foreign-database-access`."
+      operationId: find
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "200":
+          description: Found database access
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseAccessDto"
+        "403":
+          description: No access to this database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - access-endpoint
+      summary: Modify access
+      description: Modifies access of a user with given id to database with given
+        id. Requires role `update-database-access`.
+      operationId: update_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateAccessDto"
+        required: true
+      responses:
+        "403":
+          description: Modify access not permitted when no access is granted in the
+            first place
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Access could not be updated due to connection error in the
+            data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Access could not be updated in the data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Modified access
+        "404":
+          description: Database or user not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Modify access query or database connection is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    post:
+      tags:
+      - access-endpoint
+      summary: Give access
+      description: Give a user with given id access to some database with given id.
+        Requires role `create-database-access`.
+      operationId: create_8
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateAccessDto"
+        required: true
+      responses:
+        "502":
+          description: Access could not be created due to connection error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Access could not be created in the data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Granting access query or database connection is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Failed giving access
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database or user not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Granting access succeeded
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseAccessDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - access-endpoint
+      summary: Delete access
+      description: Delete access of a user with id to a database with id. Requires
+        role `delete-database-access`.
+      operationId: revoke
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "502":
+          description: Access could not be created due to connection error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Revoke of access not permitted as no access was found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted access
+        "400":
+          description: Modify access query or database connection is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "User, database with access was not found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Access could not be revoked in the data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    head:
+      tags:
+      - access-endpoint
+      summary: Find/Check access
+      description: "Finds or checks access of a user with given id to a database with\
+        \ given id. Requests with HTTP method **GET** return the access object, requests\
+        \ with HTTP method **HEAD** only the status. When the user has at least *READ*\
+        \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\
+        \ or `check-foreign-database-access`."
+      operationId: find_1
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "200":
+          description: Found database access
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseAccessDto"
+        "403":
+          description: No access to this database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user/{userId}:
+    get:
+      tags:
+      - user-endpoint
+      summary: Get user
+      description: Gets own user information from the metadata database. Requires
+        authentication. Foreign user information can only be obtained if additional
+        role `find-foreign-user` is present. Finding information about internal users
+        results in a 404 error.
+      operationId: find_2
+      parameters:
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "404":
+          description: User was not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found user
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserDto"
+        "403":
+          description: Find user is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - user-endpoint
+      summary: Update user
+      description: Updates user with id. Requires role `modify-user-information`.
+      operationId: modify
+      parameters:
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UserUpdateDto"
+        required: true
+      responses:
+        "202":
+          description: Modified user information
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserDto"
+        "403":
+          description: Not allowed to modify user metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Modify user query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/user in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user/{userId}/password:
+    put:
+      tags:
+      - user-endpoint
+      summary: Update user password
+      description: Updates password of user with id. Requires authentication.
+      operationId: password
+      parameters:
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UserPasswordDto"
+        required: true
+      responses:
+        "400":
+          description: Invalid password payload
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Modified user password
+        "403":
+          description: Not allowed to change foreign user password
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/user in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to get user in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to auth service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user/token:
+    put:
+      tags:
+      - user-endpoint
+      summary: Refresh token
+      description: Refreshes user token by refresh token.
+      operationId: refreshToken
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/RefreshTokenRequestDto"
+        required: true
+      responses:
+        "403":
+          description: Not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Invalid refresh token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Refreshed user token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TokenDto"
+        "502":
+          description: Connection to auth service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    post:
+      tags:
+      - user-endpoint
+      summary: Create token
+      description: Creates a user token via the Auth Service.
+      operationId: getToken
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/LoginRequestDto"
+        required: true
+      responses:
+        "404":
+          description: Failed to find user in auth database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "428":
+          description: Account is not fully setup in auth service (requires password
+            change?)
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Invalid login request
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Obtained user token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TokenDto"
+        "403":
+          description: Not allowed to get token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to get user in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to auth service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/ontology/{ontologyId}:
+    get:
+      tags:
+      - ontology-endpoint
+      summary: Find ontology
+      description: Finds an ontology with id in the metadata database.
+      operationId: find_3
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Find one ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OntologyDto"
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    put:
+      tags:
+      - ontology-endpoint
+      summary: Update ontology
+      description: Updates an ontology with id. Requires role `update-ontology`.
+      operationId: update
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OntologyModifyDto"
+        required: true
+      responses:
+        "202":
+          description: Updated ontology successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OntologyDto"
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - ontology-endpoint
+      summary: Delete ontology
+      description: Deletes an ontology with given id. Requires role `delete-ontology`.
+      operationId: delete
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted ontology successfully
+          content:
+            application/json: {}
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/message/{messageId}:
+    put:
+      tags:
+      - message-endpoint
+      summary: Update message
+      description: Updates a message with id. Requires role `update-maintenance-message`.
+      operationId: update_1
+      parameters:
+      - name: messageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/BannerMessageUpdateDto"
+        required: true
+      responses:
+        "202":
+          description: Updated message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/BannerMessageBriefDto"
+        "404":
+          description: Could not find message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - message-endpoint
+      summary: Delete message
+      description: Deletes a message with id. Requires role `delete-maintenance-message`.
+      operationId: delete_1
+      parameters:
+      - name: messageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Could not find message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted message
+          content:
+            application/json: {}
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/image/{imageId}:
+    get:
+      tags:
+      - image-endpoint
+      summary: Find image
+      description: Finds a container image in the metadata database.
+      operationId: findById
+      parameters:
+      - name: imageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Found image
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ImageDto"
+        "404":
+          description: Image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    put:
+      tags:
+      - image-endpoint
+      summary: Update image
+      description: Updates container image in the metadata database. Requires role
+        `modify-image`.
+      operationId: update_2
+      parameters:
+      - name: imageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ImageChangeDto"
+        required: true
+      responses:
+        "404":
+          description: Image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated image successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ImageDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - image-endpoint
+      summary: Delete image
+      description: Deletes a container image in the metadata database. Requires role
+        `delete-image`.
+      operationId: delete_2
+      parameters:
+      - name: imageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted image successfully
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/identifier/{identifierId}:
+    get:
+      tags:
+      - identifier-endpoint
+      summary: Find identifier
+      description: Finds an identifier with id. The response format depends on the
+        HTTP `Accept` header set on the request.
+      operationId: find_6
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Accept
+        in: header
+        required: true
+        schema:
+          type: string
+      responses:
+        "410":
+          description: Failed to retrieve from S3 endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to data service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to find in data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found identifier successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+            application/ld+json:
+              schema:
+                $ref: "#/components/schemas/LdDatasetDto"
+            text/csv: {}
+            text/xml: {}
+            text/bibliography: {}
+            text/bibliography; style=apa: {}
+            text/bibliography; style=ieee: {}
+            text/bibliography; style=bibtex: {}
+        "400":
+          description: "Identifier could not be exported, the requested style is not\
+            \ known"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "409":
+          description: Exported resource was not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Identifier could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "406":
+          description: Failed to find acceptable representation
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    put:
+      tags:
+      - identifier-endpoint
+      summary: Save identifier
+      description: Saves an identifier with id as a draft identifier. Identifiers
+        can only be created for objects the user has at least *READ* access in the
+        associated database (requires role `create-identifier`) or for any object
+        in any database (requires role `create-foreign-identifier`).
+      operationId: save
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/IdentifierSaveDto"
+        required: true
+      responses:
+        "400":
+          description: Identifier form contains invalid request data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Failed to find database, table or view"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Insufficient access rights or authorities
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Saved identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - identifier-endpoint
+      summary: Delete identifier
+      description: Deletes an identifier with id. Requires role `delete-identifier`.
+      operationId: delete_3
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: Deleting identifier not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Identifier or database could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to delete in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted identifier
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/identifier/{identifierId}/publish:
+    put:
+      tags:
+      - identifier-endpoint
+      summary: Publish identifier
+      description: Publishes an identifier with id. A published identifier cannot
+        be changed anymore. Requires role `publish-identifier`.
+      operationId: publish
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Identifier form contains invalid request data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Failed to find database, table or view"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Insufficient access rights or authorities
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Published identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/visibility:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database visibility
+      description: Updates the database with id on the visibility. Only the database
+        owner can perform this operation. Requires role `modify-database-visibility`.
+      operationId: visibility
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseModifyVisibilityDto"
+        required: true
+      responses:
+        "400":
+          description: The visibility payload is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Visibility modified successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Visibility modification is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/view/{viewId}:
+    get:
+      tags:
+      - view-endpoint
+      summary: Get view
+      description: Gets a view with id in the metadata database.
+      operationId: find_7
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: Find view is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, view or user could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Find view successfully
+          headers:
+            X-Username:
+              description: The authentication username
+              style: simple
+            Access-Control-Expose-Headers:
+              description: Expose custom headers
+              style: simple
+            X-Type:
+              description: The JDBC connection type
+              style: simple
+            X-View:
+              description: The view internal name
+              style: simple
+            X-Database:
+              description: The database internal name
+              style: simple
+            X-Password:
+              description: The authentication password
+              style: simple
+            X-Host:
+              description: The database hostname
+              style: simple
+            X-Port:
+              description: The database port number
+              style: simple
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ViewDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - view-endpoint
+      summary: Update view
+      description: Updates a view with id. This can only be performed by the view
+        owner or database owner. Requires role `create-database-view`.
+      operationId: update_3
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ViewUpdateDto"
+        required: true
+      responses:
+        "403":
+          description: Update not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database or View could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Update view successfully
+          content:
+            '*/*':
+              schema:
+                $ref: "#/components/schemas/ViewBriefDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Update view query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - view-endpoint
+      summary: Delete view
+      description: Deletes a view with id. Requires role `delete-database-view`.
+      operationId: delete_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "202":
+          description: Delete view successfully
+        "423":
+          description: Delete view resulted in an invalid query statement
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, view or user could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Delete view query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Deletion not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}:
+    get:
+      tags:
+      - table-endpoint
+      summary: Find table
+      description: "Finds a table with id. When a table is hidden (i.e. when `is_public`\
+        \ is `false`), then the user needs to have at least read access and the role\
+        \ `find-table`. When the `system` role is present, the endpoint responds with\
+        \ additional connection metadata in the header."
+      operationId: findById_2
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Failed to establish connection with broker service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Table, database or container could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to obtain queue information from broker service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Find table successfully
+          headers:
+            X-Username:
+              description: The authentication username
+              style: simple
+            Access-Control-Expose-Headers:
+              description: Expose custom headers
+              style: simple
+            X-Password:
+              description: The authentication password
+              style: simple
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TableDto"
+        "403":
+          description: Access to the database is forbidden
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - table-endpoint
+      summary: Update table
+      description: Updates a table in the database with id. Requires role `update-table`.
+      operationId: update_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/TableUpdateDto"
+        required: true
+      responses:
+        "400":
+          description: Update table visibility payload is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated the table
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TableBriefDto"
+        "403":
+          description: Update table visibility not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Table could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - table-endpoint
+      summary: Delete table
+      description: Deletes a table with id. Only the owner of a table can perform
+        this action (requires role `delete-table`) or anyone can delete a table (requires
+        role `delete-foreign-table`).
+      operationId: delete_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Delete table query resulted in an invalid query statement
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Delete table successfully
+        "404":
+          description: "Table, database or container could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Access to the database is forbidden
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/statistic:
+    put:
+      tags:
+      - table-endpoint
+      summary: Update statistics
+      description: "Updates basic statistical properties (min, max, mean, median,\
+        \ std.dev) for numerical columns in a table with id. This action can only\
+        \ be performed by the table owner. Requires role `update-table-statistic`."
+      operationId: updateStatistic
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Failed to map column statistic to known columns
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not the owner
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated table statistics successfully
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/column/{columnId}:
+    put:
+      tags:
+      - table-endpoint
+      summary: Update semantics
+      description: Updates column semantics of a table column with id. Only the table
+        owner with at least *READ* access to the associated database can update the
+        column semantics (requires role `modify-table-column-semantics`) or foreign
+        table columns if role `modify-foreign-table-column-semantics`.
+      operationId: updateColumn
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: columnId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ColumnSemanticsUpdateDto"
+        required: true
+      responses:
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated column semantics successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ColumnDto"
+        "404":
+          description: Failed to find user/table/database/ontology in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Update semantic concept query is malformed or update unit of
+            measurement query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Access to the database is forbidden
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/owner:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database owner
+      description: Updates the database with id on the owner. Only the database owner
+        can perform this operation. Requires role `modify-database-owner`.
+      operationId: transfer
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseTransferDto"
+        required: true
+      responses:
+        "400":
+          description: Owner payload is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Transfer of ownership was successful
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Transfer of ownership is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/metadata/view:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database view schemas
+      description: Updates the database with id with generated metadata from view
+        that are not yet known to the database. Only the database owner can perform
+        this operation. Requires role `find-database`.
+      operationId: refreshViewMetadata
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Refreshed database views metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "403":
+          description: Refresh view metadata is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/metadata/table:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database table schemas
+      description: Updates the database with id with generated metadata from tables
+        that are not yet known to the database. Only the database owner can perform
+        this operation. Requires role `find-database`.
+      operationId: refreshTableMetadata
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Failed to parse payload at search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Refreshed database tables metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "403":
+          description: Not allowed to refresh table metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to fin user/database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/image:
+    get:
+      tags:
+      - database-endpoint
+      summary: Get database preview image
+      description: Gets the database with id on the preview image.
+      operationId: findPreviewImage
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: View of image was successful
+          content:
+            '*/*':
+              schema:
+                type: array
+                items:
+                  type: string
+                  format: byte
+        "404":
+          description: Database or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database preview image
+      description: Updates the database with id on the preview image. Only the database
+        owner can perform this operation. Requires role `modify-database-image`.
+      operationId: modifyImage
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseModifyImageDto"
+        required: true
+      responses:
+        "403":
+          description: Modify of image is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Modify of image was successful
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "410":
+          description: File was not found in the Storage Service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user:
+    get:
+      tags:
+      - user-endpoint
+      summary: List users
+      description: "Lists users known to the metadata database. Internal users are\
+        \ omitted from the result list. If the optional query parameter `username`\
+        \ is present, the result list can be filtered by matching this exact username."
+      operationId: findAll
+      parameters:
+      - name: username
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "200":
+          description: List users
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/UserBriefDto"
+    post:
+      tags:
+      - user-endpoint
+      summary: Create user
+      description: Creates a user in the auth service and metadata database. Requires
+        that no credentials are sent in the request.
+      operationId: create
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateUserDto"
+        required: true
+      responses:
+        "201":
+          description: Created user
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserDto"
+        "404":
+          description: Default role not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Failed to create in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Internal authentication to the auth service is invalid
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "409":
+          description: User with username already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Parameters are not well-formed (likely email)
+          content:
+            application/json: {}
+        "417":
+          description: User with e-mail already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to create in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/ontology:
+    get:
+      tags:
+      - ontology-endpoint
+      summary: List ontologies
+      description: Lists all ontologies known to the metadata database.
+      operationId: findAll_2
+      responses:
+        "200":
+          description: List ontologies
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/OntologyBriefDto"
+    post:
+      tags:
+      - ontology-endpoint
+      summary: Create ontology
+      description: Creates an ontology in the metadata database. Requires role `create-ontology`.
+      operationId: create_1
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OntologyCreateDto"
+        required: true
+      responses:
+        "201":
+          description: Registered ontology successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OntologyDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/message:
+    get:
+      tags:
+      - message-endpoint
+      summary: List messages
+      description: "Lists messages known to the metadata database. Messages can be\
+        \ filtered be filtered with the optional `active` parameter. If set to *true*,\
+        \ only active messages (that is, messages whose end time has not been reached)\
+        \ will be returned. Otherwise only inactive messages are returned. If not\
+        \ set, active and inactive messages are returned."
+      operationId: list_2
+      parameters:
+      - name: active
+        in: query
+        required: false
+        schema:
+          type: boolean
+      responses:
+        "200":
+          description: List messages
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/BannerMessageDto"
+    post:
+      tags:
+      - message-endpoint
+      summary: Create message
+      description: Creates a message in the metadata database. Requires role `create-maintenance-message`.
+      operationId: create_2
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/BannerMessageCreateDto"
+        required: true
+      responses:
+        "201":
+          description: Created message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/BannerMessageBriefDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/image:
+    get:
+      tags:
+      - image-endpoint
+      summary: List images
+      description: Lists all container images known to the metadata database.
+      operationId: findAll_3
+      responses:
+        "200":
+          description: List images
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ImageBriefDto"
+    post:
+      tags:
+      - image-endpoint
+      summary: Create image
+      description: Creates a container image in the metadata database. Requires role
+        `create-image`.
+      operationId: create_3
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ImageCreateDto"
+        required: true
+      responses:
+        "201":
+          description: Created image
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ImageDto"
+        "409":
+          description: Image already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Image specification is invalid
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/identifier:
+    get:
+      tags:
+      - identifier-endpoint
+      summary: List identifiers
+      description: Lists all identifiers known to the metadata database
+      operationId: findAll_4
+      parameters:
+      - name: dbid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: qid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: vid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: tid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: Accept
+        in: header
+        required: true
+        schema:
+          type: string
+      responses:
+        "200":
+          description: Found identifiers successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  type: string
+            application/ld+json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/LdDatasetDto"
+        "406":
+          description: "Identifier could not be exported, the requested style is not\
+            \ known"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    post:
+      tags:
+      - identifier-endpoint
+      summary: Create identifier
+      description: Create an identifier with id to create a draft identifier. Identifiers
+        can only be created for objects the user has at least *READ* access in the
+        associated database (requires role `create-identifier`) or for any object
+        in any database (requires role `create-foreign-identifier`).
+      operationId: create_4
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateIdentifierDto"
+        required: true
+      responses:
+        "201":
+          description: Drafted identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+        "400":
+          description: Identifier form contains invalid request data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Failed to find database, table or view"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Insufficient access rights or authorities
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/view:
+    get:
+      tags:
+      - view-endpoint
+      summary: List views
+      description: Lists views known to the metadata database.
+      operationId: findAll_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Find views successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ViewBriefDto"
+        "404":
+          description: Database or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    post:
+      tags:
+      - view-endpoint
+      summary: Create view
+      description: Creates a view. This can only be performed by the database owner.
+        Requires role `create-database-view`.
+      operationId: create_6
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateViewDto"
+        required: true
+      responses:
+        "201":
+          description: Create view successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ViewBriefDto"
+        "423":
+          description: Create view resulted in an invalid query statement
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Create view query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Credentials missing
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/user in metadata database.
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table:
+    get:
+      tags:
+      - table-endpoint
+      summary: List tables
+      description: "Lists all tables known to the metadata database. When a database\
+        \ has a hidden schema (i.e. when `is_schema_public` is `false`), then the\
+        \ user needs to have at least read access and the role `list-tables`."
+      operationId: list_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: List tables not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: List tables
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/TableBriefDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    post:
+      tags:
+      - table-endpoint
+      summary: Create table
+      description: Creates a table in the database with id. Requires role `create-table`.
+      operationId: create_7
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateTableDto"
+        required: true
+      responses:
+        "409":
+          description: Create table conflicts with existing table name
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Create table query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, container or user could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Create table not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created a new table
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TableBriefDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/container:
+    get:
+      tags:
+      - container-endpoint
+      summary: List containers
+      description: List all containers in the metadata database.
+      operationId: findAll_6
+      parameters:
+      - name: limit
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int32
+      responses:
+        "200":
+          description: List containers
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ContainerBriefDto"
+    post:
+      tags:
+      - container-endpoint
+      summary: Create container
+      description: Creates a container in the metadata database. Requires role `create-container`.
+      operationId: create_9
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/CreateContainerDto"
+        required: true
+      responses:
+        "409":
+          description: Container name already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: "Create container not permitted, need authority `create-container`"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created a new container
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ContainerDto"
+        "400":
+          description: Container payload malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Container image or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/unit:
+    get:
+      tags:
+      - unit-endpoint
+      summary: List units
+      description: Lists units known to the metadata database.
+      operationId: findAll_1
+      responses:
+        "200":
+          description: Find all semantic units
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/UnitDto"
+  /api/ontology/{ontologyId}/entity:
+    get:
+      tags:
+      - ontology-endpoint
+      summary: Find entities
+      description: Finds semantic entities by label or uri in an ontology with id.
+        Requires role `execute-semantic-query`.
+      operationId: find_4
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: label
+        in: query
+        required: false
+        schema:
+          type: string
+      - name: uri
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "422":
+          description: Ontology does not have rdf or sparql endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Filter params are invalid
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "417":
+          description: Generated query or uri is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found entities
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/EntityDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/oai:
+    get:
+      tags:
+      - metadata-endpoint
+      summary: Get record
+      operationId: identify_1_1_1_1
+      parameters:
+      - name: verb
+        in: query
+      - name: parameters
+        in: query
+        required: true
+        schema:
+          $ref: "#/components/schemas/OaiListIdentifiersParameters"
+      responses:
+        "200":
+          description: List containers
+          content:
+            text/xml: {}
+  /api/message/message/{messageId}:
+    get:
+      tags:
+      - message-endpoint
+      summary: Find message
+      description: Finds a message with id in the metadata database.
+      operationId: find_5
+      parameters:
+      - name: messageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Get messages
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/BannerMessageDto"
+        "404":
+          description: Could not find message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/license:
+    get:
+      tags:
+      - license-endpoint
+      summary: List licenses
+      description: Lists licenses known to the metadata database.
+      operationId: list_3
+      responses:
+        "200":
+          description: List of licenses
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/LicenseDto"
+  /api/identifier/retrieve:
+    get:
+      tags:
+      - identifier-endpoint
+      summary: Retrieve PID metadata
+      description: "Retrieves Persistent Identifier (PID) metadata from external endpoints.\
+        \ Supported PIDs are: ORCID, ROR, DOI."
+      operationId: retrieve
+      parameters:
+      - name: url
+        in: query
+        required: true
+        schema:
+          type: string
+      responses:
+        "404":
+          description: Failed to find metadata for identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Retrieved metadata from identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+  /api/database/{databaseId}:
+    get:
+      tags:
+      - database-endpoint
+      summary: Find database
+      description: Finds a database with id.
+      operationId: findById_1
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: "Database, user or exchange could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to view database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Database found successfully
+          headers:
+            X-Username:
+              description: The authentication username
+              style: simple
+            Access-Control-Expose-Headers:
+              description: Expose custom headers
+              style: simple
+            X-Password:
+              description: The authentication password
+              style: simple
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "503":
+          description: Failed to find queue information in broker service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to the broker service could not be established
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/suggest:
+    get:
+      tags:
+      - table-endpoint
+      summary: Suggest semantics
+      description: Suggests semantic concepts for a table. This action can only be
+        performed by the table owner. Requires role `table-semantic-analyse`.
+      operationId: analyseTable
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: Not the table owner.
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "422":
+          description: Ontology does not have rdf or sparql endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Suggested table semantics successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/EntityDto"
+        "417":
+          description: Generated query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Failed to parse statistic in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/column/{columnId}/suggest:
+    get:
+      tags:
+      - table-endpoint
+      summary: Suggest semantics
+      description: Suggests column semantics. Requires role `table-semantic-analyse`.
+      operationId: analyseTableColumn
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: columnId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "422":
+          description: Ontology does not have rdf or sparql endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Suggested table column semantics successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/TableColumnEntityDto"
+        "400":
+          description: Generated query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/container/{containerId}:
+    get:
+      tags:
+      - container-endpoint
+      summary: Find container
+      description: Finds a container in the metadata database.
+      operationId: findById_3
+      parameters:
+      - name: containerId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Container image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found container
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ContainerDto"
+    delete:
+      tags:
+      - container-endpoint
+      summary: Delete container
+      description: Deletes a container in the metadata database. Requires role `delete-container`.
+      operationId: delete_6
+      parameters:
+      - name: containerId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: "Create container not permitted, need authority `delete-container`"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Container not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted container
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/concept:
+    get:
+      tags:
+      - concept-endpoint
+      summary: List concepts
+      description: List all semantic concepts known to the metadata database
+      operationId: findAll_7
+      responses:
+        "200":
+          description: List concepts
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ConceptDto"
+components:
+  schemas:
+    CreatorBriefDto:
+      required:
+      - creator_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 11
+        affiliation:
+          type: string
+          example: Brown University
+        creator_name:
+          type: string
+          example: "Carberry, Josiah"
+        name_type:
+          type: string
+          example: Personal
+          enum:
+          - Personal
+          - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+          - ORCID
+          - ROR
+          - ISNI
+          - GRID
+        affiliation_identifier:
+          type: string
+          example: https://ror.org/05gq02987
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+          - ROR
+          - GRID
+          - ISNI
+    DatabaseBriefDto:
+      required:
+      - contact
+      - id
+      - identifiers
+      - internal_name
+      - is_public
+      - is_schema_public
+      - name
+      - owner_id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 3
+        name:
+          type: string
+          example: Air Quality
+        description:
+          type: string
+          example: Air Quality
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierBriefDto"
+        contact:
+          $ref: "#/components/schemas/UserBriefDto"
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        owner_id:
+          type: string
+          format: uuid
+          example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5
+        preview_image:
+          type: string
+    IdentifierBriefDto:
+      required:
+      - creators
+      - database_id
+      - id
+      - owned_by
+      - publication_year
+      - publisher
+      - status
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 2
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreatorBriefDto"
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierTitleDto"
+        doi:
+          type: string
+          example: 10.1038/nphys1170
+        publisher:
+          type: string
+          example: TU Wien
+        status:
+          type: string
+          example: draft
+          enum:
+          - draft
+          - published
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        view_id:
+          type: integer
+          format: int64
+          example: 1
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        owned_by:
+          type: string
+          format: uuid
+          example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5
+    IdentifierTitleDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        title:
+          type: string
+          example: Airquality Demonstrator
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          enum:
+          - AlternativeTitle
+          - Subtitle
+          - TranslatedTitle
+          - Other
+    UserBriefDto:
+      required:
+      - id
+      - username
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+          example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4
+        username:
+          type: string
+          description: Only contains lowercase characters
+          example: jcarberry
+        name:
+          type: string
+          example: Josiah Carberry
+        orcid:
+          type: string
+          example: 0000-0002-1825-0097
+        qualified_name:
+          type: string
+          example: Josiah Carberry — @jcarberry
+        given_name:
+          type: string
+          example: Josiah
+        family_name:
+          type: string
+          example: Carberry
+    DatabaseAccessDto:
+      required:
+      - type
+      - user
+      type: object
+      properties:
+        user:
+          $ref: "#/components/schemas/UserBriefDto"
+        type:
+          type: string
+          example: read
+          enum:
+          - read
+          - write_own
+          - write_all
+    ApiErrorDto:
+      required:
+      - code
+      - message
+      - status
+      type: object
+      properties:
+        status:
+          type: string
+          example: NOT_FOUND
+          enum:
+          - 100 CONTINUE
+          - 101 SWITCHING_PROTOCOLS
+          - 102 PROCESSING
+          - 103 EARLY_HINTS
+          - 103 CHECKPOINT
+          - 200 OK
+          - 201 CREATED
+          - 202 ACCEPTED
+          - 203 NON_AUTHORITATIVE_INFORMATION
+          - 204 NO_CONTENT
+          - 205 RESET_CONTENT
+          - 206 PARTIAL_CONTENT
+          - 207 MULTI_STATUS
+          - 208 ALREADY_REPORTED
+          - 226 IM_USED
+          - 300 MULTIPLE_CHOICES
+          - 301 MOVED_PERMANENTLY
+          - 302 FOUND
+          - 302 MOVED_TEMPORARILY
+          - 303 SEE_OTHER
+          - 304 NOT_MODIFIED
+          - 305 USE_PROXY
+          - 307 TEMPORARY_REDIRECT
+          - 308 PERMANENT_REDIRECT
+          - 400 BAD_REQUEST
+          - 401 UNAUTHORIZED
+          - 402 PAYMENT_REQUIRED
+          - 403 FORBIDDEN
+          - 404 NOT_FOUND
+          - 405 METHOD_NOT_ALLOWED
+          - 406 NOT_ACCEPTABLE
+          - 407 PROXY_AUTHENTICATION_REQUIRED
+          - 408 REQUEST_TIMEOUT
+          - 409 CONFLICT
+          - 410 GONE
+          - 411 LENGTH_REQUIRED
+          - 412 PRECONDITION_FAILED
+          - 413 PAYLOAD_TOO_LARGE
+          - 413 REQUEST_ENTITY_TOO_LARGE
+          - 414 URI_TOO_LONG
+          - 414 REQUEST_URI_TOO_LONG
+          - 415 UNSUPPORTED_MEDIA_TYPE
+          - 416 REQUESTED_RANGE_NOT_SATISFIABLE
+          - 417 EXPECTATION_FAILED
+          - 418 I_AM_A_TEAPOT
+          - 419 INSUFFICIENT_SPACE_ON_RESOURCE
+          - 420 METHOD_FAILURE
+          - 421 DESTINATION_LOCKED
+          - 422 UNPROCESSABLE_ENTITY
+          - 423 LOCKED
+          - 424 FAILED_DEPENDENCY
+          - 425 TOO_EARLY
+          - 426 UPGRADE_REQUIRED
+          - 428 PRECONDITION_REQUIRED
+          - 429 TOO_MANY_REQUESTS
+          - 431 REQUEST_HEADER_FIELDS_TOO_LARGE
+          - 451 UNAVAILABLE_FOR_LEGAL_REASONS
+          - 500 INTERNAL_SERVER_ERROR
+          - 501 NOT_IMPLEMENTED
+          - 502 BAD_GATEWAY
+          - 503 SERVICE_UNAVAILABLE
+          - 504 GATEWAY_TIMEOUT
+          - 505 HTTP_VERSION_NOT_SUPPORTED
+          - 506 VARIANT_ALSO_NEGOTIATES
+          - 507 INSUFFICIENT_STORAGE
+          - 508 LOOP_DETECTED
+          - 509 BANDWIDTH_LIMIT_EXCEEDED
+          - 510 NOT_EXTENDED
+          - 511 NETWORK_AUTHENTICATION_REQUIRED
+        message:
+          type: string
+          example: Error message
+        code:
+          type: string
+          example: error.service.code
+    UserUpdateDto:
+      required:
+      - language
+      - theme
+      type: object
+      properties:
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Brown University
+        orcid:
+          type: string
+          example: 0000-0002-1825-0097
+        theme:
+          type: string
+          example: dark
+        language:
+          type: string
+          example: en
+    UserAttributesDto:
+      required:
+      - language
+      - theme
+      type: object
+      properties:
+        theme:
+          type: string
+          example: light
+        orcid:
+          type: string
+          example: https://orcid.org/0000-0002-1825-0097
+        affiliation:
+          type: string
+          example: Brown University
+        language:
+          type: string
+          example: en
+    UserDto:
+      required:
+      - attributes
+      - id
+      - password
+      - username
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+          example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4
+        name:
+          type: string
+          example: Josiah Carberry
+        username:
+          type: string
+          example: username
+        password:
+          type: string
+          example: p4ssw0rd
+        attributes:
+          $ref: "#/components/schemas/UserAttributesDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        qualified_name:
+          type: string
+          example: Josiah Carberry — @jcarberry
+        given_name:
+          type: string
+          example: Josiah
+        family_name:
+          type: string
+          example: Carberry
+    UserPasswordDto:
+      required:
+      - password
+      type: object
+      properties:
+        password:
+          type: string
+    RefreshTokenRequestDto:
+      required:
+      - refresh_token
+      type: object
+      properties:
+        refresh_token:
+          type: string
+          example: refresh_token
+    TokenDto:
+      required:
+      - access_token
+      - expires_in
+      - id_token
+      - not-before-policy
+      - refresh_expires_in
+      - refresh_token
+      - scope
+      - session_state
+      - token_type
+      type: object
+      properties:
+        scope:
+          type: string
+        access_token:
+          type: string
+        expires_in:
+          type: integer
+          format: int64
+        refresh_token:
+          type: string
+        refresh_expires_in:
+          type: integer
+          format: int64
+        id_token:
+          type: string
+        session_state:
+          type: string
+        token_type:
+          type: string
+        not-before-policy:
+          type: integer
+          format: int64
+    OntologyModifyDto:
+      required:
+      - prefix
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: Ontology URI
+        prefix:
+          type: string
+          example: Ontology prefix
+        sparql_endpoint:
+          type: string
+          example: Ontology SPARQL endpoint
+        rdf_path:
+          type: string
+          example: rdf/om-2.0.rdf
+    OntologyDto:
+      required:
+      - id
+      - prefix
+      - rdf
+      - sparql
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+          example: http://www.wikidata.org/
+        prefix:
+          type: string
+          example: wd
+        sparql:
+          type: boolean
+          example: true
+        rdf:
+          type: boolean
+          example: false
+        uri_pattern:
+          type: string
+          example: http://www.wikidata.org/entity/.*
+        sparql_endpoint:
+          type: string
+          example: https://query.wikidata.org/sparql
+        rdf_path:
+          type: string
+          example: rdf/om-2.0.rdf
+    BannerMessageUpdateDto:
+      required:
+      - message
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+        display_start:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        display_end:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+    BannerMessageBriefDto:
+      required:
+      - message
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+    ImageChangeDto:
+      required:
+      - dialect
+      - driver_class
+      - jdbc_method
+      - registry
+      type: object
+      properties:
+        registry:
+          type: string
+          example: docker.io/library
+        defaultPort:
+          maximum: 65535
+          minimum: 1024
+          type: integer
+          format: int32
+          example: 5432
+        dialect:
+          type: string
+          example: Postgres
+        driver_class:
+          type: string
+          example: org.postgresql.Driver
+        jdbc_method:
+          type: string
+          example: postgresql
+    DataTypeDto:
+      required:
+      - display_name
+      - documentation
+      - is_buildable
+      - is_quoted
+      - value
+      type: object
+      properties:
+        value:
+          type: string
+          example: time
+        documentation:
+          type: string
+          example: https://mariadb.com/kb/en/time/
+        display_name:
+          type: string
+          example: TIME(fsp)
+        size_min:
+          type: integer
+          format: int32
+          example: 0
+        size_max:
+          type: integer
+          format: int32
+          example: 6
+        size_default:
+          type: integer
+          format: int32
+          example: 0
+        size_required:
+          type: boolean
+          example: false
+        d_min:
+          type: integer
+          format: int32
+        d_max:
+          type: integer
+          format: int32
+        d_default:
+          type: integer
+          format: int32
+        d_required:
+          type: boolean
+        data_hint:
+          type: string
+          example: "e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S"
+        type_hint:
+          type: string
+          example: "fsp=microsecond precision, min. 0, max. 6"
+        is_quoted:
+          type: boolean
+          description: frontend needs to quote this data type
+          example: false
+        is_buildable:
+          type: boolean
+          description: frontend can build this data type
+          example: true
+    ImageDto:
+      required:
+      - data_types
+      - default
+      - default_port
+      - dialect
+      - driver_class
+      - id
+      - jdbc_method
+      - name
+      - operators
+      - registry
+      - version
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        registry:
+          type: string
+          example: docker.io/library
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+          example: "10.5"
+        dialect:
+          type: string
+          example: org.hibernate.dialect.MariaDBDialect
+        operators:
+          type: array
+          items:
+            $ref: "#/components/schemas/OperatorDto"
+        driver_class:
+          type: string
+          example: org.mariadb.jdbc.Driver
+        jdbc_method:
+          type: string
+          example: mariadb
+        default:
+          type: boolean
+          example: false
+        default_port:
+          type: integer
+          format: int32
+          example: 3306
+        data_types:
+          type: array
+          items:
+            $ref: "#/components/schemas/DataTypeDto"
+    OperatorDto:
+      required:
+      - display_name
+      - documentation
+      - value
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        value:
+          type: string
+          example: XOR
+        documentation:
+          type: string
+          example: https://mariadb.com/kb/en/xor/
+        display_name:
+          type: string
+          example: XOR
+    IdentifierSaveDto:
+      required:
+      - creators
+      - database_id
+      - id
+      - publication_year
+      - publisher
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        doi:
+          type: string
+          example: 10.1111/11111111
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierTitleDto"
+        descriptions:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierDescriptionDto"
+        funders:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierFunderDto"
+        licenses:
+          type: array
+          items:
+            $ref: "#/components/schemas/LicenseDto"
+        publisher:
+          type: string
+          example: TU Wien
+        language:
+          type: string
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierCreatorDto"
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+        view_id:
+          type: integer
+          format: int64
+        table_id:
+          type: integer
+          format: int64
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        related_identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveRelatedIdentifierDto"
+    LicenseDto:
+      required:
+      - identifier
+      - uri
+      type: object
+      properties:
+        identifier:
+          type: string
+          example: MIT
+        uri:
+          type: string
+          example: https://opensource.org/licenses/MIT
+        description:
+          type: string
+          example: "A short and simple permissive license with conditions only requiring\
+            \ preservation of copyright and license notices. Licensed works, modifications,\
+            \ and larger works may be distributed under different terms and without\
+            \ source code."
+    SaveIdentifierCreatorDto:
+      required:
+      - creator_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Wesleyan University
+        creator_name:
+          type: string
+          example: "Carberry, Josiah"
+        name_type:
+          type: string
+          example: Personal
+          enum:
+          - Personal
+          - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+          - ORCID
+          - ROR
+          - ISNI
+          - GRID
+        affiliation_identifier:
+          type: string
+          example: https://ror.org/04d836q62
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+          - ROR
+          - GRID
+          - ISNI
+    SaveIdentifierDescriptionDto:
+      required:
+      - description
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        description:
+          type: string
+          example: "Air quality reports at Stephansplatz, Vienna"
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          example: Abstract
+          enum:
+          - Abstract
+          - Methods
+          - SeriesInformation
+          - TableOfContents
+          - TechnicalInfo
+          - Other
+    SaveIdentifierFunderDto:
+      required:
+      - funder_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        funder_name:
+          type: string
+          example: European Commission
+        funder_identifier:
+          type: string
+          example: http://doi.org/10.13039/501100000780
+        funder_identifier_type:
+          type: string
+          example: Crossref Funder ID
+          enum:
+          - Crossref Funder ID
+          - ROR
+          - GND
+          - ISNI
+          - Other
+        scheme_uri:
+          type: string
+          example: http://doi.org/
+        award_number:
+          type: string
+          example: "824087"
+        award_title:
+          type: string
+          example: EOSC-Life
+    SaveIdentifierTitleDto:
+      required:
+      - id
+      - title
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        title:
+          type: string
+          example: Airquality Demonstrator
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          example: Subtitle
+          enum:
+          - AlternativeTitle
+          - Subtitle
+          - TranslatedTitle
+          - Other
+    SaveRelatedIdentifierDto:
+      required:
+      - id
+      - relation
+      - type
+      - value
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        value:
+          type: string
+          example: 10.70124/dc4zh-9ce78
+        type:
+          type: string
+          example: DOI
+          enum:
+          - DOI
+          - URL
+          - URN
+          - ARK
+          - arXiv
+          - bibcode
+          - EAN13
+          - EISSN
+          - Handle
+          - IGSN
+          - ISBN
+          - ISTC
+          - LISSN
+          - LSID
+          - PMID
+          - PURL
+          - UPC
+          - w3id
+        relation:
+          type: string
+          example: Cites
+          enum:
+          - IsCitedBy
+          - Cites
+          - IsSupplementTo
+          - IsSupplementedBy
+          - IsContinuedBy
+          - Continues
+          - IsDescribedBy
+          - Describes
+          - HasMetadata
+          - IsMetadataFor
+          - HasVersion
+          - IsVersionOf
+          - IsNewVersionOf
+          - IsPreviousVersionOf
+          - IsPartOf
+          - HasPart
+          - IsPublishedIn
+          - IsReferencedBy
+          - References
+          - IsDocumentedBy
+          - Documents
+          - IsCompiledBy
+          - Compiles
+          - IsVariantFormOf
+          - IsOriginalFormOf
+          - IsIdenticalTo
+          - IsReviewedBy
+          - Reviews
+          - IsDerivedFrom
+          - IsSourceOf
+          - IsRequiredBy
+          - Requires
+          - IsObsoletedBy
+          - Obsoletes
+    CreatorDto:
+      required:
+      - creator_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 11
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Brown University
+        creator_name:
+          type: string
+          example: "Carberry, Josiah"
+        name_type:
+          type: string
+          example: Personal
+          enum:
+          - Personal
+          - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+          - ORCID
+          - ROR
+          - ISNI
+          - GRID
+        name_identifier_scheme_uri:
+          type: string
+          example: https://orcid.org/
+        affiliation_identifier:
+          type: string
+          example: https://ror.org/05gq02987
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+          - ROR
+          - GRID
+          - ISNI
+        affiliation_identifier_scheme_uri:
+          type: string
+          example: https://ror.org/
+    IdentifierDescriptionDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 3
+        description:
+          type: string
+          example: "Air quality reports at Stephansplatz, Vienna"
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          example: Abstract
+          enum:
+          - Abstract
+          - Methods
+          - SeriesInformation
+          - TableOfContents
+          - TechnicalInfo
+          - Other
+    IdentifierDto:
+      required:
+      - creators
+      - database_id
+      - descriptions
+      - funders
+      - id
+      - language
+      - licenses
+      - owner
+      - publication_year
+      - publisher
+      - query
+      - query_hash
+      - query_normalized
+      - status
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 2
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierTitleDto"
+        descriptions:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDescriptionDto"
+        funders:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierFunderDto"
+        query:
+          type: string
+          example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\
+            \ = \"09:STEF\""
+        execution:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        doi:
+          type: string
+          example: 10.1038/nphys1170
+        publisher:
+          type: string
+          example: TU Wien
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        language:
+          type: string
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        licenses:
+          type: array
+          items:
+            $ref: "#/components/schemas/LicenseDto"
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreatorDto"
+        status:
+          type: string
+          example: draft
+          enum:
+          - draft
+          - published
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        view_id:
+          type: integer
+          format: int64
+          example: 1
+        query_normalized:
+          type: string
+          example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\
+            \ = \"09:STEF\""
+        related_identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/RelatedIdentifierDto"
+        query_hash:
+          type: string
+          description: query hash in sha512
+        result_hash:
+          type: string
+          example: 34fe82cda2c53f13f8d90cfd7a3469e3a939ff311add50dce30d9136397bf8e5
+        result_number:
+          type: integer
+          format: int64
+          example: 1
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+    IdentifierFunderDto:
+      required:
+      - funder_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 2
+        funder_name:
+          type: string
+          example: European Commission
+        funder_identifier:
+          type: string
+          example: http://doi.org/10.13039/501100000780
+        funder_identifier_type:
+          type: string
+          example: Crossref Funder ID
+          enum:
+          - Crossref Funder ID
+          - ROR
+          - GND
+          - ISNI
+          - Other
+        scheme_uri:
+          type: string
+          example: http://doi.org/
+        award_number:
+          type: string
+          example: "824087"
+        award_title:
+          type: string
+          example: EOSC-Life
+    RelatedIdentifierDto:
+      required:
+      - id
+      - relation
+      - type
+      - value
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 8
+        value:
+          type: string
+          example: 10.70124/dc4zh-9ce78
+        type:
+          type: string
+          example: DOI
+          enum:
+          - DOI
+          - URL
+          - URN
+          - ARK
+          - arXiv
+          - bibcode
+          - EAN13
+          - EISSN
+          - Handle
+          - IGSN
+          - ISBN
+          - ISTC
+          - LISSN
+          - LSID
+          - PMID
+          - PURL
+          - UPC
+          - w3id
+        relation:
+          type: string
+          example: Cites
+          enum:
+          - IsCitedBy
+          - Cites
+          - IsSupplementTo
+          - IsSupplementedBy
+          - IsContinuedBy
+          - Continues
+          - IsDescribedBy
+          - Describes
+          - HasMetadata
+          - IsMetadataFor
+          - HasVersion
+          - IsVersionOf
+          - IsNewVersionOf
+          - IsPreviousVersionOf
+          - IsPartOf
+          - HasPart
+          - IsPublishedIn
+          - IsReferencedBy
+          - References
+          - IsDocumentedBy
+          - Documents
+          - IsCompiledBy
+          - Compiles
+          - IsVariantFormOf
+          - IsOriginalFormOf
+          - IsIdenticalTo
+          - IsReviewedBy
+          - Reviews
+          - IsDerivedFrom
+          - IsSourceOf
+          - IsRequiredBy
+          - Requires
+          - IsObsoletedBy
+          - Obsoletes
+    DatabaseModifyVisibilityDto:
+      required:
+      - is_public
+      - is_schema_public
+      type: object
+      properties:
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ViewUpdateDto:
+      required:
+      - is_public
+      - is_schema_public
+      type: object
+      properties:
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ViewBriefDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - name
+      - query
+      - query_hash
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        name:
+          type: string
+          example: Air Quality
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        initial_view:
+          type: boolean
+          description: True if it is the default view for the database
+          example: true
+        query_hash:
+          type: string
+          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
+        owned_by:
+          type: string
+          format: uuid
+          example: ac750fcf-ea02-4fce-85ac-d73857e18b35
+    TableUpdateDto:
+      required:
+      - is_public
+      - is_schema_public
+      type: object
+      properties:
+        description:
+          maxLength: 180
+          minLength: 0
+          type: string
+          example: Air Quality in Austria
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    TableBriefDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - is_public
+      - is_schema_public
+      - is_versioned
+      - name
+      - owned_by
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 3
+        name:
+          type: string
+          example: Air Quality
+        description:
+          type: string
+          example: Air Quality in Austria
+        database_id:
+          type: integer
+          format: int64
+          example: 2
+        internal_name:
+          type: string
+          example: air_quality
+        is_versioned:
+          type: boolean
+          example: true
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        owned_by:
+          type: string
+          format: uuid
+          example: 78337b80-5699-45db-8111-cec86439ab6b
+    ColumnSemanticsUpdateDto:
+      type: object
+      properties:
+        concept_uri:
+          type: string
+        unit_uri:
+          type: string
+    ColumnDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - is_null_allowed
+      - name
+      - ord
+      - table_id
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Given Name
+        alias:
+          type: string
+          example: firstname
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        mean:
+          type: number
+          example: 45.4
+        median:
+          type: number
+          example: 51
+        concept:
+          $ref: "#/components/schemas/ConceptBriefDto"
+        unit:
+          $ref: "#/components/schemas/UnitBriefDto"
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Column comment
+        enums:
+          type: array
+          example:
+          - val1
+          items:
+            type: string
+            example: "[\"val1\"]"
+        sets:
+          type: array
+          example:
+          - val1
+          items:
+            type: string
+            example: "[\"val1\"]"
+        database_id:
+          type: integer
+          format: int64
+          example: 2
+        table_id:
+          type: integer
+          format: int64
+          example: 3
+        ord:
+          type: integer
+          format: int32
+          example: 0
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: given_name
+        index_length:
+          type: integer
+          format: int64
+          example: 255
+        length:
+          type: integer
+          format: int64
+          example: 255
+        type:
+          type: string
+          example: varchar
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+        data_length:
+          type: integer
+          format: int64
+          example: 34300
+        max_data_length:
+          type: integer
+          format: int64
+          example: 34300
+        num_rows:
+          type: integer
+          format: int64
+          example: 32
+        val_min:
+          type: number
+          example: 0
+        val_max:
+          type: number
+          example: 100
+        std_dev:
+          type: number
+          example: 5.32
+        is_null_allowed:
+          type: boolean
+          example: false
+    ConceptBriefDto:
+      required:
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 23
+        uri:
+          type: string
+          example: http://www.wikidata.org/entity/Q202444
+        name:
+          type: string
+          example: given name
+        description:
+          type: string
+          example: "name typically used to differentiate people from the same family,\
+            \ clan, or other social group who have a common last name"
+    UnitBriefDto:
+      required:
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 34
+        uri:
+          type: string
+          example: http://www.wikidata.org/entity/Q1422583
+        name:
+          type: string
+          example: importance
+        description:
+          type: string
+          example: "subjective magnitude of value, meaning, or purpose"
+    DatabaseTransferDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+    DatabaseModifyImageDto:
+      type: object
+      properties:
+        key:
+          type: string
+    CreateAccessDto:
+      required:
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          example: read
+          enum:
+          - read
+          - write_own
+          - write_all
+    CreateUserDto:
+      required:
+      - email
+      - password
+      - username
+      type: object
+      properties:
+        username:
+          pattern: "^[a-z0-9]{3,}$"
+          type: string
+          example: user
+        email:
+          type: string
+          example: user@example.com
+        password:
+          type: string
+    LoginRequestDto:
+      required:
+      - password
+      - username
+      type: object
+      properties:
+        username:
+          type: string
+          example: user
+        password:
+          type: string
+    OntologyCreateDto:
+      required:
+      - prefix
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: Ontology URI
+        prefix:
+          type: string
+          example: Ontology prefix
+        sparql_endpoint:
+          type: string
+          example: Ontology SPARQL endpoint
+    BannerMessageCreateDto:
+      required:
+      - message
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+        display_start:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        display_end:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+    ImageCreateDto:
+      required:
+      - default_port
+      - dialect
+      - driver_class
+      - is_default
+      - jdbc_method
+      - name
+      - registry
+      - version
+      type: object
+      properties:
+        registry:
+          type: string
+          example: docker.io/library
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+        dialect:
+          type: string
+        is_default:
+          type: boolean
+          example: false
+        driver_class:
+          type: string
+        jdbc_method:
+          type: string
+        default_port:
+          maximum: 65535
+          minimum: 1024
+          type: integer
+          format: int32
+    CreateIdentifierDto:
+      required:
+      - creators
+      - database_id
+      - publication_year
+      - publisher
+      - titles
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        doi:
+          type: string
+          example: 10.1111/11111111
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierTitleDto"
+        descriptions:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierDescriptionDto"
+        funders:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierFunderDto"
+        licenses:
+          type: array
+          items:
+            $ref: "#/components/schemas/LicenseDto"
+        publisher:
+          type: string
+          example: TU Wien
+        language:
+          type: string
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveIdentifierCreatorDto"
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+        view_id:
+          type: integer
+          format: int64
+        table_id:
+          type: integer
+          format: int64
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        related_identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/SaveRelatedIdentifierDto"
+    CreateDatabaseDto:
+      required:
+      - container_id
+      - is_public
+      - is_schema_public
+      - name
+      type: object
+      properties:
+        name:
+          type: string
+          example: Air Quality
+        container_id:
+          type: integer
+          format: int64
+          example: 1
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    CreateViewDto:
+      required:
+      - is_public
+      - is_schema_public
+      - name
+      - query
+      type: object
+      properties:
+        name:
+          maxLength: 63
+          minLength: 1
+          type: string
+          example: Air Quality
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality`
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    CreateForeignKeyDto:
+      required:
+      - columns
+      - referenced_columns
+      - referenced_table
+      type: object
+      properties:
+        columns:
+          type: array
+          items:
+            type: string
+        referenced_table:
+          type: string
+        referenced_columns:
+          type: array
+          items:
+            type: string
+        on_update:
+          type: string
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+        on_delete:
+          type: string
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+    CreateTableColumnDto:
+      required:
+      - name
+      - null_allowed
+      - type
+      type: object
+      properties:
+        name:
+          type: string
+          example: Date
+        type:
+          type: string
+          example: string
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Formatted as YYYY-MM-dd
+        enums:
+          type: array
+          description: "enum values, only considered when type = ENUM"
+          items:
+            type: string
+            description: "enum values, only considered when type = ENUM"
+        sets:
+          type: array
+          description: "set values, only considered when type = SET"
+          items:
+            type: string
+            description: "set values, only considered when type = SET"
+        index_length:
+          type: integer
+          format: int64
+        null_allowed:
+          type: boolean
+          example: true
+        concept_uri:
+          type: string
+        unit_uri:
+          type: string
+    CreateTableConstraintsDto:
+      required:
+      - checks
+      - foreign_keys
+      - primary_key
+      - uniques
+      type: object
+      properties:
+        uniques:
+          type: array
+          items:
+            type: array
+            items:
+              type: string
+        checks:
+          uniqueItems: true
+          type: array
+          items:
+            type: string
+        foreign_keys:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreateForeignKeyDto"
+        primary_key:
+          uniqueItems: true
+          type: array
+          items:
+            type: string
+    CreateTableDto:
+      required:
+      - columns
+      - constraints
+      - is_public
+      - is_schema_public
+      - name
+      type: object
+      properties:
+        name:
+          maxLength: 64
+          minLength: 1
+          type: string
+          example: Air Quality
+        description:
+          maxLength: 180
+          minLength: 0
+          type: string
+          example: Air Quality in Austria
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreateTableColumnDto"
+        constraints:
+          $ref: "#/components/schemas/CreateTableConstraintsDto"
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    CreateContainerDto:
+      required:
+      - host
+      - image_id
+      - name
+      - privileged_password
+      - privileged_username
+      - quota
+      type: object
+      properties:
+        name:
+          type: string
+          example: Air Quality
+        host:
+          type: string
+          description: Hostname of container
+          example: data-db2
+        port:
+          type: integer
+          description: Port of container
+          format: int32
+          example: 3306
+        quota:
+          type: integer
+          format: int64
+          example: 50
+        image_id:
+          type: integer
+          description: Image ID
+          format: int64
+          example: 1
+        ui_host:
+          type: string
+          example: example.com
+        ui_port:
+          type: integer
+          format: int32
+          example: 3306
+        privileged_username:
+          type: string
+          description: Username of privileged user
+          example: root
+        privileged_password:
+          type: string
+          description: Password of privileged user
+          example: dbrepo
+    ContainerDto:
+      required:
+      - count
+      - id
+      - image
+      - internal_name
+      - name
+      - quota
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        name:
+          type: string
+          example: Air Quality
+        host:
+          type: string
+          example: data-db
+        port:
+          type: integer
+          format: int32
+          example: 3306
+        image:
+          $ref: "#/components/schemas/ImageDto"
+        quota:
+          type: integer
+          format: int64
+          example: 50
+        count:
+          type: integer
+          format: int64
+          example: 10
+        username:
+          type: string
+          example: username
+        password:
+          type: string
+          example: p4ssw0rd
+        last_retrieved:
+          type: string
+          format: date-time
+        internal_name:
+          type: string
+          example: air_quality
+        ui_host:
+          type: string
+          example: example.com
+        ui_port:
+          type: integer
+          format: int32
+          example: 3306
+    ColumnBriefDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - name
+      - table_id
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Given Name
+        alias:
+          type: string
+          example: firstname
+        database_id:
+          type: integer
+          format: int64
+          example: 2
+        table_id:
+          type: integer
+          format: int64
+          example: 3
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: given_name
+        type:
+          type: string
+          example: varchar
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+    UnitDto:
+      required:
+      - columns
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+        name:
+          type: string
+        description:
+          type: string
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnBriefDto"
+    OntologyBriefDto:
+      required:
+      - id
+      - prefix
+      - rdf
+      - sparql
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+          example: http://www.wikidata.org/
+        prefix:
+          type: string
+          example: wd
+        sparql:
+          type: boolean
+          example: true
+        rdf:
+          type: boolean
+          example: false
+        uri_pattern:
+          type: string
+          example: http://www.wikidata.org/entity/.*
+    EntityDto:
+      required:
+      - label
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: https://www.wikidata.org/entity/Q1686799
+        label:
+          type: string
+          example: Apache Jena
+        description:
+          type: string
+          example: open source semantic web framework for Java
+    OaiListIdentifiersParameters:
+      type: object
+      properties:
+        metadataPrefix:
+          type: string
+        from:
+          type: string
+        until:
+          type: string
+        set:
+          type: string
+        resumptionToken:
+          type: string
+        fromDate:
+          type: string
+          format: date-time
+        untilDate:
+          type: string
+          format: date-time
+        parametersString:
+          type: string
+    BannerMessageDto:
+      required:
+      - id
+      - message
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+        display_start:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        display_end:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+    ImageBriefDto:
+      required:
+      - default
+      - id
+      - jdbc_method
+      - name
+      - version
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 5
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+          example: "10.5"
+        jdbc_method:
+          type: string
+          example: mariadb
+        default:
+          type: boolean
+          example: false
+    LdCreatorDto:
+      required:
+      - '@type'
+      - name
+      type: object
+      properties:
+        name:
+          type: string
+        sameAs:
+          type: string
+        givenName:
+          type: string
+        familyName:
+          type: string
+        '@type':
+          type: string
+    LdDatasetDto:
+      required:
+      - '@context'
+      - '@type'
+      - citation
+      - creator
+      - description
+      - hasPart
+      - identifier
+      - name
+      - temporalCoverage
+      - url
+      - version
+      type: object
+      properties:
+        name:
+          type: string
+        description:
+          type: string
+        url:
+          type: string
+        identifier:
+          type: array
+          items:
+            type: string
+        license:
+          type: string
+        creator:
+          type: array
+          items:
+            $ref: "#/components/schemas/LdCreatorDto"
+        citation:
+          type: string
+        hasPart:
+          type: array
+          items:
+            $ref: "#/components/schemas/LdDatasetDto"
+        temporalCoverage:
+          type: string
+        version:
+          type: string
+          format: date-time
+        '@context':
+          type: string
+        '@type':
+          type: string
+    ConstraintsDto:
+      type: object
+      properties:
+        uniques:
+          type: array
+          items:
+            $ref: "#/components/schemas/UniqueDto"
+        checks:
+          uniqueItems: true
+          type: array
+          example:
+          - value > 1
+          items:
+            type: string
+            example: "[\"value > 1\"]"
+        foreign_keys:
+          type: array
+          items:
+            $ref: "#/components/schemas/ForeignKeyDto"
+        primary_key:
+          uniqueItems: true
+          type: array
+          items:
+            $ref: "#/components/schemas/PrimaryKeyDto"
+    DatabaseDto:
+      required:
+      - accesses
+      - contact
+      - exchange_name
+      - id
+      - identifiers
+      - internal_name
+      - is_public
+      - is_schema_public
+      - name
+      - owner
+      - subsets
+      - tables
+      - views
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 3
+        name:
+          type: string
+          example: Air Quality
+        description:
+          type: string
+          example: Air Quality
+        tables:
+          type: array
+          items:
+            $ref: "#/components/schemas/TableDto"
+        views:
+          type: array
+          items:
+            $ref: "#/components/schemas/ViewDto"
+        container:
+          $ref: "#/components/schemas/ContainerDto"
+        accesses:
+          type: array
+          items:
+            $ref: "#/components/schemas/DatabaseAccessDto"
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDto"
+        subsets:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDto"
+        contact:
+          $ref: "#/components/schemas/UserBriefDto"
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        exchange_name:
+          type: string
+          example: dbrepo
+        exchange_type:
+          type: string
+          example: topic
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        preview_image:
+          type: string
+    ForeignKeyBriefDto:
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 8
+    ForeignKeyDto:
+      required:
+      - name
+      - referenced_table
+      - references
+      - table
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        name:
+          type: string
+          example: fk_name
+        references:
+          type: array
+          items:
+            $ref: "#/components/schemas/ForeignKeyReferenceDto"
+        table:
+          $ref: "#/components/schemas/TableBriefDto"
+        referenced_table:
+          $ref: "#/components/schemas/TableBriefDto"
+        on_update:
+          type: string
+          example: restrict
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+        on_delete:
+          type: string
+          example: restrict
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+    ForeignKeyReferenceDto:
+      required:
+      - column
+      - foreign_key
+      - referenced_column
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 8
+        column:
+          $ref: "#/components/schemas/ColumnBriefDto"
+        foreign_key:
+          $ref: "#/components/schemas/ForeignKeyBriefDto"
+        referenced_column:
+          $ref: "#/components/schemas/ColumnBriefDto"
+    PrimaryKeyDto:
+      required:
+      - column
+      - table
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 8
+        table:
+          $ref: "#/components/schemas/TableBriefDto"
+        column:
+          $ref: "#/components/schemas/ColumnBriefDto"
+    TableDto:
+      required:
+      - columns
+      - constraints
+      - database_id
+      - id
+      - internal_name
+      - is_public
+      - is_schema_public
+      - is_versioned
+      - name
+      - owner
+      - queue_name
+      - routing_key
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 3
+        name:
+          type: string
+          example: Air Quality
+        alias:
+          type: string
+          example: a
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDto"
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Air Quality in Austria
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnDto"
+        database:
+          $ref: "#/components/schemas/DatabaseDto"
+        constraints:
+          $ref: "#/components/schemas/ConstraintsDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        database_id:
+          type: integer
+          format: int64
+          example: 2
+        internal_name:
+          type: string
+          example: air_quality
+        is_versioned:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        queue_name:
+          type: string
+          example: air_quality
+        queue_type:
+          type: string
+          example: quorum
+        routing_key:
+          type: string
+          example: dbrepo.1.2
+        is_public:
+          type: boolean
+          example: true
+        num_rows:
+          type: integer
+          format: int64
+          example: 5
+        data_length:
+          type: integer
+          description: in bytes
+          format: int64
+          example: 16384
+        max_data_length:
+          type: integer
+          description: in bytes
+          format: int64
+          example: 0
+        avg_row_length:
+          type: integer
+          description: in bytes
+          format: int64
+          example: 3276
+    UniqueDto:
+      required:
+      - columns
+      - id
+      - name
+      - table
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 5
+        name:
+          type: string
+          example: uk_name
+        table:
+          $ref: "#/components/schemas/TableBriefDto"
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnBriefDto"
+    ViewColumnDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - is_null_allowed
+      - name
+      - ord
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 12
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Given Name
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Column comment
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        ord:
+          type: integer
+          format: int32
+          example: 0
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: given_name
+        index_length:
+          type: integer
+          format: int64
+          example: 255
+        length:
+          type: integer
+          format: int64
+          example: 255
+        type:
+          type: string
+          example: varchar
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+        is_null_allowed:
+          type: boolean
+          example: false
+    ViewDto:
+      required:
+      - columns
+      - database_id
+      - id
+      - identifiers
+      - internal_name
+      - name
+      - owner
+      - query
+      - query_hash
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        name:
+          type: string
+          example: Air Quality
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDto"
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
+        database:
+          $ref: "#/components/schemas/DatabaseDto"
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ViewColumnDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        initial_view:
+          type: boolean
+          description: True if it is the default view for the database
+          example: true
+        query_hash:
+          type: string
+          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
+    TableColumnEntityDto:
+      required:
+      - column_id
+      - database_id
+      - table_id
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: https://www.wikidata.org/entity/Q1686799
+        label:
+          type: string
+          example: Apache Jena
+        description:
+          type: string
+          example: open source semantic web framework for Java
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        column_id:
+          type: integer
+          format: int64
+          example: 1
+    ContainerBriefDto:
+      required:
+      - count
+      - hash
+      - id
+      - image
+      - internal_name
+      - name
+      - quota
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        hash:
+          type: string
+          example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50
+        name:
+          type: string
+          example: Air Quality
+        image:
+          $ref: "#/components/schemas/ImageBriefDto"
+        quota:
+          type: integer
+          format: int32
+          example: 50
+        count:
+          type: integer
+          format: int32
+          example: 10
+        internal_name:
+          type: string
+          example: air-quality
+    ConceptDto:
+      required:
+      - columns
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+        name:
+          type: string
+        description:
+          type: string
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnBriefDto"
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+    bearerAuth:
+      type: http
+      scheme: bearer
+      bearerFormat: JWT
diff --git a/.docs/.openapi/api-search.yaml b/.docs/.openapi/api-search.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c47cbfb649c8e832ccbd8238ea5e574ac522900b
--- /dev/null
+++ b/.docs/.openapi/api-search.yaml
@@ -0,0 +1,387 @@
+{
+  "components": {
+    "schemas": {
+      "IndexDto": {
+        "properties": {
+          "results": {
+            "items": {
+              "type": "object"
+            },
+            "type": "array"
+          },
+          "type": {
+            "description": "Same as the requested type",
+            "enum": [
+              "database",
+              "table",
+              "view",
+              "column",
+              "user",
+              "identifier",
+              "concept",
+              "unit"
+            ],
+            "type": "string"
+          }
+        },
+        "required": [
+          "results",
+          "type"
+        ]
+      },
+      "IndexFieldDto": {
+        "properties": {
+          "attr_friendly_name": {
+            "example": "Name",
+            "type": "string"
+          },
+          "attr_name": {
+            "example": "name",
+            "type": "string"
+          },
+          "type": {
+            "description": "OpenSearch data types.",
+            "example": "string",
+            "type": "string"
+          }
+        },
+        "required": [
+          "attr_name",
+          "attr_friendly_name",
+          "type"
+        ],
+        "type": "object"
+      },
+      "IndexFieldsDto": {
+        "properties": {
+          "results": {
+            "items": {
+              "$ref": "#/components/schemas/IndexFieldDto"
+            },
+            "type": "array"
+          }
+        },
+        "required": [
+          "results"
+        ],
+        "type": "object"
+      },
+      "SearchRequestDto": {
+        "properties": {
+          "field_value_pairs": {
+            "type": "object"
+          },
+          "search_term": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "search_term",
+          "field_value_pairs"
+        ],
+        "type": "object"
+      }
+    },
+    "securitySchemes": {
+      "basicAuth": {
+        "in": "header",
+        "scheme": "basic",
+        "type": "http"
+      },
+      "bearerAuth": {
+        "bearerFormat": "JWT",
+        "in": "header",
+        "scheme": "bearer",
+        "type": "http"
+      }
+    }
+  },
+  "externalDocs": {
+    "description": "Sourcecode Documentation",
+    "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/"
+  },
+  "info": {
+    "contact": {
+      "email": "andreas.rauber@tuwien.ac.at",
+      "name": "Prof. Andreas Rauber"
+    },
+    "description": "Service that searches the search database",
+    "license": {
+      "name": "Apache 2.0",
+      "url": "https://www.apache.org/licenses/LICENSE-2.0"
+    },
+    "title": "Database Repository Search Service API",
+    "version": "1.5"
+  },
+  "openapi": "3.0.0",
+  "paths": {
+    "/api/search": {
+      "get": {
+        "consumes": [
+          "application/json"
+        ],
+        "description": "Performs a fuzzy search",
+        "operationId": "post_fuzzy_search",
+        "parameters": [
+          {
+            "in": "query",
+            "name": "q",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "properties": {
+                    "id": {
+                      "type": "string"
+                    }
+                  },
+                  "type": "array"
+                }
+              }
+            },
+            "description": "OK, contains the elements formatted as an array of JSON arrays"
+          },
+          "415": {
+            "description": "Wrong accept type"
+          }
+        },
+        "summary": "Performs a fuzzy search",
+        "tags": [
+          "search-endpoint"
+        ]
+      }
+    },
+    "/api/search/{field_type}": {
+      "post": {
+        "consumes": [
+          "application/json"
+        ],
+        "description": "Performs a general search",
+        "operationId": "post_general_search",
+        "parameters": [
+          {
+            "description": "The search type.",
+            "in": "path",
+            "name": "type",
+            "required": true,
+            "schema": {
+              "enum": [
+                "database",
+                "table",
+                "view",
+                "column",
+                "user",
+                "identifier",
+                "concept",
+                "unit"
+              ],
+              "type": "string"
+            }
+          },
+          {
+            "in": "query",
+            "name": "t1",
+            "schema": {
+              "type": "integer"
+            }
+          },
+          {
+            "in": "query",
+            "name": "t2",
+            "schema": {
+              "type": "integer"
+            }
+          },
+          {
+            "in": "body",
+            "name": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/components/schemas/SearchRequestDto"
+            }
+          }
+        ],
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "properties": {
+                    "results": {
+                      "items": {
+                        "type": "object"
+                      },
+                      "type": "array"
+                    },
+                    "type": {
+                      "description": "Same as the requested type",
+                      "enum": [
+                        "database",
+                        "table",
+                        "view",
+                        "column",
+                        "user",
+                        "identifier",
+                        "concept",
+                        "unit"
+                      ],
+                      "type": "string"
+                    }
+                  },
+                  "type": "object"
+                }
+              }
+            },
+            "description": "OK, contains the elements formatted as an array of JSON arrays"
+          }
+        },
+        "summary": "Performs a general search",
+        "tags": [
+          "search-endpoint"
+        ]
+      }
+    },
+    "/api/search/{field_type}/fields": {
+      "get": {
+        "operationId": "get_fields",
+        "parameters": [
+          {
+            "description": "The search type.",
+            "in": "path",
+            "name": "type",
+            "required": true,
+            "schema": {
+              "enum": [
+                "database",
+                "table",
+                "view",
+                "column",
+                "user",
+                "identifier",
+                "concept",
+                "unit"
+              ],
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/IndexFieldsDto"
+                }
+              }
+            },
+            "description": "List of fields"
+          },
+          "404": {
+            "description": "Invalid type."
+          }
+        },
+        "summary": "Get searchable fields",
+        "tags": [
+          "search-endpoint"
+        ]
+      }
+    },
+    "/api/search/{index}": {
+      "get": {
+        "consumes": [
+          "application/json"
+        ],
+        "description": "Gets the index",
+        "operationId": "get_index",
+        "parameters": [
+          {
+            "description": "The search type.",
+            "in": "path",
+            "name": "type",
+            "required": true,
+            "schema": {
+              "enum": [
+                "database",
+                "table",
+                "view",
+                "column",
+                "user",
+                "identifier",
+                "concept",
+                "unit"
+              ],
+              "type": "string"
+            }
+          },
+          {
+            "in": "body",
+            "name": "body",
+            "required": true,
+            "schema": {
+              "properties": {
+                "field_value_pairs": {
+                  "type": "object"
+                },
+                "search_term": {
+                  "example": "air quality",
+                  "type": "string"
+                },
+                "t1": {
+                  "example": 0,
+                  "type": "integer"
+                },
+                "t2": {
+                  "example": 100,
+                  "type": "integer"
+                }
+              },
+              "type": "object"
+            }
+          }
+        ],
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/IndexDto"
+                }
+              }
+            },
+            "description": "OK, contains the elements formatted as an array of JSON arrays"
+          }
+        },
+        "summary": "Gets the index",
+        "tags": [
+          "search-endpoint"
+        ]
+      }
+    }
+  },
+  "servers": [
+    {
+      "description": "Generated server url",
+      "url": "http://localhost:4000"
+    },
+    {
+      "description": "Sandbox",
+      "url": "https://test.dbrepo.tuwien.ac.at"
+    }
+  ]
+}
diff --git a/.docs/.swagger/api.base.yaml b/.docs/.openapi/api.base.yaml
similarity index 98%
rename from .docs/.swagger/api.base.yaml
rename to .docs/.openapi/api.base.yaml
index fc0a733ccc7e1c4134f8a444c9b6fe08acb7aabb..ee32aad2ff6d82927876773fb76d26b79c7b846c 100644
--- a/.docs/.swagger/api.base.yaml
+++ b/.docs/.openapi/api.base.yaml
@@ -24,7 +24,7 @@ info:
     name: Apache 2.0
     url: https://www.apache.org/licenses/LICENSE-2.0
   title: DBRepo REST API
-  version: 1.6.1
+  version: 1.6.2
 openapi: 3.1.0
 servers:
   - description: Test Instance
diff --git a/.docs/.swagger/api.yaml b/.docs/.openapi/api.yaml
similarity index 94%
rename from .docs/.swagger/api.yaml
rename to .docs/.openapi/api.yaml
index dc7a627e743279d6eddf788cc9b1c18411912e50..c5d75bca5ae848f542e636fe91d656195e2dc6b2 100644
--- a/.docs/.swagger/api.yaml
+++ b/.docs/.openapi/api.yaml
@@ -16,7 +16,7 @@ info:
     name: Apache 2.0
     url: 'https://www.apache.org/licenses/LICENSE-2.0'
   title: DBRepo REST API
-  version: 1.6.1
+  version: 1.6.2
 servers:
   - description: Test Instance
     url: 'https://test.dbrepo.tuwien.ac.at'
@@ -432,6 +432,11 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: Authorization
+          in: header
+          required: true
+          schema:
+            type: string
       requestBody:
         content:
           application/json:
@@ -490,6 +495,11 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: Authorization
+          in: header
+          required: true
+          schema:
+            type: string
       requestBody:
         content:
           application/json:
@@ -550,6 +560,11 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: Authorization
+          in: header
+          required: true
+          schema:
+            type: string
       requestBody:
         content:
           application/json:
@@ -695,6 +710,12 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: timestamp
+          in: query
+          required: false
+          schema:
+            type: string
+            format: date-time
         - name: page
           in: query
           required: false
@@ -782,6 +803,12 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: timestamp
+          in: query
+          required: false
+          schema:
+            type: string
+            format: date-time
         - name: page
           in: query
           required: false
@@ -937,6 +964,11 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: Authorization
+          in: header
+          required: true
+          schema:
+            type: string
       requestBody:
         content:
           application/json:
@@ -979,9 +1011,11 @@ paths:
         - subset-endpoint
       summary: Find subsets
       description: >-
-        Finds subsets in the query store. The result can be optionally filtered
-        by setting `persisted`. When set to *true*, only persisted queries are
-        returned, otherwise only non-persisted queries are returned.
+        Finds subsets in the query store. When the database schema is marked as
+        hidden, the user needs to be authorized, have at least read-access to
+        the database. The result can be optionally filtered by setting
+        `persisted`. When set to *true*, only persisted queries are returned,
+        otherwise only non-persisted queries are returned.
       operationId: list
       parameters:
         - name: databaseId
@@ -1032,8 +1066,10 @@ paths:
         - subset-endpoint
       summary: Create subset
       description: >-
-        Creates a subset in the query store of the data database. Requires role
-        `execute-query` for private databases.
+        Creates a subset in the query store of the data database. Can also be
+        used without authentication if (and only if) the database is marked as
+        public (i.e. when `is_public` = `is_schema_public` is set to `true`).
+        Otherwise at least read access is required.
       operationId: create
       parameters:
         - name: databaseId
@@ -1313,9 +1349,11 @@ paths:
         - subset-endpoint
       summary: Find subset
       description: >-
-        Finds a subset in the data database. Requests with HTTP header
-        `Accept=application/json` return the metadata, requests with HTTP header
-        `Accept=text/csv` return the data as downloadable file.
+        Finds a subset in the data database.  When the database schema is marked
+        as hidden, the user needs to be authorized, have at least read-access to
+        the database.  Requests with HTTP header `Accept=application/json`
+        return the metadata, requests with HTTP header `Accept=text/csv` return
+        the data as downloadable file.
       operationId: findById
       parameters:
         - name: databaseId
@@ -1330,6 +1368,11 @@ paths:
           schema:
             type: integer
             format: int64
+        - name: Accept
+          in: header
+          required: true
+          schema:
+            type: string
         - name: timestamp
           in: query
           required: false
@@ -1412,7 +1455,7 @@ paths:
               schema:
                 type: array
                 items:
-                  $ref: '#/components/schemas/DatabaseDto'
+                  $ref: '#/components/schemas/DatabaseBriefDto'
     post:
       tags:
         - database-endpoint
@@ -1425,7 +1468,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/DatabaseCreateDto'
+              $ref: '#/components/schemas/CreateDatabaseDto'
         required: true
       responses:
         '201':
@@ -1433,7 +1476,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
         '400':
           description: Database create query is malformed or image is not supported
           content:
@@ -1513,7 +1556,7 @@ paths:
               schema:
                 type: array
                 items:
-                  $ref: '#/components/schemas/DatabaseDto'
+                  $ref: '#/components/schemas/DatabaseBriefDto'
   '/api/database/{databaseId}/access/{userId}':
     get:
       tags:
@@ -1568,7 +1611,7 @@ paths:
       description: >-
         Modifies access of a user with given id to database with given id.
         Requires role `update-database-access`.
-      operationId: update_6
+      operationId: update_5
       parameters:
         - name: databaseId
           in: path
@@ -1586,7 +1629,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/UpdateDatabaseAccessDto'
+              $ref: '#/components/schemas/CreateAccessDto'
         required: true
       responses:
         '202':
@@ -1653,7 +1696,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/UpdateDatabaseAccessDto'
+              $ref: '#/components/schemas/CreateAccessDto'
         required: true
       responses:
         '202':
@@ -1803,7 +1846,11 @@ paths:
       tags:
         - user-endpoint
       summary: Get user
-      description: Gets user with id from the metadata database. Requires authentication.
+      description: >-
+        Gets own user information from the metadata database. Requires
+        authentication. Foreign user information can only be obtained if
+        additional role `find-foreign-user` is present. Finding information
+        about internal users results in a 404 error.
       operationId: find_2
       parameters:
         - name: userId
@@ -1979,7 +2026,7 @@ paths:
       tags:
         - user-endpoint
       summary: Create token
-      description: Creates a user token via the auth service.
+      description: Creates a user token via the Auth Service.
       operationId: getToken
       requestBody:
         content:
@@ -2544,7 +2591,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
         '400':
           description: The visibility payload is malformed
           content:
@@ -2678,7 +2725,7 @@ paths:
           content:
             '*/*':
               schema:
-                $ref: '#/components/schemas/ViewDto'
+                $ref: '#/components/schemas/ViewBriefDto'
         '400':
           description: Update view query is malformed
           content:
@@ -2734,10 +2781,6 @@ paths:
       responses:
         '202':
           description: Delete view successfully
-          content:
-            '*/*':
-              schema:
-                type: object
         '400':
           description: Delete view query is malformed
           content:
@@ -2783,8 +2826,10 @@ paths:
         - table-endpoint
       summary: Find table
       description: >-
-        Finds a table with id. When the `system` role is present, the endpoint
-        responds with additional connection metadata in the header.
+        Finds a table with id. When a table is hidden (i.e. when `is_public` is
+        `false`), then the user needs to have at least read access and the role
+        `find-table`. When the `system` role is present, the endpoint responds
+        with additional connection metadata in the header.
       operationId: findById_2
       parameters:
         - name: databaseId
@@ -2806,27 +2851,12 @@ paths:
             X-Username:
               description: The authentication username
               style: simple
-            X-Table:
-              description: The table internal name
-              style: simple
             Access-Control-Expose-Headers:
               description: Expose custom headers
               style: simple
-            X-Type:
-              description: The JDBC connection type
-              style: simple
-            X-Database:
-              description: The database internal name
-              style: simple
             X-Password:
               description: The authentication password
               style: simple
-            X-Host:
-              description: The database hostname
-              style: simple
-            X-Port:
-              description: The database port number
-              style: simple
           content:
             application/json:
               schema:
@@ -2988,8 +3018,8 @@ paths:
       summary: Update statistics
       description: >-
         Updates basic statistical properties (min, max, mean, median, std.dev)
-        for numerical columns in a table with id. Requires role
-        `update-table-statistic`.
+        for numerical columns in a table with id. This action can only be
+        performed by the table owner. Requires role `update-table-statistic`.
       operationId: updateStatistic
       parameters:
         - name: databaseId
@@ -3013,6 +3043,12 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/ApiErrorDto'
+        '403':
+          description: Not the owner
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ApiErrorDto'
         '404':
           description: Failed to find database/table in metadata database
           content:
@@ -3044,7 +3080,7 @@ paths:
         with at least *READ* access to the associated database can update the
         column semantics (requires role `modify-table-column-semantics`) or
         foreign table columns if role `modify-foreign-table-column-semantics`.
-      operationId: update_5
+      operationId: updateColumn
       parameters:
         - name: databaseId
           in: path
@@ -3140,7 +3176,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
         '400':
           description: Owner payload is malformed
           content:
@@ -3197,7 +3233,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
         '403':
           description: Refresh view metadata is not permitted
           content:
@@ -3248,7 +3284,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
         '400':
           description: Failed to parse payload at search service
           content:
@@ -3342,7 +3378,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
         '403':
           description: Modify of image is not permitted
           content:
@@ -3350,7 +3386,7 @@ paths:
               schema:
                 $ref: '#/components/schemas/ApiErrorDto'
         '404':
-          description: Database or user could not be found
+          description: Database could not be found
           content:
             application/json:
               schema:
@@ -3381,7 +3417,11 @@ paths:
       tags:
         - user-endpoint
       summary: List users
-      description: Lists users known to the metadata database.
+      description: >-
+        Lists users known to the metadata database. Internal users are omitted
+        from the result list. If the optional query parameter `username` is
+        present, the result list can be filtered by matching this exact
+        username.
       operationId: findAll
       parameters:
         - name: username
@@ -3410,7 +3450,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/SignupRequestDto'
+              $ref: '#/components/schemas/CreateUserDto'
         required: true
       responses:
         '201':
@@ -3673,7 +3713,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/IdentifierCreateDto'
+              $ref: '#/components/schemas/CreateIdentifierDto'
         required: true
       responses:
         '201':
@@ -3766,7 +3806,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/ViewCreateDto'
+              $ref: '#/components/schemas/CreateViewDto'
         required: true
       responses:
         '201':
@@ -3819,7 +3859,10 @@ paths:
       tags:
         - table-endpoint
       summary: List tables
-      description: Lists all tables known to the metadata database.
+      description: >-
+        Lists all tables known to the metadata database. When a database has a
+        hidden schema (i.e. when `is_schema_public` is `false`), then the user
+        needs to have at least read access and the role `list-tables`.
       operationId: list_4
       parameters:
         - name: databaseId
@@ -3869,7 +3912,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/TableCreateDto'
+              $ref: '#/components/schemas/CreateTableDto'
         required: true
       responses:
         '201':
@@ -3952,7 +3995,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/ContainerCreateDto'
+              $ref: '#/components/schemas/CreateContainerDto'
         required: true
       responses:
         '201':
@@ -4186,7 +4229,13 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/DatabaseDto'
+                $ref: '#/components/schemas/DatabaseBriefDto'
+        '403':
+          description: Not allowed to view database
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ApiErrorDto'
         '404':
           description: 'Database, user or exchange could not be found'
           content:
@@ -4214,8 +4263,8 @@ paths:
         - table-endpoint
       summary: Suggest semantics
       description: >-
-        Suggests semantic concepts for a table. Requires role
-        `table-semantic-analyse`.
+        Suggests semantic concepts for a table. This action can only be
+        performed by the table owner. Requires role `table-semantic-analyse`.
       operationId: analyseTable
       parameters:
         - name: databaseId
@@ -4245,6 +4294,12 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/ApiErrorDto'
+        '403':
+          description: Not the table owner.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ApiErrorDto'
         '404':
           description: Failed to find database/table in metadata database
           content:
@@ -4417,7 +4472,10 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/SearchResultDto'
+                properties:
+                  id:
+                    type: string
+                type: array
           description: 'OK, contains the elements formatted as an array of JSON arrays'
         '415':
           description: Wrong accept type
@@ -4741,10 +4799,18 @@ components:
           type: object
           additionalProperties:
             type: object
+            example:
+              key: value
+          example:
+            key: value
         keys:
           type: object
           additionalProperties:
             type: object
+            example:
+              id: 1
+          example:
+            id: 1
     QueryPersistDto:
       required:
         - persist
@@ -4753,13 +4819,58 @@ components:
         persist:
           type: boolean
           example: true
+    CreatorBriefDto:
+      required:
+        - creator_name
+        - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 11
+        affiliation:
+          type: string
+          example: Brown University
+        creator_name:
+          type: string
+          example: 'Carberry, Josiah'
+        name_type:
+          type: string
+          example: Personal
+          enum:
+            - Personal
+            - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+            - ORCID
+            - ROR
+            - ISNI
+            - GRID
+        affiliation_identifier:
+          type: string
+          example: 'https://ror.org/05gq02987'
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+            - ROR
+            - GRID
+            - ISNI
     IdentifierBriefDto:
       required:
-        - created_by
+        - creators
         - database_id
         - id
+        - owned_by
         - publication_year
         - publisher
+        - status
         - titles
         - type
       type: object
@@ -4767,13 +4878,19 @@ components:
         id:
           type: integer
           format: int64
+          example: 2
         type:
           type: string
+          example: database
           enum:
             - database
             - subset
             - table
             - view
+        creators:
+          type: array
+          items:
+            $ref: '#/components/schemas/CreatorBriefDto'
         titles:
           type: array
           items:
@@ -4786,6 +4903,7 @@ components:
           example: TU Wien
         status:
           type: string
+          example: draft
           enum:
             - draft
             - published
@@ -4809,9 +4927,10 @@ components:
           type: integer
           format: int32
           example: 2022
-        created_by:
+        owned_by:
           type: string
           format: uuid
+          example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5
     IdentifierTitleDto:
       required:
         - id
@@ -4820,6 +4939,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 4
         title:
           type: string
           example: Airquality Demonstrator
@@ -5034,6 +5154,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 4
         owner:
           $ref: '#/components/schemas/UserBriefDto'
         execution:
@@ -5056,6 +5177,7 @@ components:
         database_id:
           type: integer
           format: int64
+          example: 1
         query_normalized:
           type: string
           example: SELECT `id` FROM `air_quality`
@@ -5110,6 +5232,10 @@ components:
           type: object
           additionalProperties:
             type: object
+            example:
+              key: value
+          example:
+            key: value
     ImportDto:
       required:
         - header
@@ -5125,6 +5251,7 @@ components:
           description: >-
             If true, the first line contains the column names, otherwise it
             contains only data
+          example: true
         separator:
           type: string
           example: ','
@@ -5168,107 +5295,38 @@ components:
           type: object
           additionalProperties:
             type: object
-    ContainerBriefDto:
-      required:
-        - count
-        - hash
-        - id
-        - image
-        - internal_name
-        - name
-        - quota
-      type: object
-      properties:
-        id:
-          type: integer
-          format: int64
-        hash:
-          type: string
-          example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50
-        name:
-          type: string
-          example: Air Quality
-        image:
-          $ref: '#/components/schemas/ImageBriefDto'
-        quota:
-          type: integer
-          format: int32
-          example: 50
-        count:
-          type: integer
-          format: int32
-          example: 10
-        internal_name:
-          type: string
-          example: air-quality
-    DatabaseAccessDto:
-      required:
-        - type
-        - user
-      type: object
-      properties:
-        user:
-          $ref: '#/components/schemas/UserBriefDto'
-        type:
-          type: string
-          enum:
-            - read
-            - write_own
-            - write_all
-    DatabaseDto:
+            example:
+              id: 1
+          example:
+            id: 1
+    DatabaseBriefDto:
       required:
         - contact
-        - container
-        - exchange_name
         - id
+        - identifiers
         - internal_name
         - is_public
         - is_schema_public
         - name
-        - owner
+        - owner_id
       type: object
       properties:
         id:
           type: integer
           format: int64
+          example: 3
         name:
           type: string
           example: Air Quality
         description:
           type: string
           example: Air Quality
-        tables:
-          type: array
-          items:
-            $ref: '#/components/schemas/TableBriefDto'
-        views:
-          type: array
-          items:
-            $ref: '#/components/schemas/ViewBriefDto'
-        container:
-          $ref: '#/components/schemas/ContainerBriefDto'
-        accesses:
-          type: array
-          items:
-            $ref: '#/components/schemas/DatabaseAccessDto'
         identifiers:
           type: array
           items:
             $ref: '#/components/schemas/IdentifierBriefDto'
-        subsets:
-          type: array
-          items:
-            $ref: '#/components/schemas/IdentifierBriefDto'
         contact:
           $ref: '#/components/schemas/UserBriefDto'
-        owner:
-          $ref: '#/components/schemas/UserBriefDto'
-        exchange_name:
-          type: string
-          example: dbrepo
-        exchange_type:
-          type: string
-          example: topic
         internal_name:
           type: string
           example: air_quality
@@ -5278,119 +5336,34 @@ components:
         is_schema_public:
           type: boolean
           example: true
+        owner_id:
+          type: string
+          format: uuid
+          example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5
         preview_image:
           type: string
-    ImageBriefDto:
+    DatabaseAccessDto:
       required:
-        - default
-        - id
-        - jdbc_method
-        - name
-        - version
+        - type
+        - user
       type: object
       properties:
-        id:
-          type: integer
-          format: int64
-        name:
-          type: string
-          example: mariadb
-        version:
-          type: string
-          example: '10.5'
-        jdbc_method:
+        user:
+          $ref: '#/components/schemas/UserBriefDto'
+        type:
           type: string
-          example: mariadb
-        default:
-          type: boolean
-          example: false
-    TableBriefDto:
+          example: read
+          enum:
+            - read
+            - write_own
+            - write_all
+    UserUpdateDto:
       required:
-        - database_id
-        - id
-        - internal_name
-        - is_public
-        - is_schema_public
-        - is_versioned
-        - name
-        - owned_by
+        - language
+        - theme
       type: object
       properties:
-        id:
-          type: integer
-          format: int64
-        name:
-          type: string
-          example: Air Quality
-        description:
-          type: string
-          example: Air Quality in Austria
-        database_id:
-          type: integer
-          format: int64
-        internal_name:
-          type: string
-          example: air_quality
-        is_versioned:
-          type: boolean
-          example: true
-        is_public:
-          type: boolean
-          example: true
-        is_schema_public:
-          type: boolean
-          example: true
-        owned_by:
-          type: string
-          format: uuid
-    ViewBriefDto:
-      required:
-        - database_id
-        - id
-        - internal_name
-        - name
-        - query
-        - query_hash
-      type: object
-      properties:
-        id:
-          type: integer
-          format: int64
-        name:
-          type: string
-          example: Air Quality
-        query:
-          type: string
-          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
-        database_id:
-          type: integer
-          format: int64
-        internal_name:
-          type: string
-          example: air_quality
-        is_public:
-          type: boolean
-          example: true
-        is_schema_public:
-          type: boolean
-          example: true
-        initial_view:
-          type: boolean
-          description: True if it is the default view for the database
-          example: true
-        query_hash:
-          type: string
-          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
-        owned_by:
-          type: string
-          format: uuid
-    UserUpdateDto:
-      required:
-        - language
-        - theme
-      type: object
-      properties:
-        firstname:
+        firstname:
           type: string
           example: Josiah
         lastname:
@@ -5430,6 +5403,7 @@ components:
       required:
         - attributes
         - id
+        - password
         - username
       type: object
       properties:
@@ -5437,15 +5411,20 @@ components:
           type: string
           format: uuid
           example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4
-        username:
-          type: string
-          description: Only contains lowercase characters
-          example: jcarberry
         name:
           type: string
           example: Josiah Carberry
+        username:
+          type: string
+          example: username
+        password:
+          type: string
+          example: p4ssw0rd
         attributes:
           $ref: '#/components/schemas/UserAttributesDto'
+        last_retrieved:
+          type: string
+          format: date-time
         qualified_name:
           type: string
           example: Josiah Carberry — @jcarberry
@@ -5707,6 +5686,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 1
         registry:
           type: string
           example: docker.io/library
@@ -5747,6 +5727,9 @@ components:
         - value
       type: object
       properties:
+        id:
+          type: integer
+          format: int64
         value:
           type: string
           example: XOR
@@ -5756,105 +5739,53 @@ components:
         display_name:
           type: string
           example: XOR
-    CreatorSaveDto:
-      required:
-        - creator_name
-        - id
-      type: object
-      properties:
-        id:
-          type: integer
-          format: int64
-          example: 1
-        firstname:
-          type: string
-          example: Josiah
-        lastname:
-          type: string
-          example: Carberry
-        affiliation:
-          type: string
-          example: Wesleyan University
-        creator_name:
-          type: string
-          example: 'Carberry, Josiah'
-        name_type:
-          type: string
-          example: Personal
-          enum:
-            - Personal
-            - Organizational
-        name_identifier:
-          type: string
-          example: 0000-0002-1825-0097
-        name_identifier_scheme:
-          type: string
-          example: ORCID
-          enum:
-            - ORCID
-            - ROR
-            - ISNI
-            - GRID
-        affiliation_identifier:
-          type: string
-          example: 'https://ror.org/04d836q62'
-        affiliation_identifier_scheme:
-          type: string
-          example: ROR
-          enum:
-            - ROR
-            - GRID
-            - ISNI
-    IdentifierFunderSaveDto:
+    IdentifierSaveDto:
       required:
-        - funder_name
+        - creators
+        - database_id
         - id
+        - publication_year
+        - publisher
+        - titles
+        - type
       type: object
       properties:
         id:
           type: integer
           format: int64
           example: 1
-        funder_name:
-          type: string
-          example: European Commission
-        funder_identifier:
-          type: string
-          example: 'http://doi.org/10.13039/501100000780'
-        funder_identifier_type:
+        type:
           type: string
-          example: Crossref Funder ID
+          example: database
           enum:
-            - Crossref Funder ID
-            - ROR
-            - GND
-            - ISNI
-            - Other
-        scheme_uri:
-          type: string
-          example: 'http://doi.org/'
-        award_number:
-          type: string
-          example: '824087'
-        award_title:
+            - database
+            - subset
+            - table
+            - view
+        doi:
           type: string
-          example: EOSC-Life
-    IdentifierSaveDescriptionDto:
-      required:
-        - description
-        - id
-      type: object
-      properties:
-        id:
-          type: integer
-          format: int64
-          example: 1
-        description:
+          example: 10.1111/11111111
+        titles:
+          type: array
+          items:
+            $ref: '#/components/schemas/SaveIdentifierTitleDto'
+        descriptions:
+          type: array
+          items:
+            $ref: '#/components/schemas/SaveIdentifierDescriptionDto'
+        funders:
+          type: array
+          items:
+            $ref: '#/components/schemas/SaveIdentifierFunderDto'
+        licenses:
+          type: array
+          items:
+            $ref: '#/components/schemas/LicenseDto'
+        publisher:
           type: string
-          example: 'Air quality reports at Stephansplatz, Vienna'
+          example: TU Wien
         language:
           type: string
-          example: en
           enum:
             - ab
             - aa
@@ -6040,63 +5971,123 @@ components:
             - yo
             - za
             - zu
-        type:
-          type: string
-          example: Abstract
-          enum:
-            - Abstract
-            - Methods
-            - SeriesInformation
-            - TableOfContents
-            - TechnicalInfo
-            - Other
-    IdentifierSaveDto:
-      required:
-        - creators
-        - database_id
-        - id
-        - publication_year
-        - publisher
-        - titles
-        - type
-      type: object
-      properties:
-        id:
+        creators:
+          type: array
+          items:
+            $ref: '#/components/schemas/SaveIdentifierCreatorDto'
+        database_id:
           type: integer
           format: int64
           example: 1
-        type:
-          type: string
-          example: database
-          enum:
-            - database
-            - subset
-            - table
-            - view
-        doi:
-          type: string
-          example: 10.1111/11111111
-        titles:
+        query_id:
+          type: integer
+          format: int64
+        view_id:
+          type: integer
+          format: int64
+        table_id:
+          type: integer
+          format: int64
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        related_identifiers:
           type: array
           items:
-            $ref: '#/components/schemas/IdentifierSaveTitleDto'
-        descriptions:
-          type: array
-          items:
-            $ref: '#/components/schemas/IdentifierSaveDescriptionDto'
-        funders:
-          type: array
-          items:
-            $ref: '#/components/schemas/IdentifierFunderSaveDto'
-        licenses:
-          type: array
-          items:
-            $ref: '#/components/schemas/LicenseDto'
-        publisher:
+            $ref: '#/components/schemas/SaveRelatedIdentifierDto'
+    LicenseDto:
+      required:
+        - identifier
+        - uri
+      type: object
+      properties:
+        identifier:
           type: string
-          example: TU Wien
+          example: MIT
+        uri:
+          type: string
+          example: 'https://opensource.org/licenses/MIT'
+        description:
+          type: string
+          example: >-
+            A short and simple permissive license with conditions only requiring
+            preservation of copyright and license notices. Licensed works,
+            modifications, and larger works may be distributed under different
+            terms and without source code.
+    SaveIdentifierCreatorDto:
+      required:
+        - creator_name
+        - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Wesleyan University
+        creator_name:
+          type: string
+          example: 'Carberry, Josiah'
+        name_type:
+          type: string
+          example: Personal
+          enum:
+            - Personal
+            - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+            - ORCID
+            - ROR
+            - ISNI
+            - GRID
+        affiliation_identifier:
+          type: string
+          example: 'https://ror.org/04d836q62'
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+            - ROR
+            - GRID
+            - ISNI
+    SaveIdentifierDescriptionDto:
+      required:
+        - description
+        - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        description:
+          type: string
+          example: 'Air quality reports at Stephansplatz, Vienna'
         language:
           type: string
+          example: en
           enum:
             - ab
             - aa
@@ -6282,40 +6273,51 @@ components:
             - yo
             - za
             - zu
-        creators:
-          type: array
-          items:
-            $ref: '#/components/schemas/CreatorSaveDto'
-        database_id:
+        type:
+          type: string
+          example: Abstract
+          enum:
+            - Abstract
+            - Methods
+            - SeriesInformation
+            - TableOfContents
+            - TechnicalInfo
+            - Other
+    SaveIdentifierFunderDto:
+      required:
+        - funder_name
+        - id
+      type: object
+      properties:
+        id:
           type: integer
           format: int64
           example: 1
-        query_id:
-          type: integer
-          format: int64
-        view_id:
-          type: integer
-          format: int64
-        table_id:
-          type: integer
-          format: int64
-        publication_day:
-          type: integer
-          format: int32
-          example: 15
-        publication_month:
-          type: integer
-          format: int32
-          example: 12
-        publication_year:
-          type: integer
-          format: int32
-          example: 2022
-        related_identifiers:
-          type: array
-          items:
-            $ref: '#/components/schemas/RelatedIdentifierSaveDto'
-    IdentifierSaveTitleDto:
+        funder_name:
+          type: string
+          example: European Commission
+        funder_identifier:
+          type: string
+          example: 'http://doi.org/10.13039/501100000780'
+        funder_identifier_type:
+          type: string
+          example: Crossref Funder ID
+          enum:
+            - Crossref Funder ID
+            - ROR
+            - GND
+            - ISNI
+            - Other
+        scheme_uri:
+          type: string
+          example: 'http://doi.org/'
+        award_number:
+          type: string
+          example: '824087'
+        award_title:
+          type: string
+          example: EOSC-Life
+    SaveIdentifierTitleDto:
       required:
         - id
         - title
@@ -6524,26 +6526,7 @@ components:
             - Subtitle
             - TranslatedTitle
             - Other
-    LicenseDto:
-      required:
-        - identifier
-        - uri
-      type: object
-      properties:
-        identifier:
-          type: string
-          example: MIT
-        uri:
-          type: string
-          example: 'https://opensource.org/licenses/MIT'
-        description:
-          type: string
-          example: >-
-            A short and simple permissive license with conditions only requiring
-            preservation of copyright and license notices. Licensed works,
-            modifications, and larger works may be distributed under different
-            terms and without source code.
-    RelatedIdentifierSaveDto:
+    SaveRelatedIdentifierDto:
       required:
         - id
         - relation
@@ -6627,6 +6610,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 11
         firstname:
           type: string
           example: Josiah
@@ -6680,6 +6664,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 3
         description:
           type: string
           example: 'Air quality reports at Stephansplatz, Vienna'
@@ -6883,17 +6868,20 @@ components:
             - Other
     IdentifierDto:
       required:
-        - created_by
         - creators
         - database_id
-        - execution
+        - descriptions
+        - funders
         - id
+        - language
+        - licenses
         - owner
         - publication_year
         - publisher
         - query
         - query_hash
         - query_normalized
+        - status
         - titles
         - type
       type: object
@@ -6901,8 +6889,10 @@ components:
         id:
           type: integer
           format: int64
+          example: 2
         type:
           type: string
+          example: database
           enum:
             - database
             - subset
@@ -6936,7 +6926,7 @@ components:
           type: string
           example: TU Wien
         owner:
-          $ref: '#/components/schemas/UserDto'
+          $ref: '#/components/schemas/UserBriefDto'
         language:
           type: string
           enum:
@@ -7134,6 +7124,7 @@ components:
             $ref: '#/components/schemas/CreatorDto'
         status:
           type: string
+          example: draft
           enum:
             - draft
             - published
@@ -7184,9 +7175,6 @@ components:
           type: integer
           format: int32
           example: 2022
-        created_by:
-          type: string
-          format: uuid
     IdentifierFunderDto:
       required:
         - funder_name
@@ -7196,6 +7184,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 2
         funder_name:
           type: string
           example: European Commission
@@ -7231,6 +7220,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 8
         value:
           type: string
           example: 10.70124/dc4zh-9ce78
@@ -7318,276 +7308,109 @@ components:
         is_schema_public:
           type: boolean
           example: true
-    ColumnBriefDto:
+    ViewBriefDto:
       required:
-        - column_type
         - database_id
         - id
         - internal_name
         - name
-        - table_id
+        - query
+        - query_hash
       type: object
       properties:
         id:
           type: integer
           format: int64
+          example: 4
         name:
           type: string
-          example: date
-        alias:
+          example: Air Quality
+        query:
           type: string
+          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
         database_id:
           type: integer
           format: int64
-        table_id:
-          type: integer
-          format: int64
+          example: 1
         internal_name:
           type: string
-          example: mdb_date
-        column_type:
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        initial_view:
+          type: boolean
+          description: True if it is the default view for the database
+          example: true
+        query_hash:
           type: string
-          example: date
-          enum:
-            - char
-            - varchar
-            - binary
-            - varbinary
-            - tinyblob
-            - tinytext
-            - text
-            - blob
-            - mediumtext
-            - mediumblob
-            - longtext
-            - longblob
-            - enum
-            - set
-            - serial
-            - bit
-            - tinyint
-            - bool
-            - smallint
-            - mediumint
-            - int
-            - bigint
-            - float
-            - double
-            - decimal
-            - date
-            - datetime
-            - timestamp
-            - time
-            - year
-    ConceptDto:
+          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
+        owned_by:
+          type: string
+          format: uuid
+          example: ac750fcf-ea02-4fce-85ac-d73857e18b35
+    TableUpdateDto:
       required:
-        - columns
-        - id
-        - uri
+        - is_public
+        - is_schema_public
       type: object
       properties:
-        id:
-          type: integer
-          format: int64
-        uri:
-          type: string
-        name:
-          type: string
-        description:
-          type: string
-        columns:
-          type: array
-          items:
-            $ref: '#/components/schemas/ColumnBriefDto'
-    UnitDto:
-      required:
-        - columns
-        - id
-        - uri
-      type: object
-      properties:
-        id:
-          type: integer
-          format: int64
-        uri:
-          type: string
-        name:
-          type: string
-        description:
-          type: string
-        columns:
-          type: array
-          items:
-            $ref: '#/components/schemas/ColumnBriefDto'
-    ViewColumnDto:
-      required:
-        - auto_generated
-        - column_type
-        - database_id
-        - id
-        - internal_name
-        - is_null_allowed
-        - is_public
-        - name
-        - ordinal_position
-      type: object
-      properties:
-        id:
-          type: integer
-          format: int64
-        name:
-          maxLength: 64
-          minLength: 0
-          type: string
-          example: Date
-        size:
-          type: integer
-          format: int64
-          example: 255
-        d:
-          type: integer
-          format: int64
-          example: 0
-        concept:
-          $ref: '#/components/schemas/ConceptDto'
-        unit:
-          $ref: '#/components/schemas/UnitDto'
         description:
-          maxLength: 2048
-          minLength: 0
-          type: string
-          example: Column comment
-        database_id:
-          type: integer
-          format: int64
-        ordinal_position:
-          type: integer
-          format: int32
-          example: 0
-        internal_name:
-          maxLength: 64
+          maxLength: 180
           minLength: 0
           type: string
-          example: mdb_date
-        auto_generated:
-          type: boolean
-          example: false
-        index_length:
-          type: integer
-          format: int64
-        length:
-          type: integer
-          format: int64
-        column_type:
-          type: string
-          example: string
-          enum:
-            - char
-            - varchar
-            - binary
-            - varbinary
-            - tinyblob
-            - tinytext
-            - text
-            - blob
-            - mediumtext
-            - mediumblob
-            - longtext
-            - longblob
-            - enum
-            - set
-            - serial
-            - bit
-            - tinyint
-            - bool
-            - smallint
-            - mediumint
-            - int
-            - bigint
-            - float
-            - double
-            - decimal
-            - date
-            - datetime
-            - timestamp
-            - time
-            - year
+          example: Air Quality in Austria
         is_public:
           type: boolean
           example: true
-        is_null_allowed:
+        is_schema_public:
           type: boolean
-          example: false
-    ViewDto:
+          example: true
+    TableBriefDto:
       required:
-        - columns
-        - database
         - database_id
         - id
         - internal_name
+        - is_public
+        - is_schema_public
+        - is_versioned
         - name
-        - owner
-        - query
-        - query_hash
+        - owned_by
       type: object
       properties:
         id:
           type: integer
           format: int64
-        database:
-          $ref: '#/components/schemas/DatabaseDto'
+          example: 3
         name:
           type: string
           example: Air Quality
-        identifiers:
-          type: array
-          items:
-            $ref: '#/components/schemas/IdentifierDto'
-        query:
+        description:
           type: string
-          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
-        owner:
-          $ref: '#/components/schemas/UserBriefDto'
-        columns:
-          type: array
-          items:
-            $ref: '#/components/schemas/ViewColumnDto'
+          example: Air Quality in Austria
         database_id:
           type: integer
           format: int64
+          example: 2
         internal_name:
           type: string
           example: air_quality
-        is_public:
-          type: boolean
-          example: true
-        is_schema_public:
-          type: boolean
-          example: true
-        initial_view:
+        is_versioned:
           type: boolean
-          description: True if it is the default view for the database
           example: true
-        query_hash:
-          type: string
-          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
-    TableUpdateDto:
-      required:
-        - is_public
-        - is_schema_public
-      type: object
-      properties:
-        description:
-          maxLength: 180
-          minLength: 0
-          type: string
-          example: Air Quality in Austria
         is_public:
           type: boolean
           example: true
         is_schema_public:
           type: boolean
           example: true
+        owned_by:
+          type: string
+          format: uuid
+          example: 78337b80-5699-45db-8111-cec86439ab6b
     ColumnSemanticsUpdateDto:
       type: object
       properties:
@@ -7597,27 +7420,28 @@ components:
           type: string
     ColumnDto:
       required:
-        - column_type
         - database_id
         - id
         - internal_name
         - is_null_allowed
-        - is_public
         - name
-        - ordinal_position
+        - ord
         - table_id
+        - type
       type: object
       properties:
         id:
           type: integer
           format: int64
+          example: 1
         name:
           maxLength: 64
           minLength: 0
           type: string
-          example: Date
+          example: Given Name
         alias:
           type: string
+          example: firstname
         size:
           type: integer
           format: int64
@@ -7633,9 +7457,9 @@ components:
           type: number
           example: 51
         concept:
-          $ref: '#/components/schemas/ConceptDto'
+          $ref: '#/components/schemas/ConceptBriefDto'
         unit:
-          $ref: '#/components/schemas/UnitDto'
+          $ref: '#/components/schemas/UnitBriefDto'
         description:
           maxLength: 2048
           minLength: 0
@@ -7643,19 +7467,27 @@ components:
           example: Column comment
         enums:
           type: array
+          example:
+            - val1
           items:
             type: string
+            example: '["val1"]'
         sets:
           type: array
+          example:
+            - val1
           items:
             type: string
+            example: '["val1"]'
         database_id:
           type: integer
           format: int64
+          example: 2
         table_id:
           type: integer
           format: int64
-        ordinal_position:
+          example: 3
+        ord:
           type: integer
           format: int32
           example: 0
@@ -7663,16 +7495,18 @@ components:
           maxLength: 64
           minLength: 0
           type: string
-          example: mdb_date
+          example: given_name
         index_length:
           type: integer
           format: int64
+          example: 255
         length:
           type: integer
           format: int64
-        column_type:
+          example: 255
+        type:
           type: string
-          example: string
+          example: varchar
           enum:
             - char
             - varchar
@@ -7725,12 +7559,49 @@ components:
         std_dev:
           type: number
           example: 5.32
-        is_public:
-          type: boolean
-          example: true
         is_null_allowed:
           type: boolean
           example: false
+    ConceptBriefDto:
+      required:
+        - id
+        - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 23
+        uri:
+          type: string
+          example: 'http://www.wikidata.org/entity/Q202444'
+        name:
+          type: string
+          example: given name
+        description:
+          type: string
+          example: >-
+            name typically used to differentiate people from the same family,
+            clan, or other social group who have a common last name
+    UnitBriefDto:
+      required:
+        - id
+        - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 34
+        uri:
+          type: string
+          example: 'http://www.wikidata.org/entity/Q1422583'
+        name:
+          type: string
+          example: importance
+        description:
+          type: string
+          example: 'subjective magnitude of value, meaning, or purpose'
     DatabaseTransferDto:
       required:
         - id
@@ -7744,18 +7615,19 @@ components:
       properties:
         key:
           type: string
-    UpdateDatabaseAccessDto:
+    CreateAccessDto:
       required:
         - type
       type: object
       properties:
         type:
           type: string
+          example: read
           enum:
             - read
             - write_own
             - write_all
-    SignupRequestDto:
+    CreateUserDto:
       required:
         - email
         - password
@@ -7860,7 +7732,7 @@ components:
           minimum: 1024
           type: integer
           format: int32
-    IdentifierCreateDto:
+    CreateIdentifierDto:
       required:
         - creators
         - database_id
@@ -7884,15 +7756,15 @@ components:
         titles:
           type: array
           items:
-            $ref: '#/components/schemas/IdentifierSaveTitleDto'
+            $ref: '#/components/schemas/SaveIdentifierTitleDto'
         descriptions:
           type: array
           items:
-            $ref: '#/components/schemas/IdentifierSaveDescriptionDto'
+            $ref: '#/components/schemas/SaveIdentifierDescriptionDto'
         funders:
           type: array
           items:
-            $ref: '#/components/schemas/IdentifierFunderSaveDto'
+            $ref: '#/components/schemas/SaveIdentifierFunderDto'
         licenses:
           type: array
           items:
@@ -8090,7 +7962,7 @@ components:
         creators:
           type: array
           items:
-            $ref: '#/components/schemas/CreatorSaveDto'
+            $ref: '#/components/schemas/SaveIdentifierCreatorDto'
         database_id:
           type: integer
           format: int64
@@ -8119,8 +7991,8 @@ components:
         related_identifiers:
           type: array
           items:
-            $ref: '#/components/schemas/RelatedIdentifierSaveDto'
-    DatabaseCreateDto:
+            $ref: '#/components/schemas/SaveRelatedIdentifierDto'
+    CreateDatabaseDto:
       required:
         - container_id
         - is_public
@@ -8141,7 +8013,7 @@ components:
         is_schema_public:
           type: boolean
           example: true
-    ViewCreateDto:
+    CreateViewDto:
       required:
         - is_public
         - is_schema_public
@@ -8163,7 +8035,40 @@ components:
         is_schema_public:
           type: boolean
           example: true
-    ColumnCreateDto:
+    CreateForeignKeyDto:
+      required:
+        - columns
+        - referenced_columns
+        - referenced_table
+      type: object
+      properties:
+        columns:
+          type: array
+          items:
+            type: string
+        referenced_table:
+          type: string
+        referenced_columns:
+          type: array
+          items:
+            type: string
+        on_update:
+          type: string
+          enum:
+            - restrict
+            - cascade
+            - set_null
+            - no_action
+            - set_default
+        on_delete:
+          type: string
+          enum:
+            - restrict
+            - cascade
+            - set_null
+            - no_action
+            - set_default
+    CreateTableColumnDto:
       required:
         - name
         - null_allowed
@@ -8242,7 +8147,7 @@ components:
           type: string
         unit_uri:
           type: string
-    ConstraintsCreateDto:
+    CreateTableConstraintsDto:
       required:
         - checks
         - foreign_keys
@@ -8264,57 +8169,24 @@ components:
         foreign_keys:
           type: array
           items:
-            $ref: '#/components/schemas/ForeignKeyCreateDto'
+            $ref: '#/components/schemas/CreateForeignKeyDto'
         primary_key:
           uniqueItems: true
           type: array
           items:
             type: string
-    ForeignKeyCreateDto:
+    CreateTableDto:
       required:
         - columns
-        - referenced_columns
-        - referenced_table
+        - constraints
+        - is_public
+        - is_schema_public
+        - name
       type: object
       properties:
-        columns:
-          type: array
-          items:
-            type: string
-        referenced_table:
-          type: string
-        referenced_columns:
-          type: array
-          items:
-            type: string
-        on_update:
-          type: string
-          enum:
-            - restrict
-            - cascade
-            - set_null
-            - no_action
-            - set_default
-        on_delete:
-          type: string
-          enum:
-            - restrict
-            - cascade
-            - set_null
-            - no_action
-            - set_default
-    TableCreateDto:
-      required:
-        - columns
-        - constraints
-        - is_public
-        - is_schema_public
-        - name
-      type: object
-      properties:
-        name:
-          maxLength: 64
-          minLength: 1
+        name:
+          maxLength: 64
+          minLength: 1
           type: string
           example: Air Quality
         description:
@@ -8325,16 +8197,16 @@ components:
         columns:
           type: array
           items:
-            $ref: '#/components/schemas/ColumnCreateDto'
+            $ref: '#/components/schemas/CreateTableColumnDto'
         constraints:
-          $ref: '#/components/schemas/ConstraintsCreateDto'
+          $ref: '#/components/schemas/CreateTableConstraintsDto'
         is_public:
           type: boolean
           example: true
         is_schema_public:
           type: boolean
           example: true
-    ContainerCreateDto:
+    CreateContainerDto:
       required:
         - host
         - image_id
@@ -8350,10 +8222,12 @@ components:
         host:
           type: string
           description: Hostname of container
+          example: data-db2
         port:
           type: integer
           description: Port of container
           format: int32
+          example: 3306
         quota:
           type: integer
           format: int64
@@ -8362,11 +8236,14 @@ components:
           type: integer
           description: Image ID
           format: int64
+          example: 1
         ui_host:
           type: string
+          example: example.com
         ui_port:
           type: integer
           format: int32
+          example: 3306
         privileged_username:
           type: string
           description: Username of privileged user
@@ -8374,29 +8251,31 @@ components:
         privileged_password:
           type: string
           description: Password of privileged user
+          example: dbrepo
     ContainerDto:
       required:
         - count
-        - host
         - id
         - image
         - internal_name
         - name
-        - port
         - quota
       type: object
       properties:
         id:
           type: integer
           format: int64
+          example: 4
         name:
           type: string
           example: Air Quality
         host:
           type: string
+          example: data-db
         port:
           type: integer
           format: int32
+          example: 3306
         image:
           $ref: '#/components/schemas/ImageDto'
         quota:
@@ -8407,14 +8286,114 @@ components:
           type: integer
           format: int64
           example: 10
+        username:
+          type: string
+          example: username
+        password:
+          type: string
+          example: p4ssw0rd
+        last_retrieved:
+          type: string
+          format: date-time
         internal_name:
           type: string
-          example: data-db
+          example: air_quality
         ui_host:
           type: string
+          example: example.com
         ui_port:
           type: integer
           format: int32
+          example: 3306
+    ColumnBriefDto:
+      required:
+        - database_id
+        - id
+        - internal_name
+        - name
+        - table_id
+        - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Given Name
+        alias:
+          type: string
+          example: firstname
+        database_id:
+          type: integer
+          format: int64
+          example: 2
+        table_id:
+          type: integer
+          format: int64
+          example: 3
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: given_name
+        type:
+          type: string
+          example: varchar
+          enum:
+            - char
+            - varchar
+            - binary
+            - varbinary
+            - tinyblob
+            - tinytext
+            - text
+            - blob
+            - mediumtext
+            - mediumblob
+            - longtext
+            - longblob
+            - enum
+            - set
+            - serial
+            - bit
+            - tinyint
+            - bool
+            - smallint
+            - mediumint
+            - int
+            - bigint
+            - float
+            - double
+            - decimal
+            - date
+            - datetime
+            - timestamp
+            - time
+            - year
+    UnitDto:
+      required:
+        - columns
+        - id
+        - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+        name:
+          type: string
+        description:
+          type: string
+        columns:
+          type: array
+          items:
+            $ref: '#/components/schemas/ColumnBriefDto'
     OntologyBriefDto:
       required:
         - id
@@ -8470,14 +8449,14 @@ components:
           type: string
         resumptionToken:
           type: string
-        parametersString:
-          type: string
         fromDate:
           type: string
           format: date-time
         untilDate:
           type: string
           format: date-time
+        parametersString:
+          type: string
     BannerMessageDto:
       required:
         - id
@@ -8511,6 +8490,31 @@ components:
           type: string
           format: date-time
           example: '2021-03-12T15:26:21.000Z'
+    ImageBriefDto:
+      required:
+        - default
+        - id
+        - jdbc_method
+        - name
+        - version
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 5
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+          example: '10.5'
+        jdbc_method:
+          type: string
+          example: mariadb
+        default:
+          type: boolean
+          example: false
     LdCreatorDto:
       required:
         - '@type'
@@ -8583,8 +8587,11 @@ components:
         checks:
           uniqueItems: true
           type: array
+          example:
+            - value > 1
           items:
             type: string
+            example: '["value > 1"]'
         foreign_keys:
           type: array
           items:
@@ -8594,12 +8601,86 @@ components:
           type: array
           items:
             $ref: '#/components/schemas/PrimaryKeyDto'
+    DatabaseDto:
+      required:
+        - accesses
+        - contact
+        - exchange_name
+        - id
+        - identifiers
+        - internal_name
+        - is_public
+        - is_schema_public
+        - name
+        - owner
+        - subsets
+        - tables
+        - views
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 3
+        name:
+          type: string
+          example: Air Quality
+        description:
+          type: string
+          example: Air Quality
+        tables:
+          type: array
+          items:
+            $ref: '#/components/schemas/TableDto'
+        views:
+          type: array
+          items:
+            $ref: '#/components/schemas/ViewDto'
+        container:
+          $ref: '#/components/schemas/ContainerDto'
+        accesses:
+          type: array
+          items:
+            $ref: '#/components/schemas/DatabaseAccessDto'
+        identifiers:
+          type: array
+          items:
+            $ref: '#/components/schemas/IdentifierDto'
+        subsets:
+          type: array
+          items:
+            $ref: '#/components/schemas/IdentifierDto'
+        contact:
+          $ref: '#/components/schemas/UserBriefDto'
+        owner:
+          $ref: '#/components/schemas/UserBriefDto'
+        last_retrieved:
+          type: string
+          format: date-time
+        exchange_name:
+          type: string
+          example: dbrepo
+        exchange_type:
+          type: string
+          example: topic
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        preview_image:
+          type: string
     ForeignKeyBriefDto:
       type: object
       properties:
         id:
           type: integer
           format: int64
+          example: 8
     ForeignKeyDto:
       required:
         - name
@@ -8611,8 +8692,10 @@ components:
         id:
           type: integer
           format: int64
+          example: 4
         name:
           type: string
+          example: fk_name
         references:
           type: array
           items:
@@ -8623,6 +8706,7 @@ components:
           $ref: '#/components/schemas/TableBriefDto'
         on_update:
           type: string
+          example: restrict
           enum:
             - restrict
             - cascade
@@ -8631,6 +8715,7 @@ components:
             - set_default
         on_delete:
           type: string
+          example: restrict
           enum:
             - restrict
             - cascade
@@ -8647,6 +8732,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 8
         column:
           $ref: '#/components/schemas/ColumnBriefDto'
         foreign_key:
@@ -8662,6 +8748,7 @@ components:
         id:
           type: integer
           format: int64
+          example: 8
         table:
           $ref: '#/components/schemas/TableBriefDto'
         column:
@@ -8685,11 +8772,13 @@ components:
         id:
           type: integer
           format: int64
+          example: 3
         name:
           type: string
           example: Air Quality
         alias:
           type: string
+          example: a
         identifiers:
           type: array
           items:
@@ -8705,11 +8794,17 @@ components:
           type: array
           items:
             $ref: '#/components/schemas/ColumnDto'
+        database:
+          $ref: '#/components/schemas/DatabaseDto'
         constraints:
           $ref: '#/components/schemas/ConstraintsDto'
+        last_retrieved:
+          type: string
+          format: date-time
         database_id:
           type: integer
           format: int64
+          example: 2
         internal_name:
           type: string
           example: air_quality
@@ -8761,14 +8856,165 @@ components:
         id:
           type: integer
           format: int64
+          example: 5
         name:
           type: string
+          example: uk_name
         table:
           $ref: '#/components/schemas/TableBriefDto'
         columns:
           type: array
           items:
-            $ref: '#/components/schemas/ColumnDto'
+            $ref: '#/components/schemas/ColumnBriefDto'
+    ViewColumnDto:
+      required:
+        - database_id
+        - id
+        - internal_name
+        - is_null_allowed
+        - name
+        - ord
+        - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 12
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Given Name
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Column comment
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        ord:
+          type: integer
+          format: int32
+          example: 0
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: given_name
+        index_length:
+          type: integer
+          format: int64
+          example: 255
+        length:
+          type: integer
+          format: int64
+          example: 255
+        type:
+          type: string
+          example: varchar
+          enum:
+            - char
+            - varchar
+            - binary
+            - varbinary
+            - tinyblob
+            - tinytext
+            - text
+            - blob
+            - mediumtext
+            - mediumblob
+            - longtext
+            - longblob
+            - enum
+            - set
+            - serial
+            - bit
+            - tinyint
+            - bool
+            - smallint
+            - mediumint
+            - int
+            - bigint
+            - float
+            - double
+            - decimal
+            - date
+            - datetime
+            - timestamp
+            - time
+            - year
+        is_null_allowed:
+          type: boolean
+          example: false
+    ViewDto:
+      required:
+        - columns
+        - database_id
+        - id
+        - identifiers
+        - internal_name
+        - name
+        - owner
+        - query
+        - query_hash
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        name:
+          type: string
+          example: Air Quality
+        identifiers:
+          type: array
+          items:
+            $ref: '#/components/schemas/IdentifierDto'
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
+        database:
+          $ref: '#/components/schemas/DatabaseDto'
+        owner:
+          $ref: '#/components/schemas/UserBriefDto'
+        columns:
+          type: array
+          items:
+            $ref: '#/components/schemas/ViewColumnDto'
+        last_retrieved:
+          type: string
+          format: date-time
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        initial_view:
+          type: boolean
+          description: True if it is the default view for the database
+          example: true
+        query_hash:
+          type: string
+          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
     TableColumnEntityDto:
       required:
         - column_id
@@ -8798,6 +9044,60 @@ components:
           type: integer
           format: int64
           example: 1
+    ContainerBriefDto:
+      required:
+        - count
+        - hash
+        - id
+        - image
+        - internal_name
+        - name
+        - quota
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 4
+        hash:
+          type: string
+          example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50
+        name:
+          type: string
+          example: Air Quality
+        image:
+          $ref: '#/components/schemas/ImageBriefDto'
+        quota:
+          type: integer
+          format: int32
+          example: 50
+        count:
+          type: integer
+          format: int32
+          example: 10
+        internal_name:
+          type: string
+          example: air-quality
+    ConceptDto:
+      required:
+        - columns
+        - id
+        - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+        name:
+          type: string
+        description:
+          type: string
+        columns:
+          type: array
+          items:
+            $ref: '#/components/schemas/ColumnBriefDto'
     IndexDto:
       properties:
         results:
@@ -8855,12 +9155,3 @@ components:
         - search_term
         - field_value_pairs
       type: object
-    SearchResultDto:
-      properties:
-        results:
-          items:
-            type: object
-          type: array
-      required:
-        - results
-      type: object
diff --git a/.docs/.swagger/custom.css b/.docs/.openapi/custom.css
similarity index 100%
rename from .docs/.swagger/custom.css
rename to .docs/.openapi/custom.css
diff --git a/.docs/.swagger/swagger-generate.sh b/.docs/.openapi/openapi-generate.sh
similarity index 82%
rename from .docs/.swagger/swagger-generate.sh
rename to .docs/.openapi/openapi-generate.sh
index 884c2adface7aa773fe83e429ecea7f3b5ab4eef..edd927d202b42256f1da21a4415410ccee50466d 100644
--- a/.docs/.swagger/swagger-generate.sh
+++ b/.docs/.openapi/openapi-generate.sh
@@ -10,10 +10,10 @@ services[9099]=metadata
 function retrieve () {
   if [[ "$2" == analyse ]] || [[ "$2" == search ]]; then
     echo "... retrieve json api from localhost:$1"
-    curl -sSL "http://localhost:$1/api-$2.json" | yq -p=json > "./.docs/.swagger/api-$2.yaml"
+    curl -sSL "http://localhost:$1/api-$2.json" | yq -o=json - > "./.docs/.openapi/api-$2.yaml"
   else
     echo "... retrieve yaml api from localhost:$1"
-    curl -sSL "http://localhost:$1/v3/api-docs.yaml" > "./.docs/.swagger/api-$2.yaml"
+    curl -sSL "http://localhost:$1/v3/api-docs.yaml" > "./.docs/.openapi/api-$2.yaml"
   fi
 }
 
diff --git a/.docs/.swagger/openapi-merge.json b/.docs/.openapi/openapi-merge.json
similarity index 100%
rename from .docs/.swagger/openapi-merge.json
rename to .docs/.openapi/openapi-merge.json
diff --git a/.docs/.swagger/swagger-ui.html b/.docs/.openapi/swagger-ui.html
similarity index 80%
rename from .docs/.swagger/swagger-ui.html
rename to .docs/.openapi/swagger-ui.html
index 0bb08a1c07c1bfca6cc820474190dada3580df48..e84dd2ca47861ad5cdc87f51d9671a9d28e2c97b 100644
--- a/.docs/.swagger/swagger-ui.html
+++ b/.docs/.openapi/swagger-ui.html
@@ -5,7 +5,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
     <meta name="description" content="DBRepo REST API description in OpenAPI 3.0"/>
     <title>DBRepo REST API</title>
-    <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui.css"/>
+    <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.18.2/swagger-ui.css"/>
     <link rel="stylesheet" href="./custom.css"/>
     <link rel="icon" href="https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/.docs/images/logos/favicon.png" />
 </head>
@@ -17,8 +17,8 @@
     </div>
 </div>
 <div id="swagger-ui"></div>
-<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-bundle.js" crossorigin></script>
-<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-standalone-preset.js" crossorigin></script>
+<script src="https://unpkg.com/swagger-ui-dist@5.18.2/swagger-ui-bundle.js" crossorigin></script>
+<script src="https://unpkg.com/swagger-ui-dist@5.18.2/swagger-ui-standalone-preset.js" crossorigin></script>
 <script>
     window.onload = () => {
       window.ui = SwaggerUIBundle({
diff --git a/.docs/api/auth-service.md b/.docs/api/auth-service.md
index 93e87beaf280b5ed9b96a2aca508308098676173..7b28901a9b9d49a01d48a313187f86832509a03b 100644
--- a/.docs/api/auth-service.md
+++ b/.docs/api/auth-service.md
@@ -88,10 +88,6 @@ which is imported into Keycloak on startup.
 
 ## Limitations
 
-* No support for sending e-mails through Keycloak by default.
-* No support for temporary passwords.
-* No support for multi-factor authentication.
-
 !!! question "Do you miss functionality? Do these limitations affect you?"
 
     We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get
diff --git a/.docs/api/ui.md b/.docs/api/ui.md
index 30b32c0a0ccde771c8bde22f21ca630d6354a9b3..b82058c19bae4c4e629e0f1e06eca29985c94f67 100644
--- a/.docs/api/ui.md
+++ b/.docs/api/ui.md
@@ -101,6 +101,7 @@ See the [API Overview](..) page for detailed examples.
 
 ## Limitations
 
+* Changing the OIDC provider URL requires to build the UI from scratch.
 * When developing locally, the `axios` module does not parse custom headers (such as `X-Count`, `X-Headers`) and/or
   blocks CORS requests wrongfully.
 
diff --git a/.docs/changelog.md b/.docs/changelog.md
index f2bb1ab0571500d7cb4a80d955381d3ef03a2b52..efdb4dd291dbbc3194ffc3ec3168ed71befffee3 100644
--- a/.docs/changelog.md
+++ b/.docs/changelog.md
@@ -2,6 +2,33 @@
 author: Martin Weise
 ---
 
+## v1.6.3 (2025-02-05)
+
+[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.3)
+
+### What's Changed
+
+#### Changes
+
+* Refactored the UI to support OIDC and added an event listener to the Auth Service that syncs users on creation to the
+  Metadata DB in [#488](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/488).
+
+## v1.6.2 (2025-01-24)
+
+[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.2)
+
+### What's Changed
+
+#### Changes
+
+* Added interface tests for the Python library in Gitlab CI/CD pipeline
+  in [#486](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/486).
+
+#### Fixes
+
+* Fixed a bug where no pagination was possible
+  in [#487](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/487).
+
 ## v1.6.1 (2025-01-21)
 
 [:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.1)
@@ -15,7 +42,7 @@ author: Martin Weise
 
 #### Fixes
 
-* Added init container that adds the admin user to the Metadata Database 
+* Added init container that adds the admin user to the Metadata Database
   in [#480](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/480).
 
 ## v1.6.0 (2025-01-07)
diff --git a/.docs/concepts/data-visibility.md b/.docs/concepts/data-visibility.md
index 04f37c6979bd9019d954859535a757c72da4b63e..31c6ca3682780c4353c6aa5baaae666047893635 100644
--- a/.docs/concepts/data-visibility.md
+++ b/.docs/concepts/data-visibility.md
@@ -8,28 +8,40 @@ subset of a database.
 
 ## Visibility
 
-In total there are three possible scenarios:
+In total there are four possible visibility settings that can be applied on database level and then at the subsequent
+levels (table, view, subset). We give two examples for better understanding:
 
-#### Public
+!!! example "Example: Database that is hidden but certain views are visible"
+
+    Database *Airquality* has the settings to hide all data and schema by default.
+
+    * Table `sensor` inherits the settings from the database by default and therefore is also **hidden**. Nobody can
+      read/write to this database by default. Only designated users that the database owner allows to read/write can do
+      so.
+    * View `v_sensor` inherits the settings from the database by default and therefore is also **hidden**. The database
+      owner wants the data to be visible to the public (anonymously), so he changes the settings to data=visible,
+      schema=hidden. Now everybody can see the data but not the table(s) that contain the data.
+
+#### Visible
 
 !!! info "Possible use-case: data publication supplement to an open-access publication"
 
-Where the database's data and metadata is set to be *visible*. This means everything in the database (tables, views,
-subsets) are visible by anyone from the public.
+Where the resource's data and schema is set to be visible.
 
-#### Private
+#### Data-only
 
 !!! info "Possible use-case: private sensor measurements with timed embargo"
 
-Where the database's data set to be *hidden* but the schema to be *visible*. This means everything in the database
-(tables, views, subsets) are by default not visible by anyone from the public. You can however make specific views that
-join tables and/or filter certain columns and apply a 14-day delay-embargo.
+Where the resource's schema visibility is hidden but the data is visible.
 
-<figure markdown>
-![Mirroring statistical properties in Metadata Database and Search Database](../images/private-embargo.svg)
-<figcaption>Figure 1: Public view that joins two private tables and applies a time-embargo</figcaption>
-</figure>
+#### Schema-only
+
+!!! info "Possible use-case: publish data for reviewers before the final publication"
+
+Where the resource's data visibility is hidden but the schema is visible.
 
 #### Draft
 
-!!! info "Possible use-case: project data storage before publication"
\ No newline at end of file
+!!! info "Possible use-case: project data storage before publication"
+
+Where the resource's data and schema visibility is hidden. It will not be findable even in the search.
\ No newline at end of file
diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio
index 71536a321290f6c8cb39d147529a8b00fb458eed..b1aed4cb4035dfa1cbc08818c44ca5d7fac5a803 100644
--- a/.docs/images/architecture.drawio
+++ b/.docs/images/architecture.drawio
@@ -1,4 +1,4 @@
-<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/25.0.2 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="25.0.2" pages="9">
+<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.0.9 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="26.0.9" pages="9">
   <diagram id="mvBsv1rP8O80Qe3yGnn_" name="docker-compose">
     <mxGraphModel dx="683" dy="391" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
       <root>
@@ -1109,47 +1109,10 @@
     </mxGraphModel>
   </diagram>
   <diagram id="7HywRA3nQAgvNxZjCRq2" name="private-embargo">
-    <mxGraphModel dx="985" dy="394" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
+    <mxGraphModel dx="1434" dy="822" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
       <root>
         <mxCell id="0" />
         <mxCell id="1" parent="0" />
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0;entryDx=0;entryDy=0;curved=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-1" target="n6nk3BLY6128t3IB6Ma7-5">
-          <mxGeometry relative="1" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-11" value="&lt;span style=&quot;text-wrap: wrap; background-color: rgb(251, 251, 251);&quot;&gt;value,loc_id&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=8;" vertex="1" connectable="0" parent="n6nk3BLY6128t3IB6Ma7-8">
-          <mxGeometry x="0.0303" relative="1" as="geometry">
-            <mxPoint as="offset" />
-          </mxGeometry>
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-1" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
-          <mxGeometry x="250" y="170" width="80" height="80" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-2" value="&lt;b&gt;table&lt;/b&gt;: sensor (private)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-          <mxGeometry x="227.5" y="150" width="125" height="20" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;curved=1;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-3" target="n6nk3BLY6128t3IB6Ma7-5">
-          <mxGeometry relative="1" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-12" value="id,name,lat,lng" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=8;" vertex="1" connectable="0" parent="n6nk3BLY6128t3IB6Ma7-9">
-          <mxGeometry x="0.1455" relative="1" as="geometry">
-            <mxPoint as="offset" />
-          </mxGeometry>
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-3" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
-          <mxGeometry x="430" y="170" width="80" height="80" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-4" value="&lt;b&gt;table&lt;/b&gt;: location (private)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-          <mxGeometry x="405" y="150" width="130" height="20" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-5" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=8;" vertex="1" parent="1">
-          <mxGeometry x="340" y="290" width="80" height="80" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-6" value="&lt;b&gt;view&lt;/b&gt;: validated_sensor (public)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-          <mxGeometry x="290" y="370" width="180" height="20" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-4" target="n6nk3BLY6128t3IB6Ma7-4">
-          <mxGeometry relative="1" as="geometry" />
-        </mxCell>
       </root>
     </mxGraphModel>
   </diagram>
diff --git a/.docs/index.md b/.docs/index.md
index e16f9f5da6ccc94637fc0c1b56868e4fda84b023..d86224726f28fb78b3022601e02b00859a5ecc7d 100644
--- a/.docs/index.md
+++ b/.docs/index.md
@@ -14,7 +14,7 @@ author: Martin Weise
 ![Maintainability Rating](./images/maintainability.svg)
 ![Security Rating](./images/security.svg)
 
-Documentation for version: [v1.6.1](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases).
+Documentation for version: [v1.6.3](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases).
 
 DBRepo is a repository for data in databases that are used from the beginning until the end of a research 
 project supporting data evolution, -citation and -versioning. It implements the query store of the 
diff --git a/.docs/installation.md b/.docs/installation.md
index ee0d9b88faa47ca33f74c12c5cf63200e7ff7ffc..1c6db304ccf3d760c44e56b7d49aef49d76330ff 100644
--- a/.docs/installation.md
+++ b/.docs/installation.md
@@ -31,11 +31,11 @@ settings.
 - min. 200GB free SSD storage
 
 Since DBRepo is intended to be a publicly available repository, an optional fixed/static IP-address with optional
-SSL/TLS certificate is recommended. Follow the [secure install](#secure-install) guide.
+SSL/TLS certificate is recommended. Follow the [secure installation](#secure-installation) guide.
 
 ## Secure Installation
 
-Execute the install script to download only the environment and save it to `dist`.
+Execute the installation script to download only the environment and save it to `dist`.
 
 ```shell
 curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.6/install.sh | DOWNLOAD_ONLY=1 bash
@@ -50,6 +50,8 @@ Update the rest of the default secrets in the `.env` file to secure passwords. Y
 `openssl rand -hex 16`. Set `auth_ldap.dn_lookup_bind.password` in `dist/rabbitmq.conf` to the value of
 `SYSTEM_PASSWORD`.
 
+Only set the `BASE_URL` environment variable in `.env` when your hostname is **not** `localhost`.
+
 ### Runtime Configuration
 
 The [Auth Service](../api/auth-service) can be configured easily when DBRepo is running. Start DBRepo temporarily:
diff --git a/.docs/kubernetes.md b/.docs/kubernetes.md
index cc16bbe210d1b4ea98cd27ad8c47248bc551bafb..170bc863f58206778bf4488c48f322e6ad801996 100644
--- a/.docs/kubernetes.md
+++ b/.docs/kubernetes.md
@@ -14,7 +14,7 @@ helm upgrade --install dbrepo \
   -n dbrepo \
   "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" \
   --values ./values.yaml \
-  --version "1.6.1" \
+  --version "1.6.3" \
   --create-namespace \
   --cleanup-on-fail
 ```
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 122597e69534f19b49a1361c7db99f398bf0f811..85e5d640bbce875195f6c560d3e60e0d210f650e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,8 +10,8 @@ variables:
   SONARQUBE_VERSION: "10.0"
   BUN_VERSION: "1.1.40"
   DOC_VERSION: "1.6"
-  APP_VERSION: "1.6.1"
-  CHART_VERSION: "1.6.1"
+  APP_VERSION: "1.6.3"
+  CHART_VERSION: "1.6.3"
   CACHE_FALLBACK_KEY: "${CI_DEFAULT_BRANCH}"
   # This will supress any download for dependencies and plugins or upload messages which would clutter the console log.
   # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
@@ -44,34 +44,34 @@ lint-docker-compose:
   image: docker.io/alpine:${ALPINE_VERSION}
   stage: lint
   variables:
-    VERSION: 3.3.0
+    VERSION: 4.45.1
     BINARY: yq_linux_amd64
   before_script:
     - 'apk --no-cache add bash wget'
-    - 'wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq'
-    - 'ls -la .scripts'
+    - 'wget https://github.com/mikefarah/yq/releases/download/v${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq'
   script:
     - "bash .scripts/check-compose.sh"
-    - "yq compare -P docker-compose.yml .docker/docker-compose.yml 'volumes.*'"
+    - "diff <(yq '.volumes' docker-compose.yml) <(yq '.volumes' .docker/docker-compose.yml)"
     - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-analyse-service'"
-    - "bash .scripts/check-service.sh 'dbrepo-auth-db'"
+    - "IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-auth-db'"
     - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-auth-service'"
+    - "IGNORE_VOLUMES=1 IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-auth-service-init'"
     - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-broker-service'"
     - "IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-dashboard-service'"
     - "bash .scripts/check-service.sh 'dbrepo-data-db'"
     - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-data-service'"
     - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-gateway-service'"
-    - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-identity-service'"
+    - "IGNORE_VOLUMES=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-identity-service'"
     - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-metadata-db'"
     - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-metadata-service'"
-    - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-metric-db'"
+    - "IGNORE_VOLUMES=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-metric-db'"
     - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-db'"
     - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-search-service'"
     - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-service-init'"
     - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-storage-service'"
-    - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'"
+    - "IGNORE_VOLUMES=1 IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'"
     - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-ui'"
-    - "bash .scripts/check-service.sh 'dbrepo-upload-service'"
+    - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-upload-service'"
 
 lint-helm-chart:
   image: docker.io/alpine:${ALPINE_VERSION}
@@ -117,6 +117,19 @@ lint-metadata-schema:
   script:
     - diff dbrepo-metadata-db/1_setup-schema.sql helm/dbrepo/files/01-setup-schema.sql
 
+lint-open-api-version:
+  image: docker.io/alpine:${ALPINE_VERSION}
+  stage: lint
+  variables:
+    VERSION: 4.45.1
+    BINARY: yq_linux_amd64
+  before_script:
+    - 'apk --no-cache add bash wget'
+    - 'wget https://github.com/mikefarah/yq/releases/download/v${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq'
+  script:
+    - yq '.externalDocs.url' ./.docs/.openapi/api.base.yaml | grep "${DOC_VERSION}"
+    - yq '.info.version' ./.docs/.openapi/api.base.yaml | grep "${DOC_VERSION}"
+
 build-metadata-service:
   image: maven:3-openjdk-${JAVA_VERSION}
   stage: build
@@ -253,7 +266,7 @@ test-data-service:
   dependencies:
     - build-data-service
   script:
-    - "mvn -f ./dbrepo-metadata-service/pom.xml clean install $MAVEN_OPTS"
+    - "mvn -f ./dbrepo-metadata-service/pom.xml clean install -DskipTests $MAVEN_OPTS"
     - "mvn -f ./dbrepo-data-service/pom.xml clean test verify $MAVEN_OPTS"
     - "cat ./dbrepo-data-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'"
   artifacts:
@@ -471,9 +484,9 @@ release-docs:
   script:
     - "make gen-lib-doc gen-docs-doc package-config"
     - "cp -r ./lib/python/docs/build/html ./final/${DOC_VERSION}/python" # sphinx
-    - "cp .docs/.swagger/api.yaml ./final/${DOC_VERSION}/rest/api.yaml" # swagger
-    - "cp .docs/.swagger/swagger-ui.html ./final/${DOC_VERSION}/rest/index.html" # swagger
-    - "cp .docs/.swagger/custom.css ./final/${DOC_VERSION}/rest/custom.css" # swagger
+    - "cp .docs/.openapi/api.yaml ./final/${DOC_VERSION}/rest/api.yaml" # openapi
+    - "cp .docs/.openapi/swagger-ui.html ./final/${DOC_VERSION}/rest/index.html" # openapi
+    - "cp .docs/.openapi/custom.css ./final/${DOC_VERSION}/rest/custom.css" # openapi
     - "cp -r ./site/* ./final/${DOC_VERSION}" # mkdocs
     - "cp .docker/dist.tar.gz ./final/${APP_VERSION}/dist.tar.gz" # dist
     - "cp .docs/index.html.tpl ./final/index.html" # redirect patch docs
diff --git a/.gitlab/agents/dev/values.yaml b/.gitlab/agents/dev/values.yaml
index aa241d7f0eef507e104fb2ea49c9c01e37390ed5..5841a5e97bd5d9f9ddde4d13a2b74623a91cf4fb 100644
--- a/.gitlab/agents/dev/values.yaml
+++ b/.gitlab/agents/dev/values.yaml
@@ -26,6 +26,9 @@ authservice:
   client:
     id: dbrepo-client
     secret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG
+  setupJob:
+    image:
+      name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.3
   persistence:
     enabled: true
 
@@ -33,6 +36,7 @@ brokerservice:
   enabled: true
   ldap:
     bindpw: b8534187c9adf9618e7bd1c79c7f4639
+
 identityservice:
   enabled: true
   global:
@@ -66,9 +70,13 @@ searchdb:
 
 analyseservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
 
 metadataservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
   admin:
     email: noreply@example.com
   deletedRecord: permanent
@@ -83,6 +91,8 @@ metadataservice:
 
 dataservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
   rabbitmq:
     consumer:
       username: admin
@@ -95,9 +105,17 @@ dataservice:
 
 searchservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
+  init:
+    image:
+      name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
 
 storageservice:
   enabled: true
+  init:
+    image:
+      name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
 
 uploadservice:
   enabled: true
@@ -113,13 +131,15 @@ metricdb:
 
 ui:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
   public:
     api:
       client: https://s155.datalab.tuwien.ac.at
       server: https://s155.datalab.tuwien.ac.at
     title: "Database Repository"
     logo: "https://ec.tuwien.ac.at/~weise/images/DS_white_hiRes.png"
-    icon: "https://ec.tuwien.ac.at/~weise/images/DS-icon_white_hiRes.png"
+    icon: "https://ec.tuwien.ac.at/~weise/images/favicon.ico"
     touch: "https://ec.tuwien.ac.at/~weise/images/DS-icon_white_hiRes.png"
     broker:
       host: s155.datalab.tuwien.ac.at
diff --git a/.scripts/check-service.sh b/.scripts/check-service.sh
index decc22312b8a44049d4675cc36a5be3e6aafe072..1af6d7eea1556ca90f30b0abbe10abe2b623d140 100755
--- a/.scripts/check-service.sh
+++ b/.scripts/check-service.sh
@@ -1,16 +1,21 @@
 #!/bin/bash
-yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.restart"
-yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.container_name"
-yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.hostname"
+function compare () {
+  diff <(yq ".$1" docker-compose.yml) <(yq ".$1" .docker/docker-compose.yml)
+}
+
+compare "services.$1.restart"
+compare "services.$1.container_name"
+compare "services.$1.hostname"
+compare "services.$1.environment"
+compare "services.$1.healthcheck"
+compare "services.$1.logging"
+
 if [ -z "$IGNORE_IMAGE" ]; then
-  yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.image"
+  compare "services.$1.image"
 fi
 if [ -z "$IGNORE_VOLUMES" ]; then
-  yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.volumes"
+  compare "services.$1.volumes"
 fi
 if [ -z "$IGNORE_PORTS" ]; then
-  yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.ports"
+  compare "services.$1.ports"
 fi
-yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.environment"
-yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.healthcheck"
-yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.logging"
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 2479e382e55e3c20f1dd7f9c998fa5807a3f0e05..0dd2ae5e0a756aa713a101ddfff2ff8513222fa4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 .PHONY: all
 
-APP_VERSION ?= 1.6.1
-CHART_VERSION ?= 1.6.1
+APP_VERSION ?= 1.6.3
+CHART_VERSION ?= 1.6.3
 REPOSITORY_URL ?= registry.datalab.tuwien.ac.at/dbrepo
 
 .PHONY: all
diff --git a/dbrepo-analyse-service/.gitignore b/dbrepo-analyse-service/.gitignore
index d339f8575ccfbafdb8eef6431cce6c1add7aa92e..4ae9f6930d70a7da1f7b06d28fc7dcecf7ce24c4 100644
--- a/dbrepo-analyse-service/.gitignore
+++ b/dbrepo-analyse-service/.gitignore
@@ -17,12 +17,6 @@ venv/
 .venv/
 env*
 
-# Libraries
-./lib/dbrepo-1.4.4*
-./lib/dbrepo-1.4.5*
-./lib/dbrepo-1.4.6*
-./lib/dbrepo-1.4.7rc*
-
 # LLM
 *.bin
 
diff --git a/dbrepo-analyse-service/Pipfile b/dbrepo-analyse-service/Pipfile
index 831f8e532dd5f5796ca93cc6ca52fa7cecebb608..22a8e79b3a232b73784971df01dc283b8171388d 100644
--- a/dbrepo-analyse-service/Pipfile
+++ b/dbrepo-analyse-service/Pipfile
@@ -21,7 +21,7 @@ numpy = "*"
 pandas = "*"
 minio = "*"
 pydantic = "*"
-dbrepo = {path = "./lib/dbrepo-1.6.1.tar.gz"}
+dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"}
 opensearch-py = "*"
 
 [dev-packages]
diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock
index 99d70b613229b3fcc81638d99d038034b58ef9d6..5d2ace3655c32086fe018e0267ab207a9f1703b6 100644
--- a/dbrepo-analyse-service/Pipfile.lock
+++ b/dbrepo-analyse-service/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "683cc19a3205b9b5f9b99db8b71c0abadadfd652a94dcf710a73aeca92b97227"
+            "sha256": "9cc4c161729b642069bbf4ab379c0f4a9122035afcb3ac7b5b1bfc13281f76aa"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -159,11 +159,11 @@
         },
         "attrs": {
             "hashes": [
-                "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff",
-                "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"
+                "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e",
+                "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==24.3.0"
+            "version": "==25.1.0"
         },
         "blinker": {
             "hashes": [
@@ -175,20 +175,20 @@
         },
         "boto3": {
             "hashes": [
-                "sha256:7d398f66a11e67777c189d1f58c0a75d9d60f98d0ee51b8817e828930bf19e4e",
-                "sha256:8e49416216a6e3a62c2a0c44fba4dd2852c85472e7b702516605b1363867d220"
+                "sha256:7f61c9d0ea64f484a17c1e3115fdf90fd7b17ab6771e07cb4549f42b9fd28fb9",
+                "sha256:ac47215d320b0c2534340db58d6d5284cb1860b7bff172b4dd6eee2dee1d5779"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.8'",
-            "version": "==1.35.97"
+            "version": "==1.36.8"
         },
         "botocore": {
             "hashes": [
-                "sha256:88f2fab29192ffe2f2115d5bafbbd823ff4b6eb2774296e03ec8b5b0fe074f61",
-                "sha256:fed4f156b1a9b8ece53738f702ba5851b8c6216b4952de326547f349cc494f14"
+                "sha256:59d3fdfbae6d916b046e973bebcbeb70a102f9e570ca86d5ba512f1854b78fc2",
+                "sha256:81c88e5566cf018e1411a68304dc1fb9e4156ca2b50a3a0f0befc274299e67fa"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==1.35.97"
+            "version": "==1.36.8"
         },
         "certifi": {
             "hashes": [
@@ -412,9 +412,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:7cddcbdcb3eade84f67db01fa32e0649ecc01d4c3cc5e7542d3c402ad52efc19"
+                "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d"
             ],
-            "path": "./lib/dbrepo-1.6.1.tar.gz"
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
         },
         "events": {
             "hashes": [
@@ -829,20 +829,20 @@
         },
         "minio": {
             "hashes": [
-                "sha256:868dfe907e1702ce4bec86df1f3ced577a73ca85f344ef898d94fe2b5237f8c1",
-                "sha256:f5c24bf236fefd2edc567cd4455dc49a11ad8ff7ac984bb031b849d82f01222a"
+                "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79",
+                "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.9'",
-            "version": "==7.2.14"
+            "version": "==7.2.15"
         },
         "mistune": {
             "hashes": [
-                "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1",
-                "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667"
+                "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a",
+                "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==3.1.0"
+            "version": "==3.1.1"
         },
         "multidict": {
             "hashes": [
@@ -944,65 +944,65 @@
         },
         "numpy": {
             "hashes": [
-                "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2",
-                "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5",
-                "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60",
-                "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71",
-                "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631",
-                "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8",
-                "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2",
-                "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16",
-                "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa",
-                "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591",
-                "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964",
-                "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821",
-                "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484",
-                "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957",
-                "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800",
-                "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918",
-                "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95",
-                "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0",
-                "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e",
-                "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d",
-                "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73",
-                "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59",
-                "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51",
-                "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355",
-                "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348",
-                "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e",
-                "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440",
-                "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675",
-                "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84",
-                "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046",
-                "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab",
-                "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712",
-                "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308",
-                "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315",
-                "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3",
-                "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008",
-                "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5",
-                "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2",
-                "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e",
-                "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7",
-                "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf",
-                "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab",
-                "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd",
-                "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf",
-                "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8",
-                "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb",
-                "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268",
-                "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d",
-                "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780",
-                "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716",
-                "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e",
-                "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528",
-                "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af",
-                "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7",
-                "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51"
+                "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f",
+                "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0",
+                "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd",
+                "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2",
+                "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4",
+                "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648",
+                "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be",
+                "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb",
+                "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160",
+                "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd",
+                "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a",
+                "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84",
+                "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e",
+                "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748",
+                "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825",
+                "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60",
+                "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957",
+                "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715",
+                "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317",
+                "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e",
+                "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283",
+                "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278",
+                "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9",
+                "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de",
+                "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369",
+                "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb",
+                "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189",
+                "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014",
+                "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323",
+                "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e",
+                "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49",
+                "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50",
+                "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d",
+                "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37",
+                "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39",
+                "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576",
+                "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a",
+                "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba",
+                "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7",
+                "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826",
+                "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467",
+                "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495",
+                "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc",
+                "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391",
+                "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0",
+                "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97",
+                "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c",
+                "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac",
+                "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369",
+                "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8",
+                "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2",
+                "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff",
+                "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a",
+                "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df",
+                "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.10'",
-            "version": "==2.2.1"
+            "version": "==2.2.2"
         },
         "opensearch-py": {
             "hashes": [
@@ -1230,12 +1230,12 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
-                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
+                "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584",
+                "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.8'",
-            "version": "==2.10.5"
+            "version": "==2.10.6"
         },
         "pydantic-core": {
             "hashes": [
@@ -1427,11 +1427,11 @@
         },
         "referencing": {
             "hashes": [
-                "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c",
-                "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"
+                "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa",
+                "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"
             ],
-            "markers": "python_version >= '3.8'",
-            "version": "==0.35.1"
+            "markers": "python_version >= '3.9'",
+            "version": "==0.36.2"
         },
         "requests": {
             "hashes": [
@@ -1553,11 +1553,11 @@
         },
         "s3transfer": {
             "hashes": [
-                "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e",
-                "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"
+                "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f",
+                "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==0.10.4"
+            "version": "==0.11.2"
         },
         "setuptools": {
             "hashes": [
@@ -1601,11 +1601,11 @@
         },
         "tzdata": {
             "hashes": [
-                "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc",
-                "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"
+                "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694",
+                "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"
             ],
             "markers": "python_version >= '2'",
-            "version": "==2024.2"
+            "version": "==2025.1"
         },
         "urllib3": {
             "hashes": [
@@ -2079,12 +2079,12 @@
         },
         "minio": {
             "hashes": [
-                "sha256:868dfe907e1702ce4bec86df1f3ced577a73ca85f344ef898d94fe2b5237f8c1",
-                "sha256:f5c24bf236fefd2edc567cd4455dc49a11ad8ff7ac984bb031b849d82f01222a"
+                "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79",
+                "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.9'",
-            "version": "==7.2.14"
+            "version": "==7.2.15"
         },
         "opensearch-py": {
             "hashes": [
@@ -2241,81 +2241,88 @@
         },
         "wrapt": {
             "hashes": [
-                "sha256:09f5141599eaf36d6cc0b760ad87c2ab6b8618d009b2922639266676775a73a6",
-                "sha256:0aad4f54b3155d673a5c4706a71a0a84f3d415b2fc8a2a399a964d70f18846a2",
-                "sha256:0eb33799b7582bb73787b9903b70595f8eff67eecc9455f668ed01adf53f9eea",
-                "sha256:0ee037e4cc9d039efe712b13c483f4efa2c3499642369e01570b3bb1842eea3f",
-                "sha256:0fdc4e73a3fa0c25eed4d836d9732226f0326957cb075044a7f252b465299433",
-                "sha256:13887d1415dc0e213a9adeb9026ae1f427023f77110d988fbd478643490aa40c",
-                "sha256:144ed42a4ec3aca5d6f1524f99ee49493bbd0d9c66c24da7ec44b4661dca4dcc",
-                "sha256:14f78f8c313884f889c6696af62aa881af302a989a7c0df398d2b541fa53e8a9",
-                "sha256:15f96fe5e2efdc613983327240ae89cf6368c07eeb0f194d240e9549aa1ea739",
-                "sha256:162d5f15bdd3b8037e06540902227ef9e0f298496c0afaadd9e2875851446693",
-                "sha256:169033329022739c6f0d8cd3031a113953b0ba500f3d5978904bdd40baec4568",
-                "sha256:16b2fdfa09a74a3930175b6d9d7d008022aa72a4f02de2b3eecafcc1adfd3cfe",
-                "sha256:181a844005c9818792212a32e004cb4c6bd8e35cae8e97b1a39a1918d95cef58",
-                "sha256:18fb16fb6bb75f4ec6272829007f3129a9a5264d0230372f9651e5f75cfec552",
-                "sha256:1c119802ae432b8c5d55dd5253825d09c1dca1c97ffc7b32c53ecdb348712f64",
-                "sha256:20888d886186d19eab53816db2e615950b1ce7dbd5c239107daf2c8a6a4a03c6",
-                "sha256:21ffcf16f5c243a626b0f8da637948e3d5984e3bc0c1bc500ad990e88e974e3b",
-                "sha256:27a49f217839bf559d436308bae8fc4a9dd0ac98ffdb9d6aeb3f00385b0fb72c",
-                "sha256:2b20fcef5a3ee410671a5a59472e1ff9dda21cfbe5dfd15e23ee4b99ac455c8e",
-                "sha256:2c160bb8815787646b27a0c8575a26a4d6bf6abd7c5eb250ad3f2d38b29cb2cb",
-                "sha256:2f1bc359f6c52e53565e7af24b423e7a1eea97d155f38ac9e90e95303514710b",
-                "sha256:30c0c08434fe2af6e40c5c75c036d7e3c7e7f499079fc479e740d9586b09fb0d",
-                "sha256:3260178f3bc006acae93378bfd6dbf33c9249de93cc1b78d8cc7b7416f4ea99a",
-                "sha256:3dfd4738a630eddfcb7ff6c8e9fe863df3821f9c991dec73821e05450074ae09",
-                "sha256:50a4e3b45e62b1ccb96b3fc0e427f1b458ff2e0def34ae084de88418157a09d1",
-                "sha256:50bbfa7a92da7540426c774e09d6901e44d8f9b513b276ebae03ae244f0c6dbf",
-                "sha256:52f0907287d9104112dbebda46af4db0793fcc4c64c8a867099212d116b6db64",
-                "sha256:53e2986a65eba7c399d7ad1ccd204562d4ffe6e937344fe5a49eb5a83858f797",
-                "sha256:5660e470edfa15ae7ef407272c642d29e9962777a6b30bfa8fc0da2173dc9afd",
-                "sha256:57e932ad1908b53e9ad67a746432f02bc8473a9ee16e26a47645a2b224fba5fd",
-                "sha256:589f24449fd58508533c4a69b2a0f45e9e3419b86b43a0607e2fdb989c6f2552",
-                "sha256:5c2e24ba455af4b0a237a890ea6ed9bafd01fac2c47095f87c53ea3344215d43",
-                "sha256:5ebea3ebb6a394f50f150a52e279508e91c8770625ac8fcb5d8cf35995a320f2",
-                "sha256:67c30d3fe245adb0eb1061a0e526905970a0dabe7c5fba5078e0ee9d19f28167",
-                "sha256:6bb82447ddae4e3d9b51f40c494f66e6cbd8fb0e8e8b993678416535c67f9a0d",
-                "sha256:6ce4cff3922707048d754e365c4ebf41a3bcbf29b329349bf85d51873c7c7e9e",
-                "sha256:6d44b14f3a2f6343a07c90344850b7af5515538ce3a5d01f9c87d8bae9bd8724",
-                "sha256:6fd88935b12b59a933ef45facb57575095f205d30d0ae8dd1a3b485bc4fa2fbd",
-                "sha256:78da796b74f2c8e0af021ee99feb3bff7cb46f8e658fe25c20e66be1080db4a2",
-                "sha256:7966f98fa36933333d8a1c3d8552aa3d0735001901a4aabcfbd5a502b4ef14fe",
-                "sha256:7eca3a1afa9820785b79cb137c68ca38c2f77cfedc3120115da42e1d5800907e",
-                "sha256:823a262d967cbdf835787039b873ff551e36c14658bdc2e43267968b67f61f88",
-                "sha256:88623fd957ba500d8bb0f7427a76496d99313ca2f9e932481c0882e034cf1add",
-                "sha256:889587664d245dae75c752b643061f922e8a590d43a4cd088eca415ca83f2d13",
-                "sha256:9176057c60438c2ce2284cdefc2b3ee5eddc8c87cd6e24c558d9f5c64298fa4a",
-                "sha256:93018dbb956e0ad99ea2fa2c3c22f033549dcb1f56ad9f4555dfe25e49688c5d",
-                "sha256:97eaff096fcb467e0f486f3bf354c1072245c2045859d71ba71158717ec97dcc",
-                "sha256:997e8f9b984e4263993d3baf3329367e7c7673b63789bc761718a6f9ed68653d",
-                "sha256:99e544e6ce26f89ad5acc6f407bc4daf7c1d42321e836f5c768f834100bdf35c",
-                "sha256:9e04f3bd30e0b23c0ca7e1d4084e7d28b6d7d2feb8b7bc69b496fe881280579b",
-                "sha256:a7aa07603d67007c15b33d20095cc9276f3e127bfb1b8106b3e84ec6907d137e",
-                "sha256:a992f9e019145e84616048556546edeaba68e05e1c1ffbe8391067a63cdadb0c",
-                "sha256:b1a4c8edd038fee0ce67bf119b16eaa45d22a52bbaf7d0a17d2312eb0003b1bb",
-                "sha256:b8bd35c15bc82c5cbe397e8196fa57a17ce5d3f30e925a6fd39e4c5bb02fdcff",
-                "sha256:b9a58a1cbdc0588ed4c8ab0c191002d5d831a58c3bad88523fe471ea97eaf57d",
-                "sha256:bac64f57a5a7926ebc9ab519fb9eba1fc6dcd1f65d7f45937b2ce38da65c2270",
-                "sha256:bca1c0824f824bcd97b4b179dd55dcad1dab419252be2b2faebbcacefa3b27b2",
-                "sha256:bdf7b0e3d3713331c0bb9daac47cd10e5aa60d060e53696f50de4e560bd5617f",
-                "sha256:c53ef8936c4d587cb96bb1cf0d076e822fa38266c2b646837ef60465da8db22e",
-                "sha256:cbead724daa13cae46e8ab3bb24938d8514d123f34345535b184f3eb1b7ad717",
-                "sha256:cd7649f0c493d35f9aad9790bbecd7b6fd2e2f7141f6cb1e1e9bb7a681d6d0a4",
-                "sha256:d609f0ab0603bbcbf2de906b366b9f9bec75c32b4493550a940de658cc2ce512",
-                "sha256:d792631942a102d6d4f71e4948aceb307310ac0a0af054be6d28b4f79583e0f1",
-                "sha256:d87334b521ab0e2564902c0b10039dee8670485e9d397fe97c34b88801f474f7",
-                "sha256:da0d0c1c4bd55f9ace919454776dbf0821f537b9a77f739f0c3e34b14728b3b3",
-                "sha256:e0f0e731e0ca1583befd3af71b9f90d64ded1535da7b80181cb9e907cc10bbae",
-                "sha256:e5bd9186d52cf3d36bf1823be0e85297e4dbad909bc6dd495ce0d272806d84a7",
-                "sha256:e72053cc4706dac537d5a772135dc3e1de5aff52883f49994c1757c1b2dc9db2",
-                "sha256:e8a7b0699a381226d81d75b48ea58414beb5891ba8982bdc8e42912f766de074",
-                "sha256:ec3e763e7ca8dcba0792fc3e8ff7061186f59e9aafe4438e6bb1f635a6ab0901",
-                "sha256:f17e8d926f63aed65ff949682c922f96d00f65c2e852c24272232313fa7823d5",
-                "sha256:f3117feb1fc479eaf84b549d3f229d5d2abdb823f003bc2a1c6dd70072912fa0"
+                "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f",
+                "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c",
+                "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a",
+                "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b",
+                "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555",
+                "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c",
+                "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b",
+                "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6",
+                "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8",
+                "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662",
+                "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061",
+                "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998",
+                "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb",
+                "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62",
+                "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984",
+                "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392",
+                "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2",
+                "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306",
+                "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7",
+                "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3",
+                "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9",
+                "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6",
+                "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192",
+                "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317",
+                "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f",
+                "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda",
+                "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563",
+                "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a",
+                "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f",
+                "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d",
+                "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9",
+                "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8",
+                "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82",
+                "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9",
+                "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845",
+                "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82",
+                "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125",
+                "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504",
+                "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b",
+                "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7",
+                "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc",
+                "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6",
+                "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40",
+                "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a",
+                "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3",
+                "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a",
+                "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72",
+                "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681",
+                "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438",
+                "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae",
+                "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2",
+                "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb",
+                "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5",
+                "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a",
+                "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3",
+                "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8",
+                "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2",
+                "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22",
+                "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72",
+                "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061",
+                "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f",
+                "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9",
+                "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04",
+                "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98",
+                "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9",
+                "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f",
+                "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b",
+                "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925",
+                "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6",
+                "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0",
+                "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9",
+                "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c",
+                "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991",
+                "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6",
+                "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000",
+                "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb",
+                "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119",
+                "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b",
+                "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==1.17.1"
+            "version": "==1.17.2"
         }
     }
 }
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.0.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.0.tar.gz
deleted file mode 100644
index 80c2ba74f662e7b02895122a37e301fde2157b82..0000000000000000000000000000000000000000
Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.0.tar.gz and /dev/null differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz
deleted file mode 100644
index 7914db1bb84dddf85611cda3b766c0c0cdc094c7..0000000000000000000000000000000000000000
Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz and /dev/null differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..256d325e8bdbdacd8c967d852c98e39d8d3b9eb9
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ad4d6f9c5590836360d1a919f4be84b5cc5f9ade
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json
index b48be9a6bdc607bbfe2f7190b3733238f31f29b8..1c703b83750c5aa21d4da06c7895d74211122ae9 100644
--- a/dbrepo-auth-service/dbrepo-realm.json
+++ b/dbrepo-auth-service/dbrepo-realm.json
@@ -27,7 +27,7 @@
   "oauth2DevicePollingInterval" : 5,
   "enabled" : true,
   "sslRequired" : "none",
-  "registrationAllowed" : false,
+  "registrationAllowed" : true,
   "registrationEmailAsUsername" : false,
   "rememberMe" : false,
   "verifyEmail" : true,
@@ -38,6 +38,7 @@
   "bruteForceProtected" : false,
   "permanentLockout" : false,
   "maxTemporaryLockouts" : 0,
+  "bruteForceStrategy" : "MULTIPLE",
   "maxFailureWaitSeconds" : 900,
   "minimumQuickLoginWaitSeconds" : 60,
   "waitIncrementSeconds" : 60,
@@ -1308,8 +1309,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
-      "client.use.lightweight.access.token.enabled" : "true"
+      "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
     "fullScopeAllowed" : true,
@@ -1383,6 +1384,38 @@
     "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : -1,
     "protocolMappers" : [ {
+      "id" : "266edf62-a19a-483b-b594-81428e4af792",
+      "name" : "orcid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "ORCID",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "orcid",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "1a21798a-38b6-4df5-89f0-86942415246f",
+      "name" : "theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "THEME",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "theme",
+        "jsonType.label" : "String"
+      }
+    }, {
       "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
       "name" : "preferred_username",
       "protocol" : "openid-connect",
@@ -1396,18 +1429,66 @@
         "userinfo.token.claim" : "true"
       }
     }, {
-      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
-      "name" : "aud",
+      "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a",
+      "name" : "affiliation",
       "protocol" : "openid-connect",
-      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "dbrepo",
+        "introspection.token.claim" : "true",
         "userinfo.token.claim" : "true",
+        "user.attribute" : "AFFILIATION",
         "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
-        "claim.name" : "aud",
-        "access.tokenResponse.claim" : "false"
+        "claim.name" : "affiliation",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88",
+      "name" : "language",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "LANGUAGE",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "language",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
       }
     }, {
       "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
@@ -1424,9 +1505,26 @@
         "access.token.claim" : "true",
         "claim.name" : "uid"
       }
+    }, {
+      "id" : "c304ed2f-5952-4772-838d-91998a45f154",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "claim.value" : "account",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "jsonType.label" : "String",
+        "access.tokenResponse.claim" : "false"
+      }
     } ],
-    "defaultClientScopes" : [ "roles", "attributes", "basic" ],
-    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+    "defaultClientScopes" : [ "roles", "basic" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
     "clientId" : "rabbitmq-client",
@@ -1471,12 +1569,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "false",
         "user.attribute" : "username",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "client_id",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "false"
       }
     }, {
       "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
@@ -1485,11 +1583,11 @@
       "protocolMapper" : "oidc-hardcoded-claim-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "rabbitmq",
-        "userinfo.token.claim" : "false",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "aud",
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
         "access.tokenResponse.claim" : "false"
       }
     } ],
@@ -1548,8 +1646,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
       "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -1562,12 +1660,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ],
     "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
@@ -1591,8 +1689,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${emailScopeConsentText}"
+      "consent.screen.text" : "${emailScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
@@ -1601,12 +1699,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "emailVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
@@ -1615,12 +1713,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "email",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1630,8 +1728,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${profileScopeConsentText}"
+      "consent.screen.text" : "${profileScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
@@ -1640,12 +1738,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "preferred_username",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
@@ -1654,12 +1752,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "gender",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "gender",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
@@ -1668,12 +1766,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "birthdate",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "birthdate",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
@@ -1693,12 +1791,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "profile",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "profile",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
@@ -1707,12 +1805,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "updatedAt",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "updated_at",
-        "jsonType.label" : "long"
+        "jsonType.label" : "long",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "841ea785-26ab-429a-a420-09ce3948924d",
@@ -1721,12 +1819,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "lastName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "family_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
@@ -1735,12 +1833,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "website",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "website",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "475f071d-5149-4379-b928-76482f5f519c",
@@ -1749,12 +1847,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "zoneinfo",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "zoneinfo",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
@@ -1763,12 +1861,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "middleName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "middle_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
@@ -1777,12 +1875,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "picture",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "picture",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
@@ -1791,12 +1889,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
@@ -1805,12 +1903,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "firstName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "given_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
@@ -1819,12 +1917,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "nickname",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "nickname",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1858,12 +1956,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "upn",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1905,8 +2003,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${phoneScopeConsentText}"
+      "consent.screen.text" : "${phoneScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
@@ -1915,12 +2013,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumber",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
@@ -1929,12 +2027,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumberVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1944,8 +2042,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "false",
-      "consent.screen.text" : ""
+      "consent.screen.text" : "",
+      "display.on.consent.screen" : "false"
     },
     "protocolMappers" : [ {
       "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
@@ -2025,6 +2123,61 @@
       "gui.order" : "",
       "consent.screen.text" : ""
     }
+  }, {
+    "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6",
+    "name" : "service_account",
+    "description" : "Specific scope for a client enabled for service accounts",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512",
+      "name" : "Client IP Address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientAddress",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientAddress",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a",
+      "name" : "Client Host",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientHost",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientHost",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae",
+      "name" : "Client ID",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "client_id",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    } ]
   }, {
     "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
     "name" : "offline_access",
@@ -2041,8 +2194,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${addressScopeConsentText}"
+      "consent.screen.text" : "${addressScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
@@ -2115,8 +2268,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${rolesScopeConsentText}"
+      "consent.screen.text" : "${rolesScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
@@ -2132,11 +2285,15 @@
       "protocolMapper" : "oidc-usermodel-realm-role-mapper",
       "consentRequired" : false,
       "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "false",
+        "multivalued" : "true",
         "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "realm_access.roles",
-        "jsonType.label" : "String",
-        "multivalued" : "true"
+        "jsonType.label" : "String"
       }
     }, {
       "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
@@ -2166,8 +2323,12 @@
     "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
   },
   "smtpServer" : { },
+  "loginTheme" : "keycloak.v2",
+  "accountTheme" : "",
+  "adminTheme" : "",
+  "emailTheme" : "",
   "eventsEnabled" : false,
-  "eventsListeners" : [ "jboss-logging" ],
+  "eventsListeners" : [ "create-event-listener", "jboss-logging" ],
   "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
   "adminEventsEnabled" : false,
   "adminEventsDetailsEnabled" : false,
@@ -2215,7 +2376,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2241,7 +2402,15 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+      }
+    } ],
+    "org.keycloak.userprofile.UserProfileProvider" : [ {
+      "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
+      "providerId" : "declarative-user-profile",
+      "subComponents" : { },
+      "config" : {
+        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
       }
     } ],
     "org.keycloak.storage.UserStorageProvider" : [ {
@@ -2257,8 +2426,8 @@
           "config" : {
             "ldap.attribute" : [ "createTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "read.only" : [ "true" ],
             "always.read.value.from.ldap" : [ "true" ],
+            "read.only" : [ "true" ],
             "user.model.attribute" : [ "createTimestamp" ]
           }
         }, {
@@ -2269,8 +2438,8 @@
           "config" : {
             "ldap.attribute" : [ "sn" ],
             "is.mandatory.in.ldap" : [ "true" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "false" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "lastName" ]
           }
         }, {
@@ -2293,8 +2462,8 @@
           "config" : {
             "ldap.attribute" : [ "mail" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "false" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "email" ]
           }
         }, {
@@ -2303,19 +2472,19 @@
           "providerId" : "group-ldap-mapper",
           "subComponents" : { },
           "config" : {
+            "mode" : [ "LDAP_ONLY" ],
             "membership.attribute.type" : [ "DN" ],
+            "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
             "group.name.ldap.attribute" : [ "cn" ],
-            "preserve.group.inheritance" : [ "false" ],
             "membership.user.ldap.attribute" : [ "uid" ],
-            "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" ],
+            "preserve.group.inheritance" : [ "false" ],
+            "membership.ldap.attribute" : [ "member" ],
             "memberof.ldap.attribute" : [ "memberOf" ],
             "group.object.classes" : [ "groupOfNames" ],
-            "drop.non.existing.groups.during.sync" : [ "false" ],
-            "groups.path" : [ "/" ]
+            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
+            "groups.path" : [ "/" ],
+            "drop.non.existing.groups.during.sync" : [ "false" ]
           }
         }, {
           "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb",
@@ -2339,15 +2508,15 @@
             "is.mandatory.in.ldap" : [ "true" ],
             "attribute.force.default" : [ "false" ],
             "is.binary.attribute" : [ "false" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "false" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "username" ]
           }
         } ]
       },
       "config" : {
-        "pagination" : [ "false" ],
         "fullSyncPeriod" : [ "-1" ],
+        "pagination" : [ "false" ],
         "startTls" : [ "false" ],
         "connectionPooling" : [ "true" ],
         "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ],
@@ -2355,15 +2524,15 @@
         "useKerberosForPasswordAuthentication" : [ "false" ],
         "importEnabled" : [ "true" ],
         "enabled" : [ "true" ],
+        "bindCredential" : [ "admin" ],
         "changedSyncPeriod" : [ "-1" ],
-        "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
         "usernameLDAPAttribute" : [ "uid" ],
-        "bindCredential" : [ "admin" ],
+        "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
         "lastSync" : [ "1719252666" ],
         "vendor" : [ "other" ],
         "uuidLDAPAttribute" : [ "entryUUID" ],
-        "connectionUrl" : [ "ldap://identity-service:1389" ],
         "allowKerberosAuthentication" : [ "false" ],
+        "connectionUrl" : [ "ldap://identity-service:1389" ],
         "syncRegistrations" : [ "true" ],
         "authType" : [ "simple" ],
         "useTruststoreSpi" : [ "always" ],
@@ -2375,14 +2544,6 @@
         "validatePasswordPolicy" : [ "false" ]
       }
     } ],
-    "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
-      "providerId" : "declarative-user-profile",
-      "subComponents" : { },
-      "config" : {
-        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
-      }
-    } ],
     "org.keycloak.keys.KeyProvider" : [ {
       "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
       "name" : "rsa-enc-generated",
@@ -2995,10 +3156,12 @@
     "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
     "parRequestUriLifespan" : "60",
     "clientSessionMaxLifespan" : "0",
+    "organizationsEnabled" : "false",
     "shortVerificationUri" : ""
   },
-  "keycloakVersion" : "24.0.5",
+  "keycloakVersion" : "26.0.4",
   "userManagedAccessAllowed" : false,
+  "organizationsEnabled" : false,
   "clientProfiles" : {
     "profiles" : [ ]
   },
diff --git a/dbrepo-auth-service/init/Pipfile.lock b/dbrepo-auth-service/init/Pipfile.lock
index c8224a7844942ed36a6fef30185dc094f516378d..57631a05559948613a5c9a63b37463c95a48da9a 100644
--- a/dbrepo-auth-service/init/Pipfile.lock
+++ b/dbrepo-auth-service/init/Pipfile.lock
@@ -18,11 +18,11 @@
     "default": {
         "certifi": {
             "hashes": [
-                "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
-                "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
+                "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
+                "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.12.14"
+            "version": "==2025.1.31"
         },
         "charset-normalizer": {
             "hashes": [
@@ -175,11 +175,11 @@
     "develop": {
         "certifi": {
             "hashes": [
-                "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
-                "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
+                "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
+                "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.12.14"
+            "version": "==2025.1.31"
         },
         "charset-normalizer": {
             "hashes": [
diff --git a/dbrepo-auth-service/init/app.py b/dbrepo-auth-service/init/app.py
index 270e959fecb30c9f200ba96c8186357cb94599b9..5e42003a192d4b6536ccd8f6c6ccc1be9dcedd6d 100644
--- a/dbrepo-auth-service/init/app.py
+++ b/dbrepo-auth-service/init/app.py
@@ -7,7 +7,7 @@ endpoint = os.getenv('AUTH_SERVICE_ENDPOINT', 'http://localhost:8080')
 system_username = os.getenv('SYSTEM_USERNAME', 'admin')
 
 
-def fetch() -> str:
+def fetch() -> (str, str):
     print(f'Fetching user id of internal user with username: {system_username}')
     response = post(url=f'{endpoint}/realms/master/protocol/openid-connect/token', data=dict({
         'username': os.getenv('AUTH_SERVICE_ADMIN', 'admin'),
@@ -25,7 +25,8 @@ def fetch() -> str:
     if response.status_code != 200 or len(response.json()) != 1:
         raise FileNotFoundError(f'Failed to obtain user')
     ldap_user = response.json()[0]
-    print(f'Successfully fetched user id: {ldap_user["id"]}')
+    user_id = ldap_user["id"]
+    print(f'Successfully fetched user id: {user_id}')
     if 'attributes' not in ldap_user or ldap_user['attributes'] is None:
         raise ModuleNotFoundError(f'Failed to obtain user attributes: {ldap_user}')
     ldap_user_attrs = ldap_user['attributes']
@@ -35,10 +36,10 @@ def fetch() -> str:
         raise EnvironmentError(f'Failed to obtain ldap id: wrong length {len(ldap_user_attrs["LDAP_ID"])} != 1')
     ldap_user_id = ldap_user_attrs['LDAP_ID'][0]
     print(f'Successfully fetched ldap user id: {ldap_user_id}')
-    return ldap_user_id
+    return (ldap_user_id, user_id)
 
 
-def save(user_id: str) -> None:
+def save(user_id: str, keycloak_id: str) -> None:
     conn = mariadb.connect(user=os.getenv('METADATA_USERNAME', 'root'),
                            password=os.getenv('METADATA_DB_PASSWORD', 'dbrepo'),
                            host="metadata-db",
@@ -46,12 +47,13 @@ def save(user_id: str) -> None:
                            database=os.getenv('METADATA_DB', 'dbrepo'))
     cursor = conn.cursor()
     cursor.execute(
-        "INSERT IGNORE INTO `mdb_users` (`id`, `username`, `email`, `mariadb_password`, `is_internal`) VALUES (?, ?, LEFT(UUID(), 20), PASSWORD(LEFT(UUID(), 20)), true)",
-        (user_id, system_username))
+        "INSERT IGNORE INTO `mdb_users` (`id`, `keycloak_id`, `username`, `mariadb_password`, `is_internal`) VALUES (?, ?, ?, PASSWORD(LEFT(UUID(), 20)), true)",
+        (user_id, keycloak_id, system_username))
     conn.commit()
     conn.close()
 
 
 if __name__ == '__main__':
-    save(fetch())
+    user_id, keycloak_id = fetch()
+    save(user_id, keycloak_id)
     print(f'Successfully inserted user')
diff --git a/dbrepo-auth-service/init/test/test_unit_app.py b/dbrepo-auth-service/init/test/test_unit_app.py
index 624b7d8d53e7393d2077c214278bdb98f32297ba..af6aed379a3780157718d760bdabd79475e8d249 100644
--- a/dbrepo-auth-service/init/test/test_unit_app.py
+++ b/dbrepo-auth-service/init/test/test_unit_app.py
@@ -16,38 +16,6 @@ class AppUnitTest(unittest.TestCase):
         "session_state": "ae64d2bd-3225-4e05-9943-2bb91fb8fe52",
         "scope": "profile email"
     }
-    user_res = [
-        {"id": "5b516520-67cb-4aa0-86a6-d12f8b8f1a20",
-         "username": "admin",
-         "firstName": "User1",
-         "lastName": "Bar1",
-         "emailVerified": False,
-         "attributes": {"LDAP_ENTRY_DN": ["cn=admin,ou=users,dc=dbrepo,dc=at"],
-                        "createTimestamp": ["20250120141013Z"],
-                        "modifyTimestamp": ["20250120141013Z"],
-                        "LDAP_ID": ["02b6e096-6b84-103f-81f6-1f6da137f2bb"]},
-         "createdTimestamp": 1737382606939,
-         "enabled": True,
-         "totp": False,
-         "federationLink": "c109d473-5ce1-4032-af7b-02e5442f5c07",
-         "disableableCredentialTypes": [],
-         "requiredActions": [],
-         "notBefore": 0,
-         "access": {"manageGroupMembership": True,
-                    "view": True,
-                    "mapRoles": True,
-                    "impersonate": True,
-                    "manage": True}}]
-
-    def test_fetch_succeeds(self):
-        with requests_mock.Mocker() as mock:
-            # mock
-            mock.post(f'{endpoint}/realms/master/protocol/openid-connect/token', json=self.token_res, status_code=200)
-            mock.get(f'{endpoint}/admin/realms/dbrepo/users/?username=admin', json=self.user_res, status_code=200)
-
-            # test
-            user_id = fetch()
-            self.assertEqual("02b6e096-6b84-103f-81f6-1f6da137f2bb", user_id)
 
     def test_fetch_token_bad_request_fails(self):
         with requests_mock.Mocker() as mock:
diff --git a/dbrepo-auth-service/listeners/.gitignore b/dbrepo-auth-service/listeners/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..5d6e1ae3b181727bbd28cdb0107283899c3a0fd2
--- /dev/null
+++ b/dbrepo-auth-service/listeners/.gitignore
@@ -0,0 +1,30 @@
+### IntelliJ IDEA ###
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+target/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/pom.xml b/dbrepo-auth-service/listeners/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e70201b96ac3d853a0274c7f06499d336f1c27cf
--- /dev/null
+++ b/dbrepo-auth-service/listeners/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-parent</artifactId>
+        <version>24.0.5</version>
+    </parent>
+
+    <groupId>at.tuwien</groupId>
+    <artifactId>create-event-listener</artifactId>
+    <name>dbrepo-auth-service</name>
+    <version>24.0.5</version>
+
+    <description>Create event listener</description>
+
+    <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url>
+    <developers>
+        <developer>
+            <name>Martin Weise</name>
+            <email>martin.weise@tuwien.ac.at</email>
+            <organization>TU Wien</organization>
+        </developer>
+    </developers>
+
+    <properties>
+        <java.version>17</java.version>
+        <maven.version>3.9.8</maven.version>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <maven.compiler.release>${java.version}</maven.compiler.release>
+        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
+        <testcontainers.version>1.19.1</testcontainers.version>
+        <keycloak-testcontainer.version>3.2.0</keycloak-testcontainer.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-saml-core-public</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ws.rs</groupId>
+            <artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
+        </dependency>
+        <!-- Tests -->
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${testcontainers.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.dasniko</groupId>
+            <artifactId>testcontainers-keycloak</artifactId>
+            <version>${keycloak-testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>create-event-listener</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java
new file mode 100644
index 0000000000000000000000000000000000000000..769ec49097223e5fd49f76d855d9acef1cfbe35c
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java
@@ -0,0 +1,65 @@
+package at.tuwien;
+
+import org.jboss.logging.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Base64;
+
+public class Client {
+    private static final Logger log = Logger.getLogger(Client.class);
+
+    public static void postService(String data) throws IOException {
+        try {
+            final String urlString = System.getenv("METADATA_SERVICE_ENDPOINT");
+            log.debugf("METADATA_SERVICE_ENDPOINT: %s", urlString);
+            if (urlString == null || urlString.isEmpty()) {
+                throw new IllegalArgumentException("Environment variable METADATA_SERVICE_ENDPOINT is not set or is empty.");
+            }
+            final String systemUsername = System.getenv("SYSTEM_USERNAME");
+            if (systemUsername == null || systemUsername.isEmpty()) {
+                throw new IllegalArgumentException("Environment variable SYSTEM_USERNAME is not set or is empty.");
+            }
+            log.debugf("SYSTEM_USERNAME: %s", systemUsername);
+            final String systemPassword = System.getenv("SYSTEM_PASSWORD");
+            if (systemPassword == null || systemPassword.isEmpty()) {
+                throw new IllegalArgumentException("Environment variable SYSTEM_PASSWORD is not set or is empty.");
+            }
+
+            URL url = URI.create(urlString).toURL();
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setDoOutput(true);
+            conn.setRequestMethod("POST");
+            final String token = systemUsername + ":" + systemPassword;
+            conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(token.getBytes(
+                    Charset.defaultCharset())));
+            conn.setRequestProperty("Content-Type", "application/json; utf-8");
+
+            OutputStream os = conn.getOutputStream();
+            os.write(data.getBytes());
+            os.flush();
+
+            final int responseCode = conn.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_CREATED && responseCode != HttpURLConnection.HTTP_OK) {
+                throw new RuntimeException("Failed : HTTP error code : " + responseCode);
+            }
+
+            final BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+            String output;
+            log.debugf("Output from Server .... \n");
+            while ((output = br.readLine()) != null) {
+                System.out.println(output);
+                log.debugf("Input from Server: %s", output);
+            }
+            conn.disconnect();
+        } catch (IOException e) {
+            throw new IOException("Failed to post service: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b5d9221a7beb49385e129f6ccb3fff0aed73002
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java
@@ -0,0 +1,139 @@
+package at.tuwien;
+
+import org.jboss.logging.Logger;
+import org.keycloak.events.Event;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventType;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.UserModel;
+
+import java.util.StringJoiner;
+
+public class CreateEventListenerProvider implements EventListenerProvider {
+
+    private static final Logger log = Logger.getLogger(CreateEventListenerProvider.class);
+
+    private final KeycloakSession session;
+    private final RealmProvider model;
+
+    public CreateEventListenerProvider(KeycloakSession session) {
+        this.session = session;
+        this.model = session.realms();
+    }
+
+    @Override
+    public void onEvent(Event event) {
+
+        log.debugf("New %s Event", event.getType());
+        log.debugf("onEvent-> %s", toString(event));
+
+        if (EventType.REGISTER.equals(event.getType())) {
+
+            event.getDetails().forEach((key, value) -> log.debugf("%s : %s", key, value));
+
+            RealmModel realm = this.model.getRealm(event.getRealmId());
+            UserModel user = this.session.users().getUserById(realm, event.getUserId());
+            sendUserData(user);
+        }
+
+    }
+
+    @Override
+    public void onEvent(AdminEvent adminEvent, boolean b) {
+        log.debug("onEvent(AdminEvent)");
+        log.debugf("Resource path: %s", adminEvent.getResourcePath());
+        log.debugf("Resource type: %s", adminEvent.getResourceType());
+        log.debugf("Operation type: %s", adminEvent.getOperationType());
+        log.debugf("AdminEvent.toString(): %s", toString(adminEvent));
+        if (ResourceType.USER.equals(adminEvent.getResourceType())
+                && OperationType.CREATE.equals(adminEvent.getOperationType())) {
+            RealmModel realm = this.model.getRealm(adminEvent.getRealmId());
+            UserModel user = this.session.users().getUserById(realm, adminEvent.getResourcePath().substring(6));
+
+            sendUserData(user);
+        }
+    }
+
+    private void sendUserData(UserModel user) {
+        final String userData = "{" +
+                quoteAttr("id", user.getId()) + ", " +
+                quoteAttr("username", user.getUsername()) + ", " +
+                quoteAttr("email", user.getEmail()) + ", " +
+                quoteAttr("ldap_id", user.getFirstAttribute("LDAP_ID")) + ", " +
+                quoteAttr("given_name", user.getFirstName()) + ", " +
+                quoteAttr("family_name", user.getLastName()) +
+                "}";
+        try {
+            log.debugf("create new user in API: %s", userData);
+            Client.postService(userData);
+        } catch (Exception e) {
+            log.errorf("Failed to call API: %s", e);
+        }
+    }
+
+    private static String quoteAttr(String key, String value) {
+        if (value == null || value.isBlank() || value.isEmpty() || value.contentEquals(" ")) {
+            return "\"" + key + "\": null";
+        }
+        return "\"" + key + "\": \"" + value + "\"";
+    }
+
+    @Override
+    public void close() {
+    }
+
+    private String toString(Event event) {
+        final StringJoiner joiner = new StringJoiner(", ");
+        joiner.add("type=" + event.getType())
+                .add("realmId=" + event.getRealmId())
+                .add("clientId=" + event.getClientId())
+                .add("userId=" + event.getUserId())
+                .add("ipAddress=" + event.getIpAddress());
+        if (event.getError() != null) {
+            joiner.add("error=" + event.getError());
+        }
+        if (event.getDetails() != null) {
+            event.getDetails().forEach((key, value) -> {
+                if (value == null || !value.contains(" ")) {
+                    joiner.add(key + "=" + value);
+                } else {
+                    joiner.add(key + "='" + value + "'");
+                }
+            });
+        }
+        return joiner.toString();
+    }
+
+    private String toString(AdminEvent event) {
+        RealmModel realm = this.model.getRealm(event.getRealmId());
+        UserModel newRegisteredUser = this.session.users().getUserById(realm, event.getAuthDetails().getUserId());
+
+        StringJoiner joiner = new StringJoiner(", ");
+
+        joiner.add("operationType=" + event.getOperationType())
+                .add("realmId=" + event.getAuthDetails().getRealmId())
+                .add("clientId=" + event.getAuthDetails().getClientId())
+                .add("userId=" + event.getAuthDetails().getUserId());
+
+        if (newRegisteredUser != null) {
+            joiner.add("email=" + newRegisteredUser.getEmail())
+                    .add("username=" + newRegisteredUser.getUsername())
+                    .add("firstName=" + newRegisteredUser.getFirstName())
+                    .add("lastName=" + newRegisteredUser.getLastName());
+        }
+
+        joiner.add("ipAddress=" + event.getAuthDetails().getIpAddress())
+                .add("resourcePath=" + event.getResourcePath());
+
+        if (event.getError() != null) {
+            joiner.add("error=" + event.getError());
+        }
+
+        return joiner.toString();
+    }
+}
diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..61477ffa33169504a3368d11d0750c9c1404e160
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java
@@ -0,0 +1,36 @@
+package at.tuwien;
+
+import org.keycloak.Config;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventListenerProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+public class CreateEventListenerProviderFactory implements EventListenerProviderFactory {
+
+    @Override
+    public EventListenerProvider create(KeycloakSession keycloakSession) {
+        return new CreateEventListenerProvider(keycloakSession);
+    }
+
+    @Override
+    public void init(Config.Scope scope) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory keycloakSessionFactory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "create-event-listener";
+    }
+
+}
diff --git a/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml  b/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml 
new file mode 100644
index 0000000000000000000000000000000000000000..c0330ba082479a3bd9d0caf86508b5067251ed84
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml 	
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-services" />
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory b/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
new file mode 100644
index 0000000000000000000000000000000000000000..df3c5521f0958fed5fadb4f006d8ee6eb50f97c2
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
@@ -0,0 +1 @@
+at.tuwien.CreateEventListenerProviderFactory
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java b/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3d6ee94ccd764d16d589b33b51d501e2a2a3d82
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java
@@ -0,0 +1,18 @@
+package at.tuwien;
+
+import dasniko.testcontainers.keycloak.KeycloakContainer;
+import org.testcontainers.images.PullPolicy;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class EventListenerIntegrationTest {
+
+    @Container
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0")
+            .withImagePullPolicy(PullPolicy.alwaysPull())
+            .withAdminUsername("admin")
+            .withAdminPassword("admin")
+            .withRealmImportFile("dbrepo-realm.json")
+            .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false");
+}
diff --git a/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json b/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json
new file mode 100644
index 0000000000000000000000000000000000000000..56f2003e961a14d09bcd56832437f915cae04dea
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json
@@ -0,0 +1,2798 @@
+{
+  "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+  "realm" : "dbrepo",
+  "notBefore" : 0,
+  "defaultSignatureAlgorithm" : "RS256",
+  "revokeRefreshToken" : false,
+  "refreshTokenMaxReuse" : 1,
+  "accessTokenLifespan" : 900,
+  "accessTokenLifespanForImplicitFlow" : 900,
+  "ssoSessionIdleTimeout" : 864000,
+  "ssoSessionMaxLifespan" : 2592000,
+  "ssoSessionIdleTimeoutRememberMe" : 0,
+  "ssoSessionMaxLifespanRememberMe" : 0,
+  "offlineSessionIdleTimeout" : 2592000,
+  "offlineSessionMaxLifespanEnabled" : false,
+  "offlineSessionMaxLifespan" : 5184000,
+  "clientSessionIdleTimeout" : 0,
+  "clientSessionMaxLifespan" : 0,
+  "clientOfflineSessionIdleTimeout" : 0,
+  "clientOfflineSessionMaxLifespan" : 0,
+  "accessCodeLifespan" : 60,
+  "accessCodeLifespanUserAction" : 300,
+  "accessCodeLifespanLogin" : 1800,
+  "actionTokenGeneratedByAdminLifespan" : 43200,
+  "actionTokenGeneratedByUserLifespan" : 1800,
+  "oauth2DeviceCodeLifespan" : 600,
+  "oauth2DevicePollingInterval" : 5,
+  "enabled" : true,
+  "sslRequired" : "none",
+  "registrationAllowed" : false,
+  "registrationEmailAsUsername" : false,
+  "rememberMe" : false,
+  "verifyEmail" : true,
+  "loginWithEmailAllowed" : false,
+  "duplicateEmailsAllowed" : false,
+  "resetPasswordAllowed" : false,
+  "editUsernameAllowed" : false,
+  "bruteForceProtected" : false,
+  "permanentLockout" : false,
+  "maxTemporaryLockouts" : 0,
+  "maxFailureWaitSeconds" : 900,
+  "minimumQuickLoginWaitSeconds" : 60,
+  "waitIncrementSeconds" : 60,
+  "quickLoginCheckMilliSeconds" : 1000,
+  "maxDeltaTimeSeconds" : 43200,
+  "failureFactor" : 30,
+  "roles" : {
+    "realm" : [ {
+      "id" : "48f38342-1e3f-427a-995d-c436eaee65cb",
+      "name" : "default-user-handling",
+      "description" : "${default-user-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-user-theme", "modify-user-information" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "9bb4a8dc-28e0-4645-b62f-cc94425f0cb0",
+      "name" : "default-maintenance-handling",
+      "description" : "${default-maintenance-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-maintenance-message", "find-maintenance-message", "update-maintenance-message", "delete-maintenance-message", "list-maintenance-messages" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7ee1c424-11b0-46a9-b0ed-725e9b7fc40c",
+      "name" : "default-system-roles",
+      "description" : "${default-system-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "143ba359-5fa2-451e-8296-43ecf20bb251",
+      "name" : "update-semantic-concept",
+      "description" : "${update-semantic-concept}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "5136d7a3-e3f0-4585-bacd-15cb8a56095c",
+      "name" : "escalated-container-handling",
+      "description" : "${escalated-container-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-container", "delete-container" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b0bc8649-7d84-4dd3-84f0-7f174425babe",
+      "name" : "list-tables",
+      "description" : "${list-tables}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "bfd85d9c-2772-4660-a8f0-cdc0cd8252b3",
+      "name" : "default-database-handling",
+      "description" : "${default-database-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-database-image", "modify-database-owner", "update-database-access", "create-database", "list-databases", "create-database-access", "find-database", "modify-database-visibility", "import-database-data", "delete-database-access", "check-database-access" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "74648f9a-777e-4ef9-b97b-4c5d749d862f",
+      "name" : "update-search-index",
+      "description" : "${update-search-index}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "22492b64-c633-48a0-9678-b28669f2885b",
+      "name" : "execute-semantic-query",
+      "description" : "${execute-semantic-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "4ed919fa-edc5-44e5-9411-607786e4a86d",
+      "name" : "view-table-history",
+      "description" : "${view-table-history}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d89a2881-b642-4abb-b990-196e71372f6b",
+      "name" : "default-table-handling",
+      "description" : "${default-table-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3",
+      "name" : "view-database-view-data",
+      "description" : "${view-database-view-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44",
+      "name" : "create-database-view",
+      "description" : "${create-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a5ffc20e-8b11-498c-9f3b-b5740aec24c7",
+      "name" : "default-semantics-handling",
+      "description" : "${default-semantics-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-semantic-unit", "create-semantic-concept", "execute-semantic-query", "table-semantic-analyse" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe4a01f3-6590-4df6-9ade-5a9c1fae4736",
+      "name" : "create-semantic-unit",
+      "description" : "${create-semantic-unit}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "0e12eedf-545d-4d32-ac4d-2821dcb118b8",
+      "name" : "update-table-statistic",
+      "description" : "${update-table-statistic}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e63e61a2-d852-4ad3-bfb5-92d9ceafef6a",
+      "name" : "escalated-user-handling",
+      "description" : "${escalated-user-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "find-user" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be4e1aba-e276-4241-b6ea-01dce6c52f8b",
+      "name" : "find-container",
+      "description" : "${find-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3a801b48-f3c2-4bc6-aa25-c7a91d5b32a7",
+      "name" : "default-researcher-roles",
+      "description" : "${default-researcher-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3d8104fb-8307-40f0-b4b2-c3e518957110",
+      "name" : "view-table-data",
+      "description" : "${view-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe71b907-7020-44ab-9964-da2b87264582",
+      "name" : "create-database",
+      "description" : "${create-database}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e51b63c2-48dd-4bd6-95fb-d257d21b26ba",
+      "name" : "import-database-data",
+      "description" : "${import-database-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "1f0a9b13-c2b8-474c-bc08-59dbd71835a6",
+      "name" : "modify-database-image",
+      "description" : "${modify-database-image}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a7ad038c-5c06-42fc-951c-15ac09d4df66",
+      "name" : "modify-database-owner",
+      "description" : "${modify-database-owner}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6",
+      "name" : "create-ontology",
+      "description" : "${create-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b60a5694-4099-4f7d-a7e9-4c433e0eb9c9",
+      "name" : "update-semantic-unit",
+      "description" : "${update-semantic-unit}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e9854bbb-4580-4757-b1ae-305934173249",
+      "name" : "create-database-access",
+      "description" : "${create-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "50c604c1-7c6e-43f3-9c43-2398f5eff66e",
+      "name" : "list-databases",
+      "description" : "${list-databases}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b",
+      "name" : "create-container",
+      "description" : "${create-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f4116230-8642-4bb7-bbc8-db9c5c07b558",
+      "name" : "create-maintenance-message",
+      "description" : "${create-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "973f0999-cc70-4b28-9f43-979c470bea8e",
+      "name" : "default-data-steward-roles",
+      "description" : "${default-data-steward-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-identifier-handling", "default-semantics-handling", "escalated-semantics-handling", "default-user-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e1383fb7-d54c-4732-9146-93030eb2ca50",
+      "name" : "escalated-query-handling",
+      "description" : "${escalated-query-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "993b5c69-9eb2-42af-ac28-b4a46c6b61f2",
+      "name" : "find-user",
+      "description" : "${find-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e4cfdc4d-2373-477b-a8df-161db99aba00",
+      "name" : "create-foreign-identifier",
+      "description" : "${create-foreign-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6a5872a5-2b51-415d-ae2d-25a6db4a35df",
+      "name" : "escalated-semantics-handling",
+      "description" : "${escalated-semantics-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "update-semantic-unit", "create-ontology", "update-ontology", "list-ontologies", "delete-ontology", "modify-foreign-table-column-semantics", "update-semantic-concept" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "09147c48-273b-450b-8b11-7ef9b9245244",
+      "name" : "export-table-data",
+      "description" : "${export-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d14af590-60a8-4d75-b864-40ee0165bd7f",
+      "name" : "delete-database-access",
+      "description" : "${delete-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be051d45-cd74-4b13-8a45-f2d3351bd995",
+      "name" : "table-semantic-analyse",
+      "description" : "${table-semantic-analyse}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "272a79a7-e282-4261-8f7d-5d5d1364243a",
+      "name" : "update-maintenance-message",
+      "description" : "${update-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb",
+      "name" : "default-query-handling",
+      "description" : "${default-query-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c047d521-cec3-4444-86c4-aef098489b7b",
+      "name" : "delete-maintenance-message",
+      "description" : "${delete-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "88f82262-be80-4d18-9fb4-5529da031f33",
+      "name" : "system",
+      "description" : "${system}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e14ab76b-1c24-484d-ae2d-478b8457edea",
+      "name" : "list-licenses",
+      "description" : "${list-licenses}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d4f29937-3ca0-41e9-9786-2b7b921b6cdd",
+      "name" : "modify-foreign-table-column-semantics",
+      "description" : "${modify-foreign-table-column-semantics}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "8eda9f5c-938c-4915-bed5-6a81a1de15a8",
+      "name" : "list-database-views",
+      "description" : "${list-database-views}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b372f8f7-d203-4293-b991-ad93fb505917",
+      "name" : "escalated-database-handling",
+      "description" : "${escalated-database-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
+      "name" : "default-roles-dbrepo",
+      "description" : "${role_default-roles}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3293799a-82b9-4f47-8f25-1aad2e0222fd",
+      "name" : "find-identifier",
+      "description" : "${find-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "aaa3f804-38a0-4474-b8e9-f1020c4b3f62",
+      "name" : "list-queries",
+      "description" : "${list-queries}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "76e38f7b-99bf-4d12-8d74-1c7d8812f443",
+      "name" : "update-ontology",
+      "description" : "${update-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "11f7973e-d1eb-42cb-a35d-c59dfc122775",
+      "name" : "modify-user-theme",
+      "description" : "${modify-user-theme}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f392bfcb-0be5-4fad-9ce4-8ac6396f176d",
+      "name" : "export-query-data",
+      "description" : "${export-query-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "da493b7e-fb9b-43ca-82a5-e274ad2e6b39",
+      "name" : "find-query",
+      "description" : "${find-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a4d4a788-ebcf-4d32-baed-4a85616ca037",
+      "name" : "escalated-identifier-handling",
+      "description" : "${escalated-identifier-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-foreign-identifier", "modify-identifier-metadata" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "ea38d69d-17b8-4c65-95e8-1c3501b83618",
+      "name" : "default-container-handling",
+      "description" : "${default-container-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "find-container", "list-containers" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "8b8813e0-af07-4d04-a8c1-e3f37192bace",
+      "name" : "publish-identifier",
+      "description" : "${publish-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "47f5eee7-9821-4bf8-b434-0da1f81c3e5a",
+      "name" : "default-broker-handling",
+      "description" : "${default-broker-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "71874bde-64a5-4a69-8685-d8998303a80c",
+      "name" : "delete-table-data",
+      "description" : "${delete-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7c0306fc-3b03-4c64-87d1-9a34f2073977",
+      "name" : "modify-table-column-semantics",
+      "description" : "${modify-table-column-semantics}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "cd0ee04c-4a5e-4035-a11b-f6a1165f7829",
+      "name" : "delete-container",
+      "description" : "${delete-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "67ee39c0-d601-4a67-a0fe-c4f0021d557e",
+      "name" : "list-containers",
+      "description" : "${list-containers}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "795c7bb8-3502-414a-a97b-2ba1cfd6a79c",
+      "name" : "persist-query",
+      "description" : "${persist-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d05e7698-ddf5-4f20-9027-771afb2cc3c7",
+      "name" : "list-identifiers",
+      "description" : "${list-identifiers}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e4bfaf36-9a5d-43e0-9fa3-0f4ea7bad8d0",
+      "name" : "default-developer-roles",
+      "description" : "${default-developer-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-query-handling", "escalated-broker-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-maintenance-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e2cb054e-ea41-4ab0-881b-e6f576f7424e",
+      "name" : "create-semantic-concept",
+      "description" : "${create-semantic-concept}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "feb612cc-96a6-4ed2-aaa5-01f39b25beb5",
+      "name" : "insert-table-data",
+      "description" : "${insert-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a0942e33-441b-4343-9f02-4353d03f7bbb",
+      "name" : "find-database",
+      "description" : "${find-database}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6a0bb740-4448-49be-aee8-6dd183325be5",
+      "name" : "delete-foreign-table",
+      "description" : "${delete-foreign-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7f3652c7-3073-4566-ab63-25385495ebc3",
+      "name" : "modify-database-visibility",
+      "description" : "${modify-database-visibility}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "4a5df51d-f14d-41a2-ad70-6521df5a5b4f",
+      "name" : "offline_access",
+      "description" : "${role_offline-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fd41c4c3-d2f8-4f49-84c7-dba84e9a5575",
+      "name" : "execute-query",
+      "description" : "${execute-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "2963c2bb-b129-4224-b98f-c8eeab8e72d1",
+      "name" : "create-table",
+      "description" : "${create-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "0c487c93-448f-4a82-8b9f-ebd8a0904bf8",
+      "name" : "find-foreign-user",
+      "description" : "${find-foreign-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "cf9735a9-fb70-4cc5-b5f4-75afc4e5654b",
+      "name" : "modify-identifier-metadata",
+      "description" : "${modify-identifier-metadata}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "64c2b8f2-1527-4928-81ea-b2651512d028",
+      "name" : "delete-ontology",
+      "description" : "${delete-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d6e38368-b40f-423b-82e4-e8aa595237c9",
+      "name" : "find-maintenance-message",
+      "description" : "${find-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fd1cc463-3e67-49d9-81b8-2cd90c1daa9c",
+      "name" : "check-database-access",
+      "description" : "${check-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "74013867-e426-46cc-ab98-2f4a9225ad1e",
+      "name" : "find-table",
+      "description" : "${find-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a2cc60df-d280-46c5-a539-92e2aa249b4a",
+      "name" : "modify-user-information",
+      "description" : "${modify-user-information}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c367241f-b5b5-491f-84d5-07fe1bef3877",
+      "name" : "default-identifier-handling",
+      "description" : "${default-identifier-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-identifier", "list-identifiers", "create-identifier", "find-identifier", "publish-identifier" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "ba1ad8f2-39aa-487d-987f-645e8a459559",
+      "name" : "delete-table",
+      "description" : "${delete-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "09f7bdb0-296f-46c8-a3a3-8f9254fb17e4",
+      "name" : "list-maintenance-messages",
+      "description" : "${list-maintenance-messages}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe3bc45c-61c2-4ece-bcaf-d410dc7de501",
+      "name" : "update-database-access",
+      "description" : "${update-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f43e86ed-76de-4ca8-9b5e-c292c9359bfe",
+      "name" : "escalated-broker-handling",
+      "description" : "${escalated-broker-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "916b1e65-f60c-42cd-96e4-5c98ffc1ba3c",
+      "name" : "uma_authorization",
+      "description" : "${role_uma_authorization}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d1afa3ed-bf4f-469a-a061-ad7325fb8d9e",
+      "name" : "delete-database-view",
+      "description" : "${delete-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6f044bad-6651-4408-bffa-20c2d8f92eee",
+      "name" : "create-identifier",
+      "description" : "${create-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be91195a-e30a-4d15-a8da-0aca0a68782f",
+      "name" : "escalated-table-handling",
+      "description" : "${escalated-table-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-foreign-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "98bee7d6-d78c-4e7f-b6a3-3705968b248c",
+      "name" : "list-ontologies",
+      "description" : "${list-ontologies}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "15720c6b-027d-4d53-a0ff-0124bfab7c4c",
+      "name" : "re-execute-query",
+      "description" : "${re-execute-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a9b5181a-8135-41d3-9862-ef80af42211d",
+      "name" : "delete-identifier",
+      "description" : "${delete-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "469c2e63-cda6-48d4-ab8f-eb59a2c69798",
+      "name" : "find-database-view",
+      "description" : "${find-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    } ],
+    "client" : {
+      "realm-management" : [ {
+        "id" : "4628f654-f8f3-483b-8f92-2a7fc5930b14",
+        "name" : "query-realms",
+        "description" : "${role_query-realms}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "95c2cc47-12f5-4d73-8b74-67e270c45ade",
+        "name" : "manage-authorization",
+        "description" : "${role_manage-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "824791f3-c345-42f8-b103-b7e6d7e40114",
+        "name" : "manage-identity-providers",
+        "description" : "${role_manage-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "1f840202-b7e2-4195-bac9-64e64dad2037",
+        "name" : "view-identity-providers",
+        "description" : "${role_view-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "3c32c096-bb13-44c9-a080-d756a48a9ea3",
+        "name" : "query-clients",
+        "description" : "${role_query-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "e4b85a68-7f31-4fcf-89a2-f10d7df358e9",
+        "name" : "view-authorization",
+        "description" : "${role_view-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7d317752-ae56-46f2-a2ce-67c64d1b35f6",
+        "name" : "view-users",
+        "description" : "${role_view-users}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-users", "query-groups" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "28824208-976e-4622-b4d7-3d18efbb46fa",
+        "name" : "realm-admin",
+        "description" : "${role_realm-admin}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "57e846a2-930d-4621-819d-c35086507146",
+        "name" : "manage-users",
+        "description" : "${role_manage-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7fad9cde-bf96-475a-9174-14a87da51f95",
+        "name" : "view-realm",
+        "description" : "${role_view-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "bbcac294-d78a-4ea1-a4bf-0384266d2fe1",
+        "name" : "query-users",
+        "description" : "${role_query-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "480e1437-ab9e-47de-b47a-edc6b6e285de",
+        "name" : "view-clients",
+        "description" : "${role_view-clients}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-clients" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "b9a9a8f5-f91e-4e73-9e88-1cdf42bd49f9",
+        "name" : "create-client",
+        "description" : "${role_create-client}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "4d1397fb-247c-436f-b26f-124cd89afb08",
+        "name" : "query-groups",
+        "description" : "${role_query-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "e31f522b-b283-4ae1-b875-52afcd98b1d2",
+        "name" : "impersonation",
+        "description" : "${role_impersonation}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "51822d02-fa28-4a49-89da-bc534719d8a8",
+        "name" : "manage-clients",
+        "description" : "${role_manage-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "b2743ce5-0ce8-4157-ae00-f693560f0b39",
+        "name" : "manage-events",
+        "description" : "${role_manage-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7ea3d7e0-9bf4-438a-b773-243daf622aaa",
+        "name" : "view-events",
+        "description" : "${role_view-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "fb73f6f5-0ed5-41d0-852c-0eb3b195b15a",
+        "name" : "manage-realm",
+        "description" : "${role_manage-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      } ],
+      "security-admin-console" : [ ],
+      "dbrepo-client" : [ ],
+      "admin-cli" : [ ],
+      "rabbitmq-client" : [ ],
+      "account-console" : [ ],
+      "broker" : [ {
+        "id" : "de0cfd5e-c2fe-4082-ac39-e3b092139a0f",
+        "name" : "read-token",
+        "description" : "${role_read-token}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "88694c91-753d-4c44-9740-ec9ac06bba45",
+        "attributes" : { }
+      } ],
+      "account" : [ {
+        "id" : "acd78c04-eefc-4344-a5b4-3fc83d848936",
+        "name" : "delete-account",
+        "description" : "${role_delete-account}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "939be844-8c49-45b3-9ca1-4b10a454b346",
+        "name" : "view-profile",
+        "description" : "${role_view-profile}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "e52fdf00-3e73-4c17-bc1c-643493710a6b",
+        "name" : "view-applications",
+        "description" : "${role_view-applications}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "b02a822e-a708-420a-bddc-1a315033fd7c",
+        "name" : "view-consent",
+        "description" : "${role_view-consent}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "c590e5f5-2cbf-4151-b1dc-96c454f1f654",
+        "name" : "view-groups",
+        "description" : "${role_view-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "15974151-6c13-426b-8cc3-7683dd1311e1",
+        "name" : "manage-account-links",
+        "description" : "${role_manage-account-links}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "c12d8d94-c2df-498e-bbe4-2f934a83ae92",
+        "name" : "manage-consent",
+        "description" : "${role_manage-consent}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "view-consent" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "55f85811-bded-4d6b-8f7b-45844b963875",
+        "name" : "manage-account",
+        "description" : "${role_manage-account}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "manage-account-links" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      } ]
+    }
+  },
+  "groups" : [ {
+    "id" : "f2ce17fe-7b15-47a4-bbf8-86f415298fa9",
+    "name" : "data-stewards",
+    "path" : "/data-stewards",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-data-steward-roles" ],
+    "clientRoles" : { }
+  }, {
+    "id" : "124d9888-0b6e-46aa-8225-077dcedaf16e",
+    "name" : "developers",
+    "path" : "/developers",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-developer-roles" ],
+    "clientRoles" : { }
+  }, {
+    "id" : "f467c38e-9041-4faa-ae0b-39cec65ff4db",
+    "name" : "researchers",
+    "path" : "/researchers",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-researcher-roles" ],
+    "clientRoles" : { }
+  }, {
+    "id" : "2b9f94b4-d434-4a98-8eab-25678cfee983",
+    "name" : "system",
+    "path" : "/system",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-system-roles" ],
+    "clientRoles" : { }
+  } ],
+  "defaultRole" : {
+    "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
+    "name" : "default-roles-dbrepo",
+    "description" : "${role_default-roles}",
+    "composite" : false,
+    "clientRole" : false,
+    "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0"
+  },
+  "defaultGroups" : [ "/researchers" ],
+  "requiredCredentials" : [ "password" ],
+  "otpPolicyType" : "totp",
+  "otpPolicyAlgorithm" : "HmacSHA1",
+  "otpPolicyInitialCounter" : 0,
+  "otpPolicyDigits" : 6,
+  "otpPolicyLookAheadWindow" : 1,
+  "otpPolicyPeriod" : 30,
+  "otpPolicyCodeReusable" : false,
+  "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ],
+  "localizationTexts" : { },
+  "webAuthnPolicyRpEntityName" : "keycloak",
+  "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyRpId" : "",
+  "webAuthnPolicyAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyRequireResidentKey" : "not specified",
+  "webAuthnPolicyUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyCreateTimeout" : 0,
+  "webAuthnPolicyAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyAcceptableAaguids" : [ ],
+  "webAuthnPolicyExtraOrigins" : [ ],
+  "webAuthnPolicyPasswordlessRpEntityName" : "keycloak",
+  "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyPasswordlessRpId" : "",
+  "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified",
+  "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyPasswordlessCreateTimeout" : 0,
+  "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ],
+  "webAuthnPolicyPasswordlessExtraOrigins" : [ ],
+  "scopeMappings" : [ {
+    "clientScope" : "rabbitmq.tag:administrator",
+    "roles" : [ "escalated-broker-handling" ]
+  }, {
+    "clientScope" : "rabbitmq.tag:management",
+    "roles" : [ "default-broker-handling" ]
+  } ],
+  "clientScopeMappings" : {
+    "account" : [ {
+      "client" : "account-console",
+      "roles" : [ "manage-account", "view-groups" ]
+    } ]
+  },
+  "clients" : [ {
+    "id" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+    "clientId" : "account",
+    "name" : "${client_account}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/dbrepo/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/realms/dbrepo/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96",
+    "clientId" : "account-console",
+    "name" : "${client_account-console}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/dbrepo/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/realms/dbrepo/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+",
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "22d90d9c-9881-474c-8dfd-a62c808a9f1c",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6",
+    "clientId" : "admin-cli",
+    "name" : "${client_admin-cli}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : false,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "88694c91-753d-4c44-9740-ec9ac06bba45",
+    "clientId" : "broker",
+    "name" : "${client_broker}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "6b7ef364-4132-4831-b4e2-b6e9e9dc63ee",
+    "clientId" : "dbrepo-client",
+    "name" : "${dbrepo-client}",
+    "description" : "",
+    "rootUrl" : "",
+    "adminUrl" : "",
+    "baseUrl" : "",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : true,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG",
+    "redirectUris" : [ "*" ],
+    "webOrigins" : [ "*" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "oidc.ciba.grant.enabled" : "false",
+      "client.secret.creation.time" : "1680085365",
+      "backchannel.logout.session.required" : "true",
+      "post.logout.redirect.uris" : "*",
+      "oauth2.device.authorization.grant.enabled" : "false",
+      "backchannel.logout.revoke.offline.tokens" : "false"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : true,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
+      "name" : "preferred_username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "claim.value" : "dbrepo",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "access.tokenResponse.claim" : "false"
+      }
+    }, {
+      "id" : "0b4c644f-0cf0-4794-8395-d5d83009dabe",
+      "name" : "uid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "CUSTOM_ID",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "uid",
+        "jsonType.label" : "String"
+      }
+    } ],
+    "defaultClientScopes" : [ "roles", "attributes" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+  }, {
+    "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
+    "clientId" : "rabbitmq-client",
+    "name" : "${rabbitmq-client}",
+    "description" : "",
+    "rootUrl" : "",
+    "adminUrl" : "",
+    "baseUrl" : "",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "JEC2FexxrX4N65fLeDGukAl6R3Lc9y0u",
+    "redirectUris" : [ "*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "oidc.ciba.grant.enabled" : "false",
+      "client.secret.creation.time" : "1680000860",
+      "backchannel.logout.session.required" : "true",
+      "post.logout.redirect.uris" : "*",
+      "oauth2.device.authorization.grant.enabled" : "false",
+      "backchannel.logout.revoke.offline.tokens" : "false"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "01a937ed-f0e8-4137-80f3-3be3c447f7fb",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "false",
+        "user.attribute" : "username",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
+      "name" : "Audience",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "access.tokenResponse.claim" : "false"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+  }, {
+    "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+    "clientId" : "realm-management",
+    "name" : "${client_realm-management}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "f205c451-9524-4380-acc3-947f7ecb6b7c",
+    "clientId" : "security-admin-console",
+    "name" : "${client_security-admin-console}",
+    "rootUrl" : "${authAdminUrl}",
+    "baseUrl" : "/admin/dbrepo/console/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/admin/dbrepo/console/*" ],
+    "webOrigins" : [ "+" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+",
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "c4d54410-3f22-4259-9571-94da2c43b752",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  } ],
+  "clientScopes" : [ {
+    "id" : "69f4ecf0-4165-49ab-bf0d-38409b15b706",
+    "name" : "rabbitmq.tag:administrator",
+    "description" : "administrator",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "7f6e9b44-e2eb-417d-b0fe-db820c9a6564",
+    "name" : "email",
+    "description" : "OpenID Connect built-in scope: email",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${emailScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
+      "name" : "email verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "emailVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email_verified",
+        "jsonType.label" : "boolean"
+      }
+    }, {
+      "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
+      "name" : "email",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "email",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "b9da268f-6745-49dc-a764-3c54e385accc",
+    "name" : "profile",
+    "description" : "OpenID Connect built-in scope: profile",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${profileScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
+      "name" : "gender",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "gender",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "gender",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
+      "name" : "birthdate",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "birthdate",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "birthdate",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
+      "name" : "full name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-full-name-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "f757d8ec-e181-429c-9287-9ad0600b061f",
+      "name" : "profile",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "profile",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "profile",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
+      "name" : "updated at",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "updatedAt",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "updated_at",
+        "jsonType.label" : "long"
+      }
+    }, {
+      "id" : "841ea785-26ab-429a-a420-09ce3948924d",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
+      "name" : "website",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "website",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "website",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "475f071d-5149-4379-b928-76482f5f519c",
+      "name" : "zoneinfo",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "zoneinfo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "zoneinfo",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
+      "name" : "middle name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "middleName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "middle_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
+      "name" : "picture",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "picture",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "picture",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
+      "name" : "nickname",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "nickname",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "nickname",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "627fa054-08eb-4206-af71-9e838e984b8b",
+    "name" : "microprofile-jwt",
+    "description" : "Microprofile - JWT built-in scope",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "e6cc53e5-5d7e-468e-88c8-0737dd3dc759",
+      "name" : "groups",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "multivalued" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "groups",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "83b4444c-10fc-44e8-a0c0-0c1da1f9bba3",
+      "name" : "upn",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "upn",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "4122ff9e-ad3c-4142-afc6-9aefdecfc86d",
+    "name" : "role_list",
+    "description" : "SAML role list",
+    "protocol" : "saml",
+    "attributes" : {
+      "consent.screen.text" : "${samlRoleListScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb0747fa-c008-4af3-93be-e7739650ebd5",
+      "name" : "role list",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-role-list-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "single" : "false",
+        "attribute.nameformat" : "Basic",
+        "attribute.name" : "Role"
+      }
+    } ]
+  }, {
+    "id" : "2e76447d-fbe7-4fa7-a16c-54a381b960ae",
+    "name" : "rabbitmq.configure:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "52aad832-c6c4-49df-8a04-6ad4a406fdfa",
+    "name" : "phone",
+    "description" : "OpenID Connect built-in scope: phone",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${phoneScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
+      "name" : "phone number",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumber",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
+      "name" : "phone number verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumberVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number_verified",
+        "jsonType.label" : "boolean"
+      }
+    } ]
+  }, {
+    "id" : "f64d64e8-57ce-4eb2-b99e-9f02fdbd99f9",
+    "name" : "web-origins",
+    "description" : "OpenID Connect scope for add allowed web origins to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
+      "name" : "allowed web origins",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-allowed-origins-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ]
+  }, {
+    "id" : "55341d34-0086-4173-ae61-d9b175b179d8",
+    "name" : "acr",
+    "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "58ea3217-0fff-4207-9d08-919f5493b629",
+      "name" : "acr loa level",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-acr-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    } ]
+  }, {
+    "id" : "a02c2c38-923c-46ec-9899-321412b388e5",
+    "name" : "attributes",
+    "description" : "User Attributes",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "78c461c1-f3f9-4d10-8835-097f13bdcd60",
+      "name" : "Theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "aggregate.attrs" : "false",
+        "multivalued" : "false",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "theme_dark",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "attributes.theme_dark"
+      }
+    } ]
+  }, {
+    "id" : "06062e22-89c0-4e1d-a25b-2483903b02d5",
+    "name" : "rabbitmq.write:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "db63e03b-7918-492f-997b-f2dda98f3b39",
+    "name" : "rabbitmq.tag:management",
+    "description" : "management",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
+    "name" : "offline_access",
+    "description" : "OpenID Connect built-in scope: offline_access",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "consent.screen.text" : "${offlineAccessScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    }
+  }, {
+    "id" : "425abf4a-2ee2-431d-aa92-e373a36fe556",
+    "name" : "address",
+    "description" : "OpenID Connect built-in scope: address",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${addressScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
+      "name" : "address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-address-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute.formatted" : "formatted",
+        "user.attribute.country" : "country",
+        "user.attribute.postal_code" : "postal_code",
+        "userinfo.token.claim" : "true",
+        "user.attribute.street" : "street",
+        "id.token.claim" : "true",
+        "user.attribute.region" : "region",
+        "access.token.claim" : "true",
+        "user.attribute.locality" : "locality"
+      }
+    } ]
+  }, {
+    "id" : "c96f0b73-ea79-4b46-93ef-d1092297f855",
+    "name" : "rabbitmq.read:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc",
+    "name" : "roles",
+    "description" : "OpenID Connect scope for add user roles to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${rolesScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    }, {
+      "id" : "2defedf5-9af3-4531-822c-a879dedcd29d",
+      "name" : "realm roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "realm_access.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    }, {
+      "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
+      "name" : "client roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-client-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "resource_access.${client_id}.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    } ]
+  } ],
+  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ],
+  "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ],
+  "browserSecurityHeaders" : {
+    "contentSecurityPolicyReportOnly" : "",
+    "xContentTypeOptions" : "nosniff",
+    "referrerPolicy" : "no-referrer",
+    "xRobotsTag" : "none",
+    "xFrameOptions" : "SAMEORIGIN",
+    "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+    "xXSSProtection" : "1; mode=block",
+    "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
+  },
+  "smtpServer" : { },
+  "eventsEnabled" : false,
+  "eventsListeners" : [ "jboss-logging" ],
+  "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
+  "adminEventsEnabled" : false,
+  "adminEventsDetailsEnabled" : false,
+  "identityProviders" : [ ],
+  "identityProviderMappers" : [ ],
+  "components" : {
+    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ {
+      "id" : "4d3f9f14-f5d2-4b0c-8ea7-e6d078aa2191",
+      "name" : "Max Clients Limit",
+      "providerId" : "max-clients",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "max-clients" : [ "200" ]
+      }
+    }, {
+      "id" : "f35bce67-1e75-408b-b065-52183368d4fd",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "0efa669d-1017-4b4a-82e1-c2eaf72de2c9",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "528fb423-d66e-472e-9120-1f03ba9e0f18",
+      "name" : "Consent Required",
+      "providerId" : "consent-required",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "3ab11d74-5e76-408a-b85a-26bf8950f979",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ]
+      }
+    }, {
+      "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
+      "name" : "Trusted Hosts",
+      "providerId" : "trusted-hosts",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "host-sending-registration-request-must-match" : [ "true" ],
+        "client-uris-must-match" : [ "true" ]
+      }
+    }, {
+      "id" : "f565cb47-3bcf-4078-8f94-eb4179c375b8",
+      "name" : "Full Scope Disabled",
+      "providerId" : "scope",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "104ec5a9-025b-4c44-8ac0-82d22887ca3e",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ]
+      }
+    } ],
+    "org.keycloak.userprofile.UserProfileProvider" : [ {
+      "id" : "fb763636-e1ea-49c7-adca-ea105cdec4ad",
+      "providerId" : "declarative-user-profile",
+      "subComponents" : { },
+      "config" : {
+        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
+      }
+    } ],
+    "org.keycloak.keys.KeyProvider" : [ {
+      "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
+      "name" : "rsa-enc-generated",
+      "providerId" : "rsa-enc-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEowIBAAKCAQEA3b1tNLfcjFLUw9UShVDNf+ZD8sQqb4YBaIXcSJTX/zDQUPiCp176BBGI3s4VplDArnOW+LumozmKogeoHEnGEIDW8ovgK5uMU9tSA2p0qqGBUMOdR8YATTIfCJe7qGiiuGa3WZy3sQLM70SuRzx02YU8gvUcvl2Js4KyqAziOUX/w3Wa59H9jjGNUXYyqaPWJp73eHzbVYWySzyLG22mVlcUtBx5siL5T2/Xu0p9z4l7/bapwwmOVi1ZrcHjbEAwdGEiSMGI/uWqAF+r1BRpmJLR7HNXcL3eK4/56VYLaiwSejfyYeRFMITEn/UxGYhcXZ5xMUUCG0TxjBhLYpTBuwIDAQABAoIBAA4dwebcxkrH99Poa8+WkiE7JgaS9sahx9OBI2xwJANoIU2TpzGuNLQZ76uLgB+rPWZTD9Xm5a1iJjwOyQ9/937TzPCk91D0tpgcusRikb8jx/6TGB9acL4kBjYUVCCHr3BA2G75MKKGtJ2OMvAbCQSosZj+r2VDwYFEPUkV2jheE5JHSBkwyIRrus3JCwu8gu5fyCg9z8ljcxJxI5HIsi4v8Z21aCw/cLj7h5cMt44wCjQz4rOfYNBEFeHDtlfR1QtWKgjm4ZHHJbKrzf9b2kQXclziceEbSM0tYbROEXKi+s0Zc+z3HEG89vv0vfN400clmzzIAijKY6gg3pPRWdECgYEA+lnWYbSlXDMNYx6RBXm1RnlMUYIm4oy4/9ljgnoGJ6WCn3SjFkgaDtiKfGIG1BSB85r04pAPANgcWHf5tWDnq0ARvBVG0BX2bKd++7B3D4d3CRYKCwm88SslJXv9dfHVhq4+zViFPiUWwT20A72jCuUCvL88y5fh/YBecfdh+jECgYEA4r5RD0NB9dMaeg5/jk/GEHIo4Z9KLc6FrSoOFo2xFkPOy1sgDpDOiNtypuWvniO7k7Ose3DS3hlfTMsKzIW/CgQJ20+Y4cvBWDaOsRxfjj7w3d+jH5OSJdKKSzTrgLKc9ZhlRzVXy0J0hipIA6HG5kdVdLXmh85ITmf1CbJhE6sCgYBjPVeBNbXTHZ2x6/z62aslO5IoQVqetb/kE82hfDOSZcao5Ph9Lam+ttH2ynkAevykj4mBgi+gWwqpey2uW7KaLPSaxShj9kDQA3mP1fzsV/u0y1rB02Nlin/YIxVvOqU1FT9p8SwoXVVu1sHUNck62VtDbN9xqUx5S/ikXrclEQKBgQCoTssOwEcK+Vty9KYcdfy4onTUHZBLdjxl8Iyqkxy7QTQUYRznkvesQPDXEDGO+kk3dyx2KKZt9Hl4IFNww2quPZcvcuMx4DQxjbXXpA8OIIxcta95NepLJwA+mRai3nKCH1A2TlNP7pFeMa5o+8IPly3Ix2lKr4Wepa4PN5i1pwKBgCZ1QP6XAOERl9NznNmU0rXVcvYNP4PIIfQWfvGsldZ4QKkmjjAGiS0/oYqdWs+UDRZyCRChaVjDXO9fk0PEG5OGKAj9nyiYCT/M8xtJ3UeP5ffZZvJ/vnye3QdDIo1e38ZzsWwJHmLYw7fRqY9W5Vxo0Vsy22U3CJY70KTxVdTy" ],
+        "keyUse" : [ "ENC" ],
+        "certificate" : [ "MIICmzCCAYMCBgGG3GWycDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdvW00t9yMUtTD1RKFUM1/5kPyxCpvhgFohdxIlNf/MNBQ+IKnXvoEEYjezhWmUMCuc5b4u6ajOYqiB6gcScYQgNbyi+Arm4xT21IDanSqoYFQw51HxgBNMh8Il7uoaKK4ZrdZnLexAszvRK5HPHTZhTyC9Ry+XYmzgrKoDOI5Rf/DdZrn0f2OMY1RdjKpo9Ymnvd4fNtVhbJLPIsbbaZWVxS0HHmyIvlPb9e7Sn3PiXv9tqnDCY5WLVmtweNsQDB0YSJIwYj+5aoAX6vUFGmYktHsc1dwvd4rj/npVgtqLBJ6N/Jh5EUwhMSf9TEZiFxdnnExRQIbRPGMGEtilMG7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAK3kQ1VkQrzvSWvmXmazmNoA1ZiPzRDs1XhGUWxgsxzgPylr3dGBuqQbKvgnLUBQLSqlJHpI4fZflHswu1qrvVZYtekPcGef4WhcKAu2i1RwxrKa6RJQ1tRbrLuVYCzPv5p/DWgltWVn88aoLnqQn0SK/0PB/o4a4Cm7Kq2ZzCr1dACBr06LvOHsc7249OySmbG4HH+pLK6jVURhZ9VaObqAHe2FJBVVoIzURbdiRRURqumrIvbnpeaU1aFyg6ED5wTnXvmMPmVPt9F79mcB33bASO5wyu00X8t1hyN2Show2l2vxLACGUzVkTQt15s7uDLKE7qLmKSR3EuSGXWv3wA=" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "RSA-OAEP" ]
+      }
+    }, {
+      "id" : "230cb681-9ceb-4b1b-8a4c-929a11b08de0",
+      "name" : "hmac-generated-hs512",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "8a489935-9a95-459b-9059-59b438ef0fa8" ],
+        "secret" : [ "xSCVgBlrLPWoF54gKQdR7BqXlfNaCD43xtS_ZgQRC0tGNAbqhy2Q9y8LdD2IR7K__8VGaDGYtyZayopgTebhDBb4gHDjDOBX7flhFYRrm0G3aTIuCIyFG-bPULwmyP_oHeC6tjwdQhqx5G0tE2mQQqPC9dDZuUA5I7QREIGK8cI" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS512" ]
+      }
+    }, {
+      "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30",
+      "name" : "aes-generated",
+      "providerId" : "aes-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "6dc4834f-a1de-4cfe-a29d-e84ac8e9b1a8" ],
+        "secret" : [ "HpuzG_jWYKwypLeoPEMC4A" ],
+        "priority" : [ "100" ]
+      }
+    }, {
+      "id" : "bd7945cf-6d35-4e03-9c3a-197f2dc76973",
+      "name" : "hmac-generated",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "5034d264-cb50-4006-a59e-2ce636eb5f38" ],
+        "secret" : [ "ToVIw-a4IE-Yp9JpP8ztb8NAICYO8CT3tUiDPT6DdiBcgzKJ9Ym9vspxGVdmPceX3mAgbnGLAcTx1PkInSVrbZs-tX9QXFwdlyGbewhKiNpH8wEg32Wk4GuUDpTv8JCsymgWyQBY681jvIMv05eCoK2QWpqCzcgP828KM5peCzo" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS256" ]
+      }
+    }, {
+      "id" : "2293ff99-3c6d-46d1-8635-5e679d5b134a",
+      "name" : "rsa-generated",
+      "providerId" : "rsa-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEpAIBAAKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQABAoIBADNcMt6hAHub4JTAYS6Mra0EPRBO2XhWmACBrv3+8ETClXd5475KPLDewgRVtlmtbwU8G8awUXESQgPS9lfiqvQhPreA3cHlm6oP2WMKOEtakr2s8I+frsTBLCo0Ini9RaSzjoVVgS0zofyhASKi+T970MafSj5P3XNb8YBFdXgoYDiA7FXLH6a/+m7LScL+wGcFMAAeYESxZbMQLfH3v8L+4EcTraiwjLG17ZdlF3dpybMyUSse6ZQ/PdlyvBuzzLXhN6Ce2gd9ATfS+YWTzo7Yf+GU+ex5bIpVOfHqtuM/hyq7YGKENClsXwNZIAoFnvGCbvECAfgyapVrD30IfykCgYEA0rgsSZ82pxT40NxwgBD1g9lbNVBKXphRB/3S078qusUzJjT7AldEj4imGPhAbI7bI8gAeWJsp1XJWkjM8ktaVrh+NQl7p8e9OPh0pQF/5Bdg8ajbjXESpjnaU66pVYRQy/d+jNli/YRAHX5RUfsBl+6W4+WSVMGmKBiqJsur+ecCgYEAz1YVXClcmUnyZem5B+2E9noIzjF6ROE+jIb6rawM85P3Xd0lXtECQavtxw+Qk7I32qOwrxl1UpK2foVel3pazi+4OpMfmqtYGenRP1Zk1cZwrDo0cIemTDGjj3kJ8tYn12CGolFQpJZgK6OHzvG0tOxI5VZgjIViWNPe1PGWXtUCgYEAxXGNDe8BZs1f11S2lUlOw5yGug3hoYFXbAWJ5p7Ziuf8ZXB/QlJDC7se54a11wKEk6Jzz0lKRgE8CjzszJuOqnN0zn10QGIIC7nCklo1W6QMUmPGVWH994N976tZP6gbjQL6sT+AYcvpx7j0ubxYYeRNvnz+ACzzY964kGGHY0ECgYEAumlwPPNnMN7+VEjGNm2D7UMdJZ3wi3tkjF5ThdA5uMohTsAk+FG80KSu3RmOaGyEsUwY7+VYyYvlDm4E9PZqLBVVczyR3rMNPAcwPd0EPfvzk7WlLkOX7ct3fehaXH3VRlyfz9KCSeh1wOZ/lT1VtpD2nVOC7PSDzs92+kfXZZ0CgYAnrD1y4skgXkdwolZ3unn3EFyGm2d+X5aMTHwQPdWxqoNIAl/9wdghlzihwnPhhsxq1WzlxuC3V2IMrNPtRx70Mi+FbSmR5m4Xx5RptgMtMlwno+L40PzNJgMjHGjt0wcx3Vel8wuohDtnqMyS7P5nG1/TQx0Cyzwn7QOXlNpgbQ==" ],
+        "keyUse" : [ "SIG" ],
+        "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ],
+        "priority" : [ "100" ]
+      }
+    } ]
+  },
+  "internationalizationEnabled" : false,
+  "supportedLocales" : [ ],
+  "authenticationFlows" : [ {
+    "id" : "88e5d526-2298-413c-a904-133ad839d47f",
+    "alias" : "Account verification options",
+    "description" : "Method with which to verity the existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-email-verification",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Verify Existing Account by Re-authentication",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "a690c715-fbae-4c20-b680-bd4010718761",
+    "alias" : "Browser - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad",
+    "alias" : "Direct Grant - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "direct-grant-validate-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515",
+    "alias" : "First broker login - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523",
+    "alias" : "Handle Existing Account",
+    "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-confirm-link",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Account verification options",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "088f4051-36ab-4952-a4f2-4ba53c408083",
+    "alias" : "Reset - Conditional OTP",
+    "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4",
+    "alias" : "User creation or linking",
+    "description" : "Flow for the existing/non-existing user alternatives",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "create unique user config",
+      "authenticator" : "idp-create-user-if-unique",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Handle Existing Account",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4",
+    "alias" : "Verify Existing Account by Re-authentication",
+    "description" : "Reauthentication of existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-username-password-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "First broker login - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c",
+    "alias" : "browser",
+    "description" : "browser based authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "auth-cookie",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-spnego",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "identity-provider-redirector",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 25,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "autheticatorFlow" : true,
+      "flowAlias" : "forms",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d",
+    "alias" : "clients",
+    "description" : "Base authentication for clients",
+    "providerId" : "client-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "client-secret",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-jwt",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-secret-jwt",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-x509",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 40,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63",
+    "alias" : "direct grant",
+    "description" : "OpenID Connect Resource Owner Grant",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "direct-grant-validate-username",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "direct-grant-validate-password",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 30,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Direct Grant - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781",
+    "alias" : "docker auth",
+    "description" : "Used by Docker clients to authenticate against the IDP",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "docker-http-basic-authenticator",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43",
+    "alias" : "first broker login",
+    "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "review profile config",
+      "authenticator" : "idp-review-profile",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "User creation or linking",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8",
+    "alias" : "forms",
+    "description" : "Username, password, otp and other auth forms.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "auth-username-password-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Browser - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914",
+    "alias" : "registration",
+    "description" : "registration flow",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "registration-page-form",
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : true,
+      "flowAlias" : "registration form",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "d62c8dd6-633c-408a-aa99-43071510efb4",
+    "alias" : "registration form",
+    "description" : "registration form",
+    "providerId" : "form-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "registration-user-creation",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-password-action",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 50,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-recaptcha-action",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 60,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb",
+    "alias" : "reset credentials",
+    "description" : "Reset credentials for a user if they forgot their password or something",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "reset-credentials-choose-user",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-credential-email",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-password",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 40,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Reset - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "389c1c37-e8af-4610-a507-e1257f55b954",
+    "alias" : "saml ecp",
+    "description" : "SAML ECP Profile Authentication Flow",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "http-basic-authenticator",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  } ],
+  "authenticatorConfig" : [ {
+    "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4",
+    "alias" : "create unique user config",
+    "config" : {
+      "require.password.update.after.registration" : "false"
+    }
+  }, {
+    "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d",
+    "alias" : "review profile config",
+    "config" : {
+      "update.profile.on.first.login" : "missing"
+    }
+  } ],
+  "requiredActions" : [ {
+    "alias" : "CONFIGURE_TOTP",
+    "name" : "Configure OTP",
+    "providerId" : "CONFIGURE_TOTP",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 10,
+    "config" : { }
+  }, {
+    "alias" : "TERMS_AND_CONDITIONS",
+    "name" : "Terms and Conditions",
+    "providerId" : "TERMS_AND_CONDITIONS",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 20,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PASSWORD",
+    "name" : "Update Password",
+    "providerId" : "UPDATE_PASSWORD",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 30,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PROFILE",
+    "name" : "Update Profile",
+    "providerId" : "UPDATE_PROFILE",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 40,
+    "config" : { }
+  }, {
+    "alias" : "VERIFY_EMAIL",
+    "name" : "Verify Email",
+    "providerId" : "VERIFY_EMAIL",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 50,
+    "config" : { }
+  }, {
+    "alias" : "delete_account",
+    "name" : "Delete Account",
+    "providerId" : "delete_account",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 60,
+    "config" : { }
+  }, {
+    "alias" : "webauthn-register",
+    "name" : "Webauthn Register",
+    "providerId" : "webauthn-register",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 70,
+    "config" : { }
+  }, {
+    "alias" : "webauthn-register-passwordless",
+    "name" : "Webauthn Register Passwordless",
+    "providerId" : "webauthn-register-passwordless",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 80,
+    "config" : { }
+  }, {
+    "alias" : "delete_credential",
+    "name" : "Delete Credential",
+    "providerId" : "delete_credential",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 100,
+    "config" : { }
+  }, {
+    "alias" : "update_user_locale",
+    "name" : "Update User Locale",
+    "providerId" : "update_user_locale",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 1000,
+    "config" : { }
+  } ],
+  "browserFlow" : "browser",
+  "registrationFlow" : "registration",
+  "directGrantFlow" : "direct grant",
+  "resetCredentialsFlow" : "reset credentials",
+  "clientAuthenticationFlow" : "clients",
+  "dockerAuthenticationFlow" : "docker auth",
+  "firstBrokerLoginFlow" : "first broker login",
+  "attributes" : {
+    "cibaBackchannelTokenDeliveryMode" : "poll",
+    "cibaAuthRequestedUserHint" : "login_hint",
+    "clientOfflineSessionMaxLifespan" : "0",
+    "oauth2DevicePollingInterval" : "5",
+    "clientSessionIdleTimeout" : "0",
+    "actionTokenGeneratedByUserLifespan-execute-actions" : "",
+    "actionTokenGeneratedByUserLifespan-verify-email" : "",
+    "clientOfflineSessionIdleTimeout" : "0",
+    "actionTokenGeneratedByUserLifespan-reset-credentials" : "",
+    "cibaInterval" : "5",
+    "realmReusableOtpCode" : "false",
+    "cibaExpiresIn" : "120",
+    "oauth2DeviceCodeLifespan" : "600",
+    "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
+    "parRequestUriLifespan" : "60",
+    "clientSessionMaxLifespan" : "0",
+    "shortVerificationUri" : ""
+  },
+  "keycloakVersion" : "24.0.5",
+  "userManagedAccessAllowed" : false,
+  "clientProfiles" : {
+    "profiles" : [ ]
+  },
+  "clientPolicies" : {
+    "policies" : [ ]
+  }
+}
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/target/create-event-listener.jar b/dbrepo-auth-service/listeners/target/create-event-listener.jar
new file mode 100644
index 0000000000000000000000000000000000000000..26cb91c37666c966f6382d35feaaf9f5da5c7f8c
Binary files /dev/null and b/dbrepo-auth-service/listeners/target/create-event-listener.jar differ
diff --git a/dbrepo-auth-service/master-realm.json b/dbrepo-auth-service/master-realm.json
index ef06561e687af0d808781b6c71a1a2b2ea664275..1cf53fe49cffabe7e5833675db95ebff6eec7034 100644
--- a/dbrepo-auth-service/master-realm.json
+++ b/dbrepo-auth-service/master-realm.json
@@ -40,6 +40,7 @@
   "bruteForceProtected" : false,
   "permanentLockout" : false,
   "maxTemporaryLockouts" : 0,
+  "bruteForceStrategy" : "MULTIPLE",
   "maxFailureWaitSeconds" : 900,
   "minimumQuickLoginWaitSeconds" : 60,
   "waitIncrementSeconds" : 60,
@@ -664,8 +665,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
-      "client.use.lightweight.access.token.enabled" : "true"
+      "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
     "fullScopeAllowed" : true,
@@ -783,8 +784,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
       "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -816,8 +817,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${addressScopeConsentText}"
+      "consent.screen.text" : "${addressScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "4aed5e41-0d8d-4c24-80a0-cd9822072756",
@@ -845,8 +846,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${organizationScopeConsentText}"
+      "consent.screen.text" : "${organizationScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92",
@@ -864,6 +865,61 @@
         "jsonType.label" : "String"
       }
     } ]
+  }, {
+    "id" : "1be1e284-2749-4bbb-890a-2d519cc1531c",
+    "name" : "service_account",
+    "description" : "Specific scope for a client enabled for service accounts",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "c913a673-cf66-4493-a2ed-14556c07617c",
+      "name" : "Client ID",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "client_id",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "5c244d68-5c63-4356-ac71-5a586f40c77e",
+      "name" : "Client IP Address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientAddress",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientAddress",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "600285d4-ae51-4b39-a7be-bb83cf5870db",
+      "name" : "Client Host",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientHost",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientHost",
+        "jsonType.label" : "String"
+      }
+    } ]
   }, {
     "id" : "0411ea86-a074-4781-850d-ea3ca94590a2",
     "name" : "offline_access",
@@ -915,8 +971,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${profileScopeConsentText}"
+      "consent.screen.text" : "${profileScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "2d1400be-4053-4393-ba87-91b64f699054",
@@ -1217,8 +1273,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "false",
-      "consent.screen.text" : ""
+      "consent.screen.text" : "",
+      "display.on.consent.screen" : "false"
     },
     "protocolMappers" : [ {
       "id" : "635cbac1-7cab-43bd-99fc-f7084aca2fa2",
@@ -1254,8 +1310,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${rolesScopeConsentText}"
+      "consent.screen.text" : "${rolesScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "2b5a3df4-1adb-402d-bc28-2bd43224e682",
@@ -1264,12 +1320,12 @@
       "protocolMapper" : "oidc-usermodel-realm-role-mapper",
       "consentRequired" : false,
       "config" : {
-        "introspection.token.claim" : "true",
-        "multivalued" : "true",
         "user.attribute" : "foo",
+        "introspection.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "realm_access.roles",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "multivalued" : "true"
       }
     }, {
       "id" : "f3b60071-ef26-48a7-9554-67f62f84d543",
@@ -1278,12 +1334,12 @@
       "protocolMapper" : "oidc-usermodel-client-role-mapper",
       "consentRequired" : false,
       "config" : {
-        "introspection.token.claim" : "true",
-        "multivalued" : "true",
         "user.attribute" : "foo",
+        "introspection.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "resource_access.${client_id}.roles",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "multivalued" : "true"
       }
     }, {
       "id" : "b757200e-494a-4585-857e-e4c18aef7a0c",
@@ -1303,8 +1359,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${emailScopeConsentText}"
+      "consent.screen.text" : "${emailScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "e18769b3-778b-47d8-be52-dd2769deebd1",
@@ -1344,8 +1400,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${phoneScopeConsentText}"
+      "consent.screen.text" : "${phoneScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "98cc724c-3f53-47f7-bf9f-baf2f7e08026",
@@ -1431,7 +1487,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper" ]
       }
     }, {
       "id" : "4b976576-c880-48a0-9b4d-2956cfd19b4a",
@@ -1440,7 +1496,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper" ]
       }
     }, {
       "id" : "e1861ec9-2761-46fb-8048-149492269ff0",
@@ -1470,6 +1526,14 @@
         "allow-default-scopes" : [ "true" ]
       }
     } ],
+    "org.keycloak.userprofile.UserProfileProvider" : [ {
+      "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
+      "providerId" : "declarative-user-profile",
+      "subComponents" : { },
+      "config" : {
+        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
+      }
+    } ],
     "org.keycloak.storage.UserStorageProvider" : [ {
       "id" : "3a6f24e8-128b-4ac1-b3ab-694836db82fd",
       "name" : "Identity Service",
@@ -1483,8 +1547,8 @@
           "config" : {
             "ldap.attribute" : [ "mail" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "false" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "email" ]
           }
         }, {
@@ -1495,8 +1559,8 @@
           "config" : {
             "ldap.attribute" : [ "sn" ],
             "is.mandatory.in.ldap" : [ "true" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "true" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "lastName" ]
           }
         }, {
@@ -1507,8 +1571,8 @@
           "config" : {
             "ldap.attribute" : [ "modifyTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "true" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "modifyTimestamp" ]
           }
         }, {
@@ -1541,17 +1605,17 @@
           "providerId" : "group-ldap-mapper",
           "subComponents" : { },
           "config" : {
+            "mode" : [ "LDAP_ONLY" ],
             "membership.attribute.type" : [ "DN" ],
+            "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
             "group.name.ldap.attribute" : [ "cn" ],
+            "ignore.missing.groups" : [ "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" ],
-            "group.object.classes" : [ "groupOfNames" ],
+            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
             "memberof.ldap.attribute" : [ "memberOf" ],
+            "group.object.classes" : [ "groupOfNames" ],
             "drop.non.existing.groups.during.sync" : [ "false" ],
             "groups.path" : [ "/" ]
           }
@@ -1563,8 +1627,8 @@
           "config" : {
             "ldap.attribute" : [ "createTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "true" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "createTimestamp" ]
           }
         } ]
@@ -1580,9 +1644,9 @@
         "importEnabled" : [ "true" ],
         "enabled" : [ "true" ],
         "changedSyncPeriod" : [ "-1" ],
+        "usernameLDAPAttribute" : [ "uid" ],
         "bindCredential" : [ "admin" ],
         "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
-        "usernameLDAPAttribute" : [ "uid" ],
         "vendor" : [ "other" ],
         "uuidLDAPAttribute" : [ "entryUUID" ],
         "allowKerberosAuthentication" : [ "false" ],
@@ -1600,14 +1664,6 @@
         "validatePasswordPolicy" : [ "false" ]
       }
     } ],
-    "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
-      "providerId" : "declarative-user-profile",
-      "subComponents" : { },
-      "config" : {
-        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
-      }
-    } ],
     "org.keycloak.keys.KeyProvider" : [ {
       "id" : "5b1052d2-fb71-47d2-86f9-908c869c8d1b",
       "name" : "hmac-generated-hs512",
@@ -2219,10 +2275,12 @@
     "parRequestUriLifespan" : "60",
     "clientSessionMaxLifespan" : "0",
     "frontendUrl" : "",
+    "organizationsEnabled" : "false",
     "acr.loa.map" : "{}"
   },
-  "keycloakVersion" : "24.0.5",
+  "keycloakVersion" : "26.0.4",
   "userManagedAccessAllowed" : false,
+  "organizationsEnabled" : false,
   "clientProfiles" : {
     "profiles" : [ ]
   },
diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile
index f4e2be5b967ca109e858d6f17099ec67d341ac12..9edf1375fb6c47f63dbd45f26bba0b3a6fe15255 100644
--- a/dbrepo-data-service/Dockerfile
+++ b/dbrepo-data-service/Dockerfile
@@ -8,7 +8,7 @@ LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 
 COPY ./pom.xml ./
 
-RUN mvn -fn -B dependency:go-offline
+RUN mvn -fn dependency:go-offline
 
 COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien
 
@@ -18,7 +18,7 @@ COPY ./rest-service ./rest-service
 COPY ./services ./services
 
 # Make sure it compiles
-RUN mvn clean package -DskipTests
+RUN mvn -fn clean package -DskipTests
 
 ###### THIRD STAGE ######
 FROM amazoncorretto:17-alpine3.19 AS runtime
diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml
index 884824994aff8a6e8f05bce24c44307ffe64c2b8..e2bfa739618b3a518aeabd623ea49718b9a06d5b 100644
--- a/dbrepo-data-service/pom.xml
+++ b/dbrepo-data-service/pom.xml
@@ -11,7 +11,7 @@
     <groupId>at.tuwien</groupId>
     <artifactId>dbrepo-data-service</artifactId>
     <name>dbrepo-data-service</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <description>Service that manages the data</description>
 
diff --git a/dbrepo-data-service/querystore/pom.xml b/dbrepo-data-service/querystore/pom.xml
index 943c115d117529adea091f02f77037367c12a32c..2905b5a935407cab65086def3f9c21d980ee329a 100644
--- a/dbrepo-data-service/querystore/pom.xml
+++ b/dbrepo-data-service/querystore/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-data-service-querystore</artifactId>
     <name>dbrepo-data-service-querystore</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies/>
 
diff --git a/dbrepo-data-service/report/pom.xml b/dbrepo-data-service/report/pom.xml
index ca03190a449b76f7217590283097978be9d8a0ab..4b230d55ebfbf084cfd00eea7cd7c568ac620d71 100644
--- a/dbrepo-data-service/report/pom.xml
+++ b/dbrepo-data-service/report/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>report</artifactId>
     <name>dbrepo-data-service-report</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
     <description>
         This module is only intended for the pipeline coverage report. See the detailed report in the
         respective modules
diff --git a/dbrepo-data-service/rest-service/pom.xml b/dbrepo-data-service/rest-service/pom.xml
index e72392c7071cb3083c894fbc3654266f34650f01..721cf1a254c8fff0927bffbd7d6ff27b3dcead8d 100644
--- a/dbrepo-data-service/rest-service/pom.xml
+++ b/dbrepo-data-service/rest-service/pom.xml
@@ -6,18 +6,18 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>rest-service</artifactId>
     <name>dbrepo-data-service-rest-service</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
             <groupId>at.tuwien</groupId>
             <artifactId>services</artifactId>
-            <version>1.6.1</version>
+            <version>1.6.3</version>
         </dependency>
     </dependencies>
 
@@ -38,6 +38,14 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>9</source>
+                    <target>9</target>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
index 7947e87a495595441c945e950453499c635aaac2..4d3803a1e1c7159903ae090515edf5d9f353b068 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
@@ -1,9 +1,9 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.database.UpdateDatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.database.CreateAccessDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.error.ApiErrorDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.*;
 import at.tuwien.service.AccessService;
 import at.tuwien.service.CredentialService;
@@ -29,7 +29,7 @@ import java.util.UUID;
 @RestController
 @CrossOrigin(origins = "*")
 @RequestMapping(path = "/api/database/{databaseId}/access")
-public class AccessEndpoint extends AbstractEndpoint {
+public class AccessEndpoint extends RestEndpoint {
 
     private final AccessService accessService;
     private final CredentialService credentialService;
@@ -76,12 +76,12 @@ public class AccessEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<Void> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                        @PathVariable("userId") UUID userId,
-                                       @Valid @RequestBody UpdateDatabaseAccessDto data)
+                                       @Valid @RequestBody CreateAccessDto data)
             throws NotAllowedException, DatabaseUnavailableException, DatabaseNotFoundException,
             RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint give access to database, databaseId={}, userId={}", databaseId, userId);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
-        final PrivilegedUserDto user = credentialService.getUser(userId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
+        final UserDto user = credentialService.getUser(userId);
         if (database.getAccesses().stream().anyMatch(a -> a.getUser().getId().equals(userId))) {
             log.error("Failed to create access to user with id {}: already has access", userId);
             throw new NotAllowedException("Failed to create access to user with id " + userId + ": already has access");
@@ -132,13 +132,13 @@ public class AccessEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId,
                                        @PathVariable("userId") UUID userId,
-                                       @Valid @RequestBody UpdateDatabaseAccessDto access) throws NotAllowedException,
+                                       @Valid @RequestBody CreateAccessDto access) throws NotAllowedException,
             DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint modify access to database, databaseId={}, userId={}, access.type={}", databaseId, userId,
                 access.getType());
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
-        final PrivilegedUserDto user = credentialService.getUser(userId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
+        final UserDto user = credentialService.getUser(userId);
         if (database.getAccesses().stream().noneMatch(a -> a.getHuserid().equals(userId))) {
             log.error("Failed to update access to user with id {}: no access", userId);
             throw new NotAllowedException("Failed to update access to user with id " + userId + ": no access");
@@ -208,8 +208,8 @@ public class AccessEndpoint extends AbstractEndpoint {
             DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint revoke access to database, databaseId={}, userId={}", databaseId, userId);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
-        final PrivilegedUserDto user = credentialService.getUser(userId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
+        final UserDto user = credentialService.getUser(userId);
         if (database.getAccesses().stream().noneMatch(a -> a.getUser().getId().equals(userId))) {
             log.error("Failed to delete access to user with id {}: no access", userId);
             throw new NotAllowedException("Failed to delete access to user with id " + userId + ": no access");
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index d101a8c97393a41ecf4e76ea4e4fb4aa3c1f4993..27848cf517ca0187f8ccd69d5ec894a4a6121304 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -1,19 +1,17 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.AccessTypeDto;
 import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.internal.CreateDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.error.ApiErrorDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.exception.*;
-import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.AccessService;
+import at.tuwien.service.ContainerService;
 import at.tuwien.service.CredentialService;
 import at.tuwien.service.DatabaseService;
-import at.tuwien.service.SubsetService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -35,21 +33,19 @@ import java.sql.SQLException;
 @RestController
 @CrossOrigin(origins = "*")
 @RequestMapping(path = "/api/database")
-public class DatabaseEndpoint extends AbstractEndpoint {
+public class DatabaseEndpoint extends RestEndpoint {
 
-    private final SubsetService queryService;
     private final AccessService accessService;
-    private final MetadataMapper metadataMapper;
     private final DatabaseService databaseService;
+    private final ContainerService containerService;
     private final CredentialService credentialService;
 
     @Autowired
-    public DatabaseEndpoint(SubsetService queryService, AccessService accessService, MetadataMapper metadataMapper,
-                            DatabaseService databaseService, CredentialService credentialService) {
-        this.queryService = queryService;
+    public DatabaseEndpoint(AccessService accessService, DatabaseService databaseService,
+                            ContainerService containerService, CredentialService credentialService) {
         this.accessService = accessService;
-        this.metadataMapper = metadataMapper;
         this.databaseService = databaseService;
+        this.containerService = containerService;
         this.credentialService = credentialService;
     }
 
@@ -90,18 +86,18 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             DatabaseMalformedException, QueryStoreCreateException, MetadataServiceException {
         log.debug("endpoint create database, data.containerId={}, data.internalName={}, data.username={}",
                 data.getContainerId(), data.getInternalName(), data.getUsername());
-        final PrivilegedContainerDto container = credentialService.getContainer(data.getContainerId());
+        final ContainerDto container = credentialService.getContainer(data.getContainerId());
         try {
-            final PrivilegedDatabaseDto database = databaseService.create(container, data);
-            queryService.createQueryStore(container, data.getInternalName());
-            final PrivilegedUserDto user = PrivilegedUserDto.builder()
+            final DatabaseDto database = containerService.createDatabase(container, data);
+            containerService.createQueryStore(container, data.getInternalName());
+            final UserDto user = UserDto.builder()
                     .id(data.getUserId())
                     .username(data.getUsername())
                     .password(data.getPassword())
                     .build();
             accessService.create(database, user, AccessTypeDto.WRITE_ALL);
             return ResponseEntity.status(HttpStatus.CREATED)
-                    .body(metadataMapper.privilegedDatabaseDtoToDatabaseDto(database));
+                    .body(database);
         } 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);
@@ -138,7 +134,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             DatabaseMalformedException, MetadataServiceException {
         log.debug("endpoint update user password in database, databaseId={}, data.username={}", databaseId,
                 data.getUsername());
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         try {
             databaseService.update(database, data);
             return ResponseEntity.status(HttpStatus.ACCEPTED)
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java
similarity index 97%
rename from dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java
rename to dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java
index 87a4d32532c586c0f2517862f0cd3cc104f4f054..45cea4371c74f61d3cca69d70b08e8341c5e78d3 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java
@@ -11,7 +11,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-public abstract class AbstractEndpoint {
+public abstract class RestEndpoint {
 
     public boolean hasRole(Principal principal, String role) {
         if (principal == null || role == null) {
@@ -45,6 +45,7 @@ public abstract class AbstractEndpoint {
         return UUID.fromString(user.getId());
     }
 
+    /* FIXME: Heap may run OOM */
     public List<Map<String, Object>> transform(Dataset<Row> dataset) {
         return dataset.collectAsList()
                 .stream()
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 f30251a5ff09e895a7324a9857134c789f6b3c03..90cb9846b23f79ed4feb1d36e887886b88ad1a06 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
@@ -1,14 +1,16 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.ExportResourceDto;
+import at.tuwien.api.database.CreateViewDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewColumnDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.database.query.ExecuteStatementDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.database.query.QueryPersistDto;
 import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.exception.*;
+import at.tuwien.mapper.MariaDbMapper;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.*;
 import at.tuwien.validation.EndpointValidator;
@@ -46,25 +48,27 @@ import java.util.UUID;
 @RestController
 @CrossOrigin(origins = "*")
 @RequestMapping(path = "/api/database/{databaseId}/subset")
-public class SubsetEndpoint extends AbstractEndpoint {
+public class SubsetEndpoint extends RestEndpoint {
 
-    private final SchemaService schemaService;
+    private final MariaDbMapper mariaDbMapper;
     private final SubsetService subsetService;
     private final MetadataMapper metadataMapper;
     private final MetricsService metricsService;
     private final StorageService storageService;
+    private final DatabaseService databaseService;
     private final CredentialService credentialService;
     private final EndpointValidator endpointValidator;
 
     @Autowired
-    public SubsetEndpoint(SchemaService schemaService, SubsetService subsetService, MetadataMapper metadataMapper,
-                          MetricsService metricsService, StorageService storageService,
+    public SubsetEndpoint(MariaDbMapper mariaDbMapper, SubsetService subsetService, MetadataMapper metadataMapper,
+                          MetricsService metricsService, StorageService storageService, DatabaseService databaseService,
                           CredentialService credentialService, EndpointValidator endpointValidator) {
-        this.schemaService = schemaService;
+        this.mariaDbMapper = mariaDbMapper;
         this.subsetService = subsetService;
         this.metadataMapper = metadataMapper;
         this.metricsService = metricsService;
         this.storageService = storageService;
+        this.databaseService = databaseService;
         this.credentialService = credentialService;
         this.endpointValidator = endpointValidator;
     }
@@ -102,7 +106,7 @@ public class SubsetEndpoint extends AbstractEndpoint {
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
             QueryNotFoundException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}", databaseId, filterPersisted);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
         final List<QueryDto> queries;
         try {
@@ -160,11 +164,10 @@ public class SubsetEndpoint extends AbstractEndpoint {
                                       Principal principal)
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
             QueryNotFoundException, FormatNotAvailableException, StorageUnavailableException, UserNotFoundException,
-            MetadataServiceException, TableNotFoundException, ViewMalformedException, QueryMalformedException,
-            NotAllowedException {
+            MetadataServiceException, TableNotFoundException, QueryMalformedException, NotAllowedException {
         log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId,
                 subsetId, accept, timestamp);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
         final QueryDto subset;
         try {
@@ -188,20 +191,16 @@ public class SubsetEndpoint extends AbstractEndpoint {
                 return ResponseEntity.ok(subset);
             case "text/csv":
                 log.trace("accept header matches csv");
-                try {
-                    final Dataset<Row> dataset = subsetService.getData(database, subset, null, null);
-                    metricsService.countSubsetGetData(databaseId, subsetId);
-                    final ExportResourceDto resource = storageService.transformDataset(dataset);
-                    final HttpHeaders headers = new HttpHeaders();
-                    headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
-                    log.trace("export table resulted in resource {}", resource);
-                    return ResponseEntity.ok()
-                            .headers(headers)
-                            .body(resource.getResource());
-                } catch (SQLException e) {
-                    log.error("Failed to find data: {}", e.getMessage());
-                    throw new DatabaseUnavailableException("Failed to find data: " + e.getMessage(), e);
-                }
+                final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, null, null);
+                final Dataset<Row> dataset = subsetService.getData(database, query, timestamp, null, null, null, null);
+                metricsService.countSubsetGetData(databaseId, subsetId);
+                final ExportResourceDto resource = storageService.transformDataset(dataset);
+                final HttpHeaders headers = new HttpHeaders();
+                headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
+                log.trace("export table resulted in resource {}", resource);
+                return ResponseEntity.ok()
+                        .headers(headers)
+                        .body(resource.getResource());
         }
         throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead");
     }
@@ -286,11 +285,11 @@ public class SubsetEndpoint extends AbstractEndpoint {
             log.debug("timestamp not set: default to {}", timestamp);
         }
         /* create */
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
         try {
             final Long subsetId = subsetService.create(database, data.getStatement(), timestamp, userId);
-            return getData(databaseId, subsetId, principal, request, page, size);
+            return getData(databaseId, subsetId, principal, request, timestamp, page, size);
         } 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);
@@ -337,15 +336,16 @@ public class SubsetEndpoint extends AbstractEndpoint {
                                                              @NotNull @PathVariable("subsetId") Long subsetId,
                                                              Principal principal,
                                                              @NotNull HttpServletRequest request,
+                                                             @RequestParam(required = false) Instant timestamp,
                                                              @RequestParam(required = false) Long page,
                                                              @RequestParam(required = false) Long size)
             throws PaginationException, DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException,
             QueryNotFoundException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
-            UserNotFoundException, MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException {
+            UserNotFoundException, MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException {
         log.debug("endpoint get subset data, databaseId={}, subsetId={}, principal.name={} page={}, size={}",
                 databaseId, subsetId, principal != null ? principal.getName() : null, page, size);
         endpointValidator.validateDataParams(page, size);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         if (!database.getIsPublic()) {
             if (principal == null) {
                 log.error("Failed to re-execute query: no authentication found");
@@ -363,6 +363,10 @@ public class SubsetEndpoint extends AbstractEndpoint {
             size = 10L;
             log.debug("size not set: default to {}", size);
         }
+        if (timestamp == null) {
+            timestamp = Instant.now();
+            log.debug("timestamp not set: default to {}", timestamp);
+        }
         try {
             final HttpHeaders headers = new HttpHeaders();
             headers.set("X-Id", "" + subsetId);
@@ -375,9 +379,17 @@ public class SubsetEndpoint extends AbstractEndpoint {
                         .headers(headers)
                         .build();
             }
-            final Dataset<Row> dataset = subsetService.getData(database, subset, page, size);
+            final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, page, size);
+            final Dataset<Row> dataset = subsetService.getData(database, query, timestamp, page, size, null, null);
             metricsService.countSubsetGetData(databaseId, subsetId);
-            final ViewDto view = schemaService.inspectView(database, metadataMapper.queryDtoToViewName(subset));
+            final String viewName = metadataMapper.queryDtoToViewName(subset);
+            databaseService.createView(database, CreateViewDto.builder()
+                    .name(viewName)
+                    .isPublic(false)
+                    .isSchemaPublic(false)
+                    .query(query)
+                    .build());
+            final ViewDto view = databaseService.inspectView(database, viewName);
             headers.set("Access-Control-Expose-Headers", "X-Id X-Headers");
             headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList()));
             return ResponseEntity.status(request.getMethod().equals("POST") ? HttpStatus.CREATED : HttpStatus.OK)
@@ -435,7 +447,7 @@ public class SubsetEndpoint extends AbstractEndpoint {
             DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException {
         log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId,
                 queryId, data.getPersist(), principal.getName());
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         credentialService.getAccess(databaseId, getId(principal));
         try {
             subsetService.persist(database, queryId, data.getPersist());
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 f0ec00a035e729157726b65af9f3c85949581c4e..82ed0a96f7596e025301f11e6ebceed2cd393acc 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
@@ -3,15 +3,14 @@ package at.tuwien.endpoints;
 import at.tuwien.ExportResourceDto;
 import at.tuwien.api.database.DatabaseAccessDto;
 import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.database.query.ImportDto;
 import at.tuwien.api.database.table.*;
 import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.database.table.internal.TableCreateDto;
 import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
+import at.tuwien.mapper.MariaDbMapper;
 import at.tuwien.service.*;
 import at.tuwien.validation.EndpointValidator;
 import io.micrometer.observation.annotation.Observed;
@@ -47,24 +46,29 @@ import java.util.Map;
 @RestController
 @CrossOrigin(origins = "*")
 @RequestMapping(path = "/api/database/{databaseId}/table")
-public class TableEndpoint extends AbstractEndpoint {
+public class TableEndpoint extends RestEndpoint {
 
     private final TableService tableService;
-    private final SchemaService schemaService;
+    private final MariaDbMapper mariaDbMapper;
+    private final SubsetService subsetService;
     private final MetricsService metricsService;
     private final StorageService storageService;
+    private final DatabaseService databaseService;
     private final CredentialService credentialService;
     private final EndpointValidator endpointValidator;
     private final MetadataServiceGateway metadataServiceGateway;
 
     @Autowired
-    public TableEndpoint(TableService tableService, SchemaService schemaService, MetricsService metricsService,
-                         StorageService storageService, CredentialService credentialService,
-                         EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) {
+    public TableEndpoint(TableService tableService, MariaDbMapper mariaDbMapper, SubsetService subsetService,
+                         MetricsService metricsService, StorageService storageService, DatabaseService databaseService,
+                         CredentialService credentialService, EndpointValidator endpointValidator,
+                         MetadataServiceGateway metadataServiceGateway) {
         this.tableService = tableService;
-        this.schemaService = schemaService;
+        this.mariaDbMapper = mariaDbMapper;
+        this.subsetService = subsetService;
         this.metricsService = metricsService;
         this.storageService = storageService;
+        this.databaseService = databaseService;
         this.credentialService = credentialService;
         this.endpointValidator = endpointValidator;
         this.metadataServiceGateway = metadataServiceGateway;
@@ -113,11 +117,11 @@ public class TableEndpoint extends AbstractEndpoint {
             throw new TableMalformedException("Table must have a primary key");
         }
         /* create */
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         try {
-            final TableDto table = tableService.createTable(database, data);
+            final TableDto table = databaseService.createTable(database, data);
             return ResponseEntity.status(HttpStatus.CREATED)
-                    .body(schemaService.inspectTable(database, table.getInternalName()));
+                    .body(databaseService.inspectTable(database, table.getInternalName()));
         } 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);
@@ -157,7 +161,7 @@ public class TableEndpoint extends AbstractEndpoint {
             TableMalformedException, DatabaseUnavailableException, TableNotFoundException, MetadataServiceException {
         log.debug("endpoint update table, databaseId={}, data.description={}", databaseId, data.getDescription());
         /* create */
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         try {
             tableService.updateTable(table, data);
             return ResponseEntity.status(HttpStatus.ACCEPTED)
@@ -200,7 +204,7 @@ public class TableEndpoint extends AbstractEndpoint {
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             QueryMalformedException, MetadataServiceException {
         log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId);
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         try {
             tableService.delete(table);
             return ResponseEntity.status(HttpStatus.ACCEPTED)
@@ -253,7 +257,7 @@ public class TableEndpoint extends AbstractEndpoint {
                                                              @NotNull HttpServletRequest request,
                                                              Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
-            PaginationException, MetadataServiceException, NotAllowedException {
+            PaginationException, MetadataServiceException, NotAllowedException, DatabaseNotFoundException {
         log.debug("endpoint get table data, databaseId={}, tableId={}, timestamp={}, page={}, size={}", databaseId,
                 tableId, timestamp, page, size);
         endpointValidator.validateDataParams(page, size);
@@ -270,7 +274,7 @@ public class TableEndpoint extends AbstractEndpoint {
             timestamp = Instant.now();
             log.debug("timestamp not set: default to {}", timestamp);
         }
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         if (!table.getIsPublic()) {
             if (principal == null) {
                 log.error("Failed find table data: authentication required");
@@ -289,8 +293,10 @@ public class TableEndpoint extends AbstractEndpoint {
             }
             headers.set("Access-Control-Expose-Headers", "X-Headers");
             headers.set("X-Headers", String.join(",", table.getColumns().stream().map(ColumnDto::getInternalName).toList()));
-            final Dataset<Row> dataset = tableService.getData(table.getDatabase(), table.getInternalName(), timestamp,
-                    null, null, null, null);
+            final String query = mariaDbMapper.defaultRawSelectQuery(table.getDatabase().getInternalName(),
+                    table.getInternalName(), timestamp, page, size);
+            final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(table.getTdbid()),
+                    query, timestamp, page, size, null, null);
             metricsService.countTableGetData(databaseId, tableId);
             return ResponseEntity.ok()
                     .headers(headers)
@@ -340,7 +346,7 @@ public class TableEndpoint extends AbstractEndpoint {
             TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException,
             StorageNotFoundException, MetadataServiceException {
         log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId);
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal));
         endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
         try {
@@ -393,7 +399,7 @@ public class TableEndpoint extends AbstractEndpoint {
             TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
                 data.getKeys());
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal));
         endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
         try {
@@ -446,7 +452,7 @@ public class TableEndpoint extends AbstractEndpoint {
             TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
                 data.getKeys());
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal));
         endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
         try {
@@ -506,7 +512,7 @@ public class TableEndpoint extends AbstractEndpoint {
             log.debug("size not set: default to 100L");
             size = 100L;
         }
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         if (!table.getIsPublic()) {
             if (principal == null) {
                 log.error("Failed to find table history: no authentication found");
@@ -565,9 +571,9 @@ public class TableEndpoint extends AbstractEndpoint {
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
             DatabaseMalformedException, TableNotFoundException, MetadataServiceException {
         log.debug("endpoint inspect table schemas, databaseId={}", databaseId);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         try {
-            return ResponseEntity.ok(tableService.getSchemas(database));
+            return ResponseEntity.ok(databaseService.exploreTables(database));
         } 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);
@@ -611,14 +617,14 @@ public class TableEndpoint extends AbstractEndpoint {
                                                              @RequestParam(required = false) Instant timestamp,
                                                              Principal principal)
             throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException,
-            QueryMalformedException, MetadataServiceException {
+            QueryMalformedException, MetadataServiceException, DatabaseNotFoundException {
         log.debug("endpoint export table data, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp);
         /* parameters */
         if (timestamp == null) {
             timestamp = Instant.now();
             log.debug("timestamp not set: default to {}", timestamp);
         }
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         if (!table.getIsPublic()) {
             if (principal == null) {
                 log.error("Failed to export private table: principal is null");
@@ -626,8 +632,10 @@ public class TableEndpoint extends AbstractEndpoint {
             }
             credentialService.getAccess(databaseId, getId(principal));
         }
-        final Dataset<Row> dataset = tableService.getData(table.getDatabase(), table.getInternalName(), timestamp, null,
-                null, null, null);
+        final String query = mariaDbMapper.defaultRawSelectQuery(table.getDatabase().getInternalName(),
+                table.getInternalName(), timestamp, null, null);
+        final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(table.getTdbid()),
+                query, timestamp, null, null, null, null);
         metricsService.countTableGetData(databaseId, tableId);
         final ExportResourceDto resource = storageService.transformDataset(dataset);
         final HttpHeaders headers = new HttpHeaders();
@@ -677,7 +685,7 @@ public class TableEndpoint extends AbstractEndpoint {
             StorageNotFoundException, MalformedException, StorageUnavailableException, QueryMalformedException,
             DatabaseUnavailableException {
         log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation());
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
+        final TableDto table = credentialService.getTable(databaseId, tableId);
         final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal));
         endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
         if (data.getLineTermination() == null) {
@@ -727,9 +735,9 @@ public class TableEndpoint extends AbstractEndpoint {
             throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
             MetadataServiceException, TableMalformedException {
         log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId);
-        final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId);
         try {
-            return ResponseEntity.ok(tableService.getStatistics(table));
+            return ResponseEntity.ok(tableService.getStatistics(
+                    credentialService.getTable(databaseId, tableId)));
         } 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 2b0463483d66429dfb0afd942bbc80ccdfb2fd26..25dfd50dd434df444a45c4f7850fcdd803f0e9de 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
@@ -1,13 +1,13 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.ExportResourceDto;
+import at.tuwien.api.database.CreateViewDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewColumnDto;
-import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
 import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.exception.*;
+import at.tuwien.mapper.MariaDbMapper;
 import at.tuwien.service.*;
 import at.tuwien.validation.EndpointValidator;
 import io.micrometer.observation.annotation.Observed;
@@ -42,23 +42,30 @@ import java.util.Map;
 @RestController
 @CrossOrigin(origins = "*")
 @RequestMapping(path = "/api/database/{databaseId}/view")
-public class ViewEndpoint extends AbstractEndpoint {
+public class ViewEndpoint extends RestEndpoint {
 
     private final ViewService viewService;
     private final TableService tableService;
+    private final MariaDbMapper mariaDbMapper;
+    private final SubsetService subsetService;
     private final MetricsService metricsService;
     private final StorageService storageService;
+    private final DatabaseService databaseService;
     private final CredentialService credentialService;
     private final EndpointValidator endpointValidator;
 
     @Autowired
-    public ViewEndpoint(ViewService viewService, TableService tableService, MetricsService metricsService,
-                        StorageService storageService, CredentialService credentialService,
+    public ViewEndpoint(ViewService viewService, TableService tableService, MariaDbMapper mariaDbMapper,
+                        SubsetService subsetService, MetricsService metricsService, StorageService storageService,
+                        DatabaseService databaseService, CredentialService credentialService,
                         EndpointValidator endpointValidator) {
         this.viewService = viewService;
         this.tableService = tableService;
+        this.mariaDbMapper = mariaDbMapper;
+        this.subsetService = subsetService;
         this.metricsService = metricsService;
         this.storageService = storageService;
+        this.databaseService = databaseService;
         this.credentialService = credentialService;
         this.endpointValidator = endpointValidator;
     }
@@ -102,11 +109,11 @@ public class ViewEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<List<ViewDto>> getSchema(@NotNull @PathVariable("databaseId") Long databaseId)
             throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
-            ViewNotFoundException, DatabaseMalformedException, MetadataServiceException {
+            DatabaseMalformedException, MetadataServiceException, ViewNotFoundException {
         log.debug("endpoint inspect view schemas, databaseId={}", databaseId);
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         try {
-            return ResponseEntity.ok(viewService.getSchemas(database));
+            return ResponseEntity.ok(databaseService.exploreViews(database));
         } 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);
@@ -146,13 +153,13 @@ public class ViewEndpoint extends AbstractEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
-                                          @Valid @RequestBody ViewCreateDto data) throws DatabaseUnavailableException,
+                                          @Valid @RequestBody CreateViewDto data) throws DatabaseUnavailableException,
             DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException {
         log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName());
-        final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId);
+        final DatabaseDto database = credentialService.getDatabase(databaseId);
         try {
             return ResponseEntity.status(HttpStatus.CREATED)
-                    .body(viewService.create(database, data));
+                    .body(databaseService.createView(database, data));
         } 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);
@@ -193,9 +200,9 @@ public class ViewEndpoint extends AbstractEndpoint {
             throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException,
             ViewMalformedException, MetadataServiceException {
         log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId);
-        final PrivilegedViewDto view = credentialService.getView(databaseId, viewId);
+        final ViewDto view = credentialService.getView(databaseId, viewId);
         try {
-            viewService.delete(view.getDatabase(), view.getInternalName());
+            viewService.delete(view);
             return ResponseEntity.status(HttpStatus.ACCEPTED)
                     .build();
         } catch (SQLException e) {
@@ -207,7 +214,7 @@ public class ViewEndpoint extends AbstractEndpoint {
     @RequestMapping(value = "/{viewId}/data", method = {RequestMethod.GET, RequestMethod.HEAD})
     @Observed(name = "dbrepo_view_data")
     @Operation(summary = "Get view data",
-            description = "Gets data from a view of a database. For private databases, the user needs at least *READ* access to the associated database. Requires role `view-database-view-data`.",
+            description = "Gets data from a view of a database. For private databases, the user needs at least *READ* access to the associated database.",
             security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "200",
@@ -251,7 +258,7 @@ public class ViewEndpoint extends AbstractEndpoint {
                                                              @NotNull HttpServletRequest request,
                                                              Principal principal)
             throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, PaginationException,
-            QueryMalformedException, NotAllowedException, MetadataServiceException, TableNotFoundException {
+            QueryMalformedException, NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException {
         log.debug("endpoint get view data, databaseId={}, viewId={}, page={}, size={}, timestamp={}", databaseId,
                 viewId, page, size, timestamp);
         endpointValidator.validateDataParams(page, size);
@@ -268,7 +275,7 @@ public class ViewEndpoint extends AbstractEndpoint {
             timestamp = Instant.now();
             log.debug("timestamp not set: default to {}", timestamp);
         }
-        final PrivilegedViewDto view = credentialService.getView(databaseId, viewId);
+        final ViewDto view = credentialService.getView(databaseId, viewId);
         if (!view.getIsPublic()) {
             if (principal == null) {
                 log.error("Failed to get data from view: unauthorized");
@@ -287,8 +294,10 @@ public class ViewEndpoint extends AbstractEndpoint {
             }
             headers.set("Access-Control-Expose-Headers", "X-Headers");
             headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList()));
-            final Dataset<Row> dataset = tableService.getData(view.getDatabase(), view.getInternalName(), timestamp,
-                    page, size, null, null);
+            final String query = mariaDbMapper.defaultRawSelectQuery(view.getDatabase().getInternalName(),
+                    view.getInternalName(), timestamp, page, size);
+            final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(databaseId),
+                    query, timestamp, page, size, null, null);
             metricsService.countViewGetData(databaseId, viewId);
             return ResponseEntity.ok()
                     .headers(headers)
@@ -336,7 +345,7 @@ public class ViewEndpoint extends AbstractEndpoint {
                                                              @RequestParam(required = false) Instant timestamp,
                                                              Principal principal)
             throws RemoteUnavailableException, ViewNotFoundException, NotAllowedException, MetadataServiceException,
-            StorageUnavailableException, QueryMalformedException, TableNotFoundException {
+            StorageUnavailableException, QueryMalformedException, TableNotFoundException, DatabaseNotFoundException {
         log.debug("endpoint export view data, databaseId={}, viewId={}", databaseId, viewId);
         /* parameters */
         if (timestamp == null) {
@@ -344,7 +353,7 @@ public class ViewEndpoint extends AbstractEndpoint {
             log.debug("timestamp not set: default to {}", timestamp);
         }
         /* parameters */
-        final PrivilegedViewDto view = credentialService.getView(databaseId, viewId);
+        final ViewDto view = credentialService.getView(databaseId, viewId);
         if (!view.getIsPublic()) {
             if (principal == null) {
                 log.error("Failed to export private view: principal is null");
@@ -352,8 +361,10 @@ public class ViewEndpoint extends AbstractEndpoint {
             }
             credentialService.getAccess(databaseId, getId(principal));
         }
-        final Dataset<Row> dataset = tableService.getData(view.getDatabase(), view.getInternalName(), timestamp, null,
-                null, null, null);
+        final String query = mariaDbMapper.defaultRawSelectQuery(view.getDatabase().getInternalName(),
+                view.getInternalName(), timestamp, null, null);
+        final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(databaseId),
+                query, timestamp, null, null, null, null);
         metricsService.countViewGetData(databaseId, viewId);
         final ExportResourceDto resource = storageService.transformDataset(dataset);
         final HttpHeaders headers = new HttpHeaders();
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 25b858f51bd3f643f7879b9eac2dbb648b00aabb..9ad13f5be68bf6714f5d18fec4973fe9898b38f6 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
@@ -2,11 +2,11 @@ package at.tuwien.validation;
 
 import at.tuwien.api.database.AccessTypeDto;
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.config.QueryConfig;
-import at.tuwien.endpoints.AbstractEndpoint;
+import at.tuwien.endpoints.RestEndpoint;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.MetadataServiceGateway;
+import at.tuwien.service.CredentialService;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -21,15 +21,15 @@ import java.util.regex.Pattern;
 
 @Log4j2
 @Component
-public class EndpointValidator extends AbstractEndpoint {
+public class EndpointValidator extends RestEndpoint {
 
     private final QueryConfig queryConfig;
-    private final MetadataServiceGateway metadataServiceGateway;
+    private final CredentialService credentialService;
 
     @Autowired
-    public EndpointValidator(QueryConfig queryConfig, MetadataServiceGateway metadataServiceGateway) {
+    public EndpointValidator(QueryConfig queryConfig, CredentialService credentialService) {
         this.queryConfig = queryConfig;
-        this.metadataServiceGateway = metadataServiceGateway;
+        this.credentialService = credentialService;
     }
 
     public void validateDataParams(Long page, Long size) throws PaginationException {
@@ -48,12 +48,12 @@ public class EndpointValidator extends AbstractEndpoint {
         }
     }
 
-    public void validateOnlyPrivateSchemaAccess(PrivilegedDatabaseDto database, Principal principal)
+    public void validateOnlyPrivateSchemaAccess(DatabaseDto database, Principal principal)
             throws NotAllowedException, RemoteUnavailableException, MetadataServiceException {
         validateOnlyPrivateSchemaAccess(database, principal, false);
     }
 
-    public void validateOnlyPrivateSchemaAccess(PrivilegedDatabaseDto database, Principal principal,
+    public void validateOnlyPrivateSchemaAccess(DatabaseDto database, Principal principal,
                                                 boolean writeAccessOnly) throws NotAllowedException,
             RemoteUnavailableException, MetadataServiceException {
         if (database.getIsSchemaPublic()) {
@@ -63,7 +63,7 @@ public class EndpointValidator extends AbstractEndpoint {
         validateOnlyAccess(database, principal, writeAccessOnly);
     }
 
-    public void validateOnlyPrivateSchemaHasRole(PrivilegedDatabaseDto database, Principal principal, String role)
+    public void validateOnlyPrivateSchemaHasRole(DatabaseDto database, Principal principal, String role)
             throws NotAllowedException {
         if (database.getIsSchemaPublic()) {
             log.trace("database with id {} has public schema: no access needed", database.getId());
@@ -82,7 +82,7 @@ public class EndpointValidator extends AbstractEndpoint {
         log.trace("principal has role '{}': access granted", role);
     }
 
-    public void validateOnlyAccess(PrivilegedDatabaseDto database, Principal principal, boolean writeAccessOnly)
+    public void validateOnlyAccess(DatabaseDto database, Principal principal, boolean writeAccessOnly)
             throws NotAllowedException, RemoteUnavailableException, MetadataServiceException {
         if (principal == null) {
             throw new NotAllowedException("No principal provided");
@@ -90,7 +90,7 @@ public class EndpointValidator extends AbstractEndpoint {
         if (isSystem(principal)) {
             return;
         }
-        final DatabaseAccessDto access = metadataServiceGateway.getAccess(database.getId(), getId(principal));
+        final DatabaseAccessDto access = credentialService.getAccess(database.getId(), getId(principal));
         log.trace("found access: {}", access);
         if (writeAccessOnly && !(access.getType().equals(AccessTypeDto.WRITE_OWN) || access.getType().equals(AccessTypeDto.WRITE_ALL))) {
             log.error("Access not allowed: no write access");
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 a30ffb7b81ec455fc4eaa0ca11472eafa2c7aaf2..d4daa90741fa306a2d5c19093d5ad9ebe0d6ba2a 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
@@ -1,18 +1,14 @@
 package at.tuwien.config;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.database.query.QueryDto;
-import at.tuwien.api.database.table.columns.ColumnTypeDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
 
 import java.sql.*;
-import java.time.Instant;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -21,38 +17,7 @@ import java.util.regex.Pattern;
 @Configuration
 public class MariaDbConfig {
 
-    /**
-     * Inserts a query into a created database with given hostname and database name. The method uses the JDBC in-out
-     * notation <a href="#{@link}">{@link https://learn.microsoft.com/en-us/sql/connect/jdbc/using-sql-escape-sequences?view=sql-server-ver16#stored-procedure-calls}</a>
-     *
-     * @param database The database.
-     * @param query    The query.
-     * @param username The connection username.
-     * @param password The connection password.
-     * @return The generated or retrieved query id.
-     * @throws SQLException The procedure did not succeed.
-     */
-    public static Long mockSystemQueryInsert(PrivilegedDatabaseDto database, String query, String username, String password)
-            throws SQLException {
-        final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
-        log.trace("connect to database {}", jdbc);
-        try (Connection connection = DriverManager.getConnection(jdbc, username, password)) {
-            final String call = "{call _store_query(?,?,?,?)}";
-            log.trace("prepare procedure '{}'", call);
-            final CallableStatement statement = connection.prepareCall(call);
-            statement.setString(1, username);
-            statement.setString(2, query);
-            statement.setTimestamp(3, Timestamp.from(Instant.now()));
-            statement.registerOutParameter(4, Types.BIGINT);
-            statement.executeUpdate();
-            final Long queryId = statement.getLong(4);
-            statement.close();
-            log.debug("received queryId={}", queryId);
-            return queryId;
-        }
-    }
-
-    public static void createDatabase(PrivilegedContainerDto container, String database) throws SQLException {
+    public static void createDatabase(ContainerDto container, String database) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) {
@@ -65,7 +30,7 @@ public class MariaDbConfig {
         log.debug("created database {}", database);
     }
 
-    public static void createInitDatabase(PrivilegedContainerDto container, DatabaseDto database) throws SQLException {
+    public static void createInitDatabase(ContainerDto container, DatabaseDto database) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) {
@@ -76,21 +41,7 @@ public class MariaDbConfig {
         log.debug("created init database {}", database.getInternalName());
     }
 
-    public static void grantReadAccess(PrivilegedDatabaseDto database, String username) {
-        final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
-        log.trace("connect to database {}", jdbc);
-        try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
-            connection.prepareStatement("GRANT SELECT ON *.* TO `" + username + "`@`%`;")
-                    .executeUpdate();
-            connection.prepareStatement("FLUSH PRIVILEGES;")
-                    .executeUpdate();
-        } catch (SQLException e) {
-            log.error("could not grant read access", e);
-        }
-        log.debug("granted read access to user {} in database {}", username, database.getInternalName());
-    }
-
-    public static void grantWriteAccess(PrivilegedDatabaseDto database, String username) {
+    public static void grantWriteAccess(DatabaseDto database, String username) {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
@@ -104,7 +55,7 @@ public class MariaDbConfig {
         log.debug("granted read access to user {} in database {}", username, database.getInternalName());
     }
 
-    public static void dropAllDatabases(PrivilegedContainerDto container) {
+    public static void dropAllDatabases(ContainerDto container) {
         final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) {
@@ -130,7 +81,7 @@ public class MariaDbConfig {
         log.debug("dropped all databases");
     }
 
-    public static void dropDatabase(PrivilegedContainerDto container, String database)
+    public static void dropDatabase(ContainerDto container, String database)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort();
         log.trace("connect to database {}", jdbc);
@@ -144,26 +95,7 @@ public class MariaDbConfig {
         log.debug("dropped database {}", database);
     }
 
-    public static List<String> getUsernames(String hostname, String database, String username, String password)
-            throws SQLException {
-        final String jdbc = "jdbc:mariadb://" + hostname + "/" + database;
-        log.trace("connect to database {}", jdbc);
-        final List<String> usernames = new LinkedList<>();
-        try (Connection connection = DriverManager.getConnection(jdbc, username, password)) {
-            final String query = "SELECT User FROM mysql.user;";
-            log.trace("prepare statement '{}'", query);
-            final PreparedStatement statement = connection.prepareStatement(query);
-            final ResultSet set = statement.executeQuery();
-            statement.close();
-            while (set.next()) {
-                usernames.add(set.getString("User"));
-            }
-            log.debug("received usernames={}", usernames);
-            return usernames;
-        }
-    }
-
-    public static List<String> getPrivileges(PrivilegedDatabaseDto database, String username) throws SQLException {
+    public static List<String> getPrivileges(DatabaseDto database, String username) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
@@ -185,7 +117,7 @@ public class MariaDbConfig {
         throw new SQLException("Failed to get privileges");
     }
 
-    public static void dropTable(PrivilegedDatabaseDto database, String table) throws SQLException {
+    public static void dropTable(DatabaseDto database, String table) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
@@ -209,50 +141,7 @@ public class MariaDbConfig {
         }
     }
 
-    /**
-     * Inserts a query into a created database with given hostname and database name. The method uses the JDBC in-out
-     * notation <a href="#{@link}">{@link https://learn.microsoft.com/en-us/sql/connect/jdbc/using-sql-escape-sequences?view=sql-server-ver16#stored-procedure-calls}</a>
-     *
-     * @param database The database.
-     * @param query    The query.
-     * @param username The connection username.
-     * @param password The connection password.
-     * @return The generated or retrieved query id.
-     * @throws SQLException The procedure did not succeed.
-     */
-    public static Long mockUserQueryInsert(PrivilegedDatabaseDto database, String query, String username, String password)
-            throws SQLException {
-        final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
-        log.trace("connect to database: {}", jdbc);
-        try (Connection connection = DriverManager.getConnection(jdbc, username, password)) {
-            final String call = "{call store_query(?,?,?)}";
-            log.trace("prepare procedure '{}'", call);
-            final CallableStatement statement = connection.prepareCall(call);
-            statement.setString(1, query);
-            statement.setTimestamp(2, Timestamp.from(Instant.now()));
-            statement.registerOutParameter(3, Types.BIGINT);
-            statement.executeUpdate();
-            final Long queryId = statement.getLong(3);
-            statement.close();
-            log.debug("received queryId={}", queryId);
-            return queryId;
-        }
-    }
-
-    /**
-     * Inserts a query into a created database with given hostname and database name. The method uses the JDBC in-out
-     * notation <a href="#{@link}">{@link https://learn.microsoft.com/en-us/sql/connect/jdbc/using-sql-escape-sequences?view=sql-server-ver16#stored-procedure-calls}</a>
-     *
-     * @param database The database.
-     * @param query    The query.
-     * @return The generated or retrieved query id.
-     * @throws SQLException The procedure did not succeed.
-     */
-    public static Long mockSystemQueryInsert(PrivilegedDatabaseDto database, String query) throws SQLException {
-        return mockSystemQueryInsert(database, query, database.getContainer().getUsername(), database.getContainer().getPassword());
-    }
-
-    public static void insertQueryStore(PrivilegedDatabaseDto database, QueryDto query, UUID userId) throws SQLException {
+    public static void insertQueryStore(DatabaseDto database, QueryDto query, UUID userId) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database: {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
@@ -272,7 +161,7 @@ public class MariaDbConfig {
         }
     }
 
-    public static List<Map<String, Object>> listQueryStore(PrivilegedDatabaseDto database) throws SQLException {
+    public static List<Map<String, Object>> listQueryStore(DatabaseDto database) throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database {}", jdbc);
         try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
@@ -297,7 +186,7 @@ public class MariaDbConfig {
         }
     }
 
-    public static List<Map<String, String>> selectQuery(PrivilegedDatabaseDto database, String query, Set<String> columns)
+    public static List<Map<String, String>> selectQuery(DatabaseDto 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);
@@ -318,7 +207,7 @@ public class MariaDbConfig {
         return rows;
     }
 
-    public static List<Map<String, byte[]>> selectQueryByteArr(PrivilegedDatabaseDto database, String query, Set<String> columns)
+    public static List<Map<String, byte[]>> selectQueryByteArr(DatabaseDto 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);
@@ -339,7 +228,7 @@ public class MariaDbConfig {
         return rows;
     }
 
-    public static void execute(PrivilegedDatabaseDto database, String query)
+    public static void execute(DatabaseDto database, String query)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database {}", jdbc);
@@ -349,17 +238,7 @@ public class MariaDbConfig {
         }
     }
 
-    public static void execute(PrivilegedContainerDto container, String query)
-            throws SQLException {
-        final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort();
-        log.trace("connect to database: {}", jdbc);
-        try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) {
-            final Statement statement = connection.createStatement();
-            statement.executeUpdate(query);
-        }
-    }
-
-    public static void dropQueryStore(PrivilegedDatabaseDto database)
+    public static void dropQueryStore(DatabaseDto database)
             throws SQLException {
         final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
         log.trace("connect to database: {}", jdbc);
@@ -373,78 +252,4 @@ public class MariaDbConfig {
         }
     }
 
-    public static Map<String, List<Object>> describeTableSchema(PrivilegedTableDto table, String username, String password)
-            throws SQLException {
-        final String jdbc = "jdbc:mariadb://" + table.getDatabase().getContainer().getHost() + ":" + table.getDatabase().getContainer().getPort() + "/" + table.getDatabase().getInternalName();
-        log.trace("connect to database {}", jdbc);
-        final Map<String, List<Object>> out = new HashMap<>();
-        try (Connection connection = DriverManager.getConnection(jdbc, username, password)) {
-            final String query = "SHOW COLUMNS FROM `" + table.getInternalName() + "`;";
-            log.trace("prepare statement '{}'", query);
-            final PreparedStatement statement = connection.prepareStatement(query);
-            final ResultSet resultSet = statement.executeQuery();
-            statement.close();
-            while (resultSet.next()) {
-                if (resultSet.getString("Field").equals("id")) {
-                    continue;
-                }
-                out.put(resultSet.getString("Field"), List.of(resultSet.getString("Type"), resultSet.getString("Null"), resultSet.getString("Key")));
-            }
-            return out;
-        }
-    }
-
-    public static ColumnTypeDto typetoColumnTypeDto(String data) throws Exception {
-        if (data.toUpperCase().startsWith("TINYINT(1)")) {
-            /* boolean in MySQL */
-            return ColumnTypeDto.BOOL;
-        }
-        final Matcher matcher = Pattern.compile("([A-Z]+)")
-                .matcher(data.toUpperCase());
-        if (!matcher.find()) {
-            log.error("Failed to map type: does not match expected format");
-            throw new Exception("Failed to map type: does not match expected format");
-        }
-        final String type = matcher.group(1);
-        try {
-            return ColumnTypeDto.valueOf(type);
-        } catch (IllegalArgumentException e) {
-            if (type.startsWith("TINYINT")) {
-                /* boolean in MySQL */
-                return ColumnTypeDto.BOOL;
-            } else if (type.startsWith("BOOL")) {
-                /* boolean */
-                return ColumnTypeDto.BOOL;
-            } else if (type.startsWith("DOUBLE")) {
-                /* double precision */
-                return ColumnTypeDto.DOUBLE;
-            } else if (type.startsWith("INT")) {
-                /* integer synonym */
-                return ColumnTypeDto.INT;
-            } else if (type.startsWith("DEC")) {
-                /* decimal synonym */
-                return ColumnTypeDto.DECIMAL;
-            } else if (type.startsWith("ENUM")) {
-                return ColumnTypeDto.ENUM;
-            } else if (type.startsWith("SET")) {
-                return ColumnTypeDto.SET;
-            }
-        }
-        log.error("Failed to map data {} and type {}", data, type);
-        throw new Exception("Failed to map data " + data + " and type " + type);
-    }
-
-    public static boolean tableExists(PrivilegedDatabaseDto database, String tableName)
-            throws SQLException {
-        final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
-        log.trace("connect to database {}", jdbc);
-        try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
-            final Statement statement = connection.createStatement();
-            final String query = "SHOW TABLES LIKE '" + tableName + "';";
-            log.trace("execute query {}", query);
-            final ResultSet result = statement.executeQuery(query);
-            return result.next();
-        }
-    }
-
 }
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 9fb4003dba35234f81cedf8334e74c8489268269..3cbdf09af1f7705b2dd3fa550c24770618ba99d1 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,8 +1,8 @@
 package at.tuwien.endpoint;
 
 import at.tuwien.api.database.AccessTypeDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.endpoints.AccessEndpoint;
 import at.tuwien.exception.*;
 import at.tuwien.service.AccessService;
@@ -53,7 +53,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_4_ID))
-                .thenReturn(USER_4_PRIVILEGED_DTO);
+                .thenReturn(USER_4_DTO);
 
         /* test */
         final ResponseEntity<Void> response = accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO);
@@ -70,7 +70,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+                .thenReturn(USER_1_DTO);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -87,10 +87,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_4_ID))
-                .thenReturn(USER_4_PRIVILEGED_DTO);
+                .thenReturn(USER_4_DTO);
         doThrow(SQLException.class)
                 .when(accessService)
-                .create(DATABASE_1_PRIVILEGED_DTO, USER_4_PRIVILEGED_DTO, AccessTypeDto.READ);
+                .create(DATABASE_1_PRIVILEGED_DTO, USER_4_DTO, AccessTypeDto.READ);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -151,7 +151,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+                .thenReturn(USER_1_DTO);
 
         /* test */
         final ResponseEntity<Void> response = accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO);
@@ -168,10 +168,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+                .thenReturn(USER_1_DTO);
         doThrow(SQLException.class)
                 .when(accessService)
-                .update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ);
+                .update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -188,7 +188,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_4_ID))
-                .thenReturn(USER_4_PRIVILEGED_DTO);
+                .thenReturn(USER_4_DTO);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -250,10 +250,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+                .thenReturn(USER_1_DTO);
         doNothing()
                 .when(accessService)
-                .delete(any(PrivilegedDatabaseDto.class), any(PrivilegedUserDto.class));
+                .delete(any(DatabaseDto.class), any(UserDto.class));
 
         /* test */
         final ResponseEntity<Void> response = accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID);
@@ -270,7 +270,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_4_ID))
-                .thenReturn(USER_4_PRIVILEGED_DTO);
+                .thenReturn(USER_4_DTO);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -331,10 +331,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getUser(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+                .thenReturn(USER_1_DTO);
         doThrow(SQLException.class)
                 .when(accessService)
-                .delete(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO);
+                .delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
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 c55442290ec1d17336dd73ac1dd4574f33e689a4..43f7b9353e0381a6bc001b1a563036e20e8daae1 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
@@ -2,13 +2,13 @@ package at.tuwien.endpoint;
 
 import at.tuwien.api.database.AccessTypeDto;
 import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.endpoints.DatabaseEndpoint;
 import at.tuwien.exception.*;
 import at.tuwien.service.AccessService;
+import at.tuwien.service.ContainerService;
 import at.tuwien.service.CredentialService;
 import at.tuwien.service.DatabaseService;
-import at.tuwien.service.SubsetService;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -39,7 +39,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     private DatabaseEndpoint databaseEndpoint;
 
     @MockBean
-    private SubsetService queryService;
+    private ContainerService containerService;
 
     @MockBean
     private AccessService accessService;
@@ -63,15 +63,15 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
         /* mock */
         when(credentialService.getContainer(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL))
+                .thenReturn(CONTAINER_1_DTO);
+        when(containerService.createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doNothing()
-                .when(queryService)
-                .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+                .when(containerService)
+                .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME);
         doNothing()
                 .when(accessService)
-                .create(eq(DATABASE_1_PRIVILEGED_DTO), any(PrivilegedUserDto.class), any(AccessTypeDto.class));
+                .create(eq(DATABASE_1_PRIVILEGED_DTO), any(UserDto.class), any(AccessTypeDto.class));
 
         /* test */
         final ResponseEntity<DatabaseDto> response = databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL);
@@ -85,15 +85,15 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
         /* mock */
         when(credentialService.getContainer(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL))
+                .thenReturn(CONTAINER_1_DTO);
+        when(containerService.createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doNothing()
-                .when(queryService)
-                .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+                .when(containerService)
+                .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME);
         doNothing()
                 .when(accessService)
-                .create(eq(DATABASE_1_PRIVILEGED_DTO), any(PrivilegedUserDto.class), any(AccessTypeDto.class));
+                .create(eq(DATABASE_1_PRIVILEGED_DTO), any(UserDto.class), any(AccessTypeDto.class));
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
@@ -108,10 +108,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
         /* mock */
         when(credentialService.getContainer(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
+                .thenReturn(CONTAINER_1_DTO);
         doThrow(SQLException.class)
-                .when(databaseService)
-                .create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL);
+                .when(containerService)
+                .createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -144,11 +144,11 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         doThrow(ContainerNotFoundException.class)
                 .when(credentialService)
                 .getContainer(CONTAINER_1_ID);
-        when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL))
+        when(containerService.createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doThrow(QueryStoreCreateException.class)
-                .when(queryService)
-                .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+                .when(containerService)
+                .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME);
 
         /* test */
         assertThrows(ContainerNotFoundException.class, () -> {
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 8a08f8231fe0de7babf1db995dc60786407425f8..8837ccb0d1c96f3dff61c0826fcabb956ecdc914 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
@@ -1,14 +1,14 @@
 package at.tuwien.endpoint;
 
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.database.CreateViewDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.query.ExecuteStatementDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.database.query.QueryPersistDto;
 import at.tuwien.endpoints.SubsetEndpoint;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.service.CredentialService;
-import at.tuwien.service.SchemaService;
+import at.tuwien.service.DatabaseService;
 import at.tuwien.service.StorageService;
 import at.tuwien.service.SubsetService;
 import at.tuwien.test.AbstractUnitTest;
@@ -25,7 +25,6 @@ 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.mock.web.MockHttpServletRequest;
 import org.springframework.security.test.context.support.WithAnonymousUser;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -53,12 +52,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @MockBean
     private SubsetService subsetService;
 
-    @MockBean
-    private SchemaService schemaService;
-
-    @MockBean
-    private MetadataServiceGateway metadataServiceGateway;
-
     @MockBean
     private HttpServletRequest httpServletRequest;
 
@@ -66,10 +59,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     private StorageService storageService;
 
     @MockBean
-    private CredentialService credentialService;
+    private DatabaseService databaseService;
 
     @MockBean
-    private MockHttpServletRequest mockHttpServletRequest;
+    private CredentialService credentialService;
 
     @BeforeEach
     public void beforeEach() {
@@ -98,6 +91,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
             MetadataServiceException {
 
         /* mock */
+        when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
+                .thenReturn(DATABASE_3_USER_1_READ_ACCESS_DTO);
         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));
 
@@ -136,14 +131,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_privateDataPrivateSchemaAnonymous_fails() throws DatabaseNotFoundException, SQLException,
-            RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException {
+    public void findById_privateDataPrivateSchemaAnonymous_fails() throws DatabaseNotFoundException,
+            RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
-                .thenReturn(QUERY_1_DTO);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -214,10 +207,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
                 .thenReturn(QUERY_5_DTO);
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
+                .thenReturn(mock);
         when(storageService.transformDataset(any(Dataset.class)))
                 .thenReturn(EXPORT_RESOURCE_DTO);
-        when(subsetService.getData(any(PrivilegedDatabaseDto.class), any(QueryDto.class), eq(null), eq(null)))
-                .thenReturn(mock);
 
         /* test */
         generic_findById(DATABASE_1_ID, QUERY_1_ID, "text/csv", null, USER_1_PRINCIPAL);
@@ -226,20 +219,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void findById_publicDataPrivateSchemaAnonymous_fails() throws DatabaseNotFoundException,
-            RemoteUnavailableException, UserNotFoundException, StorageUnavailableException, QueryMalformedException,
-            QueryNotFoundException, SQLException, MetadataServiceException, TableNotFoundException,
-            ViewMalformedException {
-        final Dataset<Row> mock = sparkSession.emptyDataFrame();
+            RemoteUnavailableException, MetadataServiceException {
 
         /* mock */
         when(credentialService.getDatabase(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
-                .thenReturn(QUERY_5_DTO);
-        when(subsetService.getData(any(PrivilegedDatabaseDto.class), any(QueryDto.class), eq(null), eq(null)))
-                .thenReturn(mock);
-        when(storageService.transformDataset(any(Dataset.class)))
-                .thenReturn(EXPORT_RESOURCE_DTO);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -251,7 +235,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void findById_publicDataPublicSchemaAnonymous_fails() throws DatabaseNotFoundException, SQLException,
             RemoteUnavailableException, UserNotFoundException, QueryMalformedException, StorageUnavailableException,
-            QueryNotFoundException, MetadataServiceException, TableNotFoundException, ViewMalformedException {
+            QueryNotFoundException, MetadataServiceException, TableNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
@@ -259,7 +243,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
         when(subsetService.findById(DATABASE_4_PRIVILEGED_DTO, QUERY_5_ID))
                 .thenReturn(QUERY_5_DTO);
-        when(subsetService.getData(any(PrivilegedDatabaseDto.class), any(QueryDto.class), eq(null), eq(null)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
         when(storageService.transformDataset(any(Dataset.class)))
                 .thenReturn(EXPORT_RESOURCE_DTO);
@@ -304,29 +288,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void findById_publicDataPrivateSchemaUnavailableExport_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            MetadataServiceException, SQLException, QueryMalformedException, UserNotFoundException,
-            QueryNotFoundException, TableNotFoundException, ViewMalformedException, StorageUnavailableException {
-
-        /* mock */
-        when(credentialService.getDatabase(DATABASE_3_ID))
-                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID))
-                .thenReturn(QUERY_5_DTO);
-        when(storageService.transformDataset(any(Dataset.class)))
-                .thenReturn(EXPORT_RESOURCE_DTO);
-        doThrow(SQLException.class)
-                .when(subsetService)
-                .getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(QUERY_5_DTO), eq(null), eq(null));
-
-        /* test */
-        assertThrows(DatabaseUnavailableException.class, () -> {
-            generic_findById(DATABASE_3_ID, QUERY_5_ID, "text/csv", null, USER_1_PRINCIPAL);
-        });
-    }
-
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
     public void create_noAccess_succeeds() throws UserNotFoundException, QueryStoreInsertException,
@@ -342,12 +303,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getDatabase(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
         when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong()))
                 .thenReturn(QUERY_5_DTO);
-        when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_5_DTO);
+        when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
+                .thenReturn(QUERY_5_VIEW_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("POST");
 
@@ -388,12 +349,16 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getDatabase(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_5_DTO);
-        when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong()))
+        when(subsetService.create(any(DatabaseDto.class), eq(QUERY_5_STATEMENT), any(Instant.class), eq(USER_1_ID)))
+                .thenReturn(QUERY_5_ID);
+        when(subsetService.findById(any(DatabaseDto.class), eq(QUERY_5_ID)))
                 .thenReturn(QUERY_5_DTO);
-        when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
+        when(databaseService.createView(any(DatabaseDto.class), any(CreateViewDto.class)))
+                .thenReturn(QUERY_5_VIEW_DTO);
+        when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
+                .thenReturn(QUERY_5_VIEW_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("POST");
 
@@ -401,38 +366,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
     }
 
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
-    public void create_unavailable_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
-            SQLException, MetadataServiceException, QueryMalformedException, TableNotFoundException,
-            ViewMalformedException, UserNotFoundException, QueryNotFoundException, QueryStoreInsertException,
-            NotAllowedException {
-        final ExecuteStatementDto request = ExecuteStatementDto.builder()
-                .statement(QUERY_5_STATEMENT)
-                .build();
-
-        /* mock */
-        when(credentialService.getDatabase(DATABASE_3_ID))
-                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        doThrow(SQLException.class)
-                .when(subsetService)
-                .getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(null), eq(null));
-        when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong()))
-                .thenReturn(QUERY_5_DTO);
-        when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_1_ID))
-                .thenReturn(DATABASE_3_USER_1_READ_ACCESS_DTO);
-        doThrow(SQLException.class)
-                .when(subsetService)
-                .create(eq(DATABASE_3_PRIVILEGED_DTO), eq(QUERY_5_STATEMENT), any(Instant.class), eq(USER_1_ID));
-        when(httpServletRequest.getMethod())
-                .thenReturn("POST");
-
-        /* test */
-        assertThrows(DatabaseUnavailableException.class, () -> {
-            subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
-        });
-    }
-
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
     public void create_databaseNotFound_fails() throws RemoteUnavailableException,
@@ -454,34 +387,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
-    @Test
-    @WithMockUser(username = USER_4_USERNAME)
-    public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
-            MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException,
-            NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException,
-            StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, PaginationException,
-            StorageNotFoundException, TableNotFoundException, ViewMalformedException, ViewNotFoundException {
-        final Dataset<Row> mock = sparkSession.emptyDataFrame();
-        final ExecuteStatementDto request = ExecuteStatementDto.builder()
-                .statement(QUERY_5_STATEMENT)
-                .build();
-
-        /* mock */
-        when(credentialService.getDatabase(DATABASE_3_ID))
-                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
-                .thenReturn(mock);
-        when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong()))
-                .thenReturn(QUERY_5_DTO);
-        when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_5_DTO);
-        when(httpServletRequest.getMethod())
-                .thenReturn("POST");
-
-        /* test */
-        subsetEndpoint.create(DATABASE_3_ID, request, USER_4_PRINCIPAL, httpServletRequest, null, null, null);
-    }
-
     @Test
     @WithAnonymousUser
     public void create_publicDataPublicSchemaAnonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
@@ -499,10 +404,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_4_PRIVILEGED_DTO);
         when(subsetService.findById(eq(DATABASE_4_PRIVILEGED_DTO), anyLong()))
                 .thenReturn(QUERY_5_DTO);
-        when(subsetService.getData(eq(DATABASE_4_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
-        when(schemaService.inspectView(eq(DATABASE_4_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_5_DTO);
+        when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
+                .thenReturn(QUERY_5_VIEW_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("POST");
 
@@ -527,10 +432,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(subsetService.findById(eq(DATABASE_1_PRIVILEGED_DTO), anyLong()))
                 .thenReturn(QUERY_1_DTO);
-        when(subsetService.getData(eq(DATABASE_1_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
-        when(schemaService.inspectView(eq(DATABASE_1_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_1_DTO);
+        when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
+                .thenReturn(QUERY_1_VIEW_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("POST");
 
@@ -542,7 +447,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void create_privateDataPublicSchemaAnonymous_fails() throws DatabaseNotFoundException, SQLException,
             MetadataServiceException, UserNotFoundException, QueryNotFoundException, QueryMalformedException,
-            TableNotFoundException, ViewMalformedException, ViewNotFoundException, RemoteUnavailableException {
+            TableNotFoundException, RemoteUnavailableException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
         final ExecuteStatementDto request = ExecuteStatementDto.builder()
                 .statement(QUERY_5_STATEMENT)
@@ -553,10 +458,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_2_PRIVILEGED_DTO);
         when(subsetService.findById(eq(DATABASE_2_PRIVILEGED_DTO), anyLong()))
                 .thenReturn(QUERY_2_DTO);
-        when(subsetService.getData(eq(DATABASE_2_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
-        when(schemaService.inspectView(eq(DATABASE_2_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_4_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("POST");
 
@@ -570,7 +473,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
             NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException,
             DatabaseUnavailableException, PaginationException, MetadataServiceException, TableNotFoundException,
-            ViewMalformedException, ViewNotFoundException {
+            ViewNotFoundException, ViewMalformedException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
@@ -580,15 +483,15 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(QUERY_5_DTO);
         when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO))
                 .thenReturn(QUERY_5_RESULT_NUMBER);
-        when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
-        when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_5_DTO);
+        when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
+                .thenReturn(QUERY_5_VIEW_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
 
         /* test */
-        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null);
+        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
     }
@@ -597,7 +500,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void getData_head_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException,
             QueryMalformedException, DatabaseUnavailableException, PaginationException, MetadataServiceException,
-            TableNotFoundException, ViewMalformedException, ViewNotFoundException {
+            TableNotFoundException, ViewNotFoundException, ViewMalformedException {
 
         /* mock */
         when(credentialService.getDatabase(DATABASE_3_ID))
@@ -610,7 +513,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn("HEAD");
 
         /* test */
-        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null);
+        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getHeaders().get("X-Count"));
         assertEquals(1, response.getHeaders().get("X-Count").size());
@@ -622,7 +525,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException,
             QueryMalformedException, QueryNotFoundException, PaginationException, SQLException,
-            MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException {
+            MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
@@ -632,15 +535,15 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(QUERY_1_DTO);
         when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO))
                 .thenReturn(QUERY_1_RESULT_NUMBER);
-        when(subsetService.getData(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
-        when(schemaService.inspectView(eq(DATABASE_1_PRIVILEGED_DTO), anyString()))
-                .thenReturn(VIEW_1_DTO);
+        when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
+                .thenReturn(QUERY_1_VIEW_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
 
         /* test */
-        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null);
+        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
     }
@@ -656,7 +559,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, null, httpServletRequest, null, null);
+            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, null, httpServletRequest, null, null, null);
         });
     }
 
@@ -674,7 +577,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null);
+            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
         });
     }
 
@@ -683,7 +586,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
     public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
             UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException,
             QueryMalformedException, QueryNotFoundException, PaginationException, SQLException,
-            MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException {
+            MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException {
 
         /* mock */
         when(credentialService.getDatabase(DATABASE_1_ID))
@@ -696,36 +599,13 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn("HEAD");
 
         /* test */
-        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null);
+        final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getHeaders().get("X-Count"));
         assertEquals(1, response.getHeaders().get("X-Count").size());
         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, QueryNotFoundException, MetadataServiceException, QueryMalformedException,
-            TableNotFoundException, ViewMalformedException {
-
-        /* mock */
-        when(credentialService.getDatabase(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)
-                .getData(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L);
-
-        /* 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,
@@ -825,7 +705,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
-    protected List<QueryDto> generic_list(Long databaseId, PrivilegedDatabaseDto database, Principal principal)
+    protected List<QueryDto> generic_list(Long databaseId, DatabaseDto database, Principal principal)
             throws NotAllowedException, DatabaseUnavailableException, QueryNotFoundException, DatabaseNotFoundException,
             RemoteUnavailableException, MetadataServiceException {
 
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 e3171892a0be41f816feb749990a70aafc252f3d..b37007a0108946429481c7fa229eb575bc6e98f0 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,14 +1,15 @@
 package at.tuwien.endpoint;
 
 import at.tuwien.api.database.DatabaseAccessDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.query.ImportDto;
 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;
 import at.tuwien.service.CredentialService;
-import at.tuwien.service.SchemaService;
+import at.tuwien.service.DatabaseService;
+import at.tuwien.service.SubsetService;
 import at.tuwien.service.TableService;
 import at.tuwien.test.AbstractUnitTest;
 import jakarta.servlet.http.HttpServletRequest;
@@ -61,7 +62,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     private TableService tableService;
 
     @MockBean
-    private SchemaService schemaService;
+    private SubsetService subsetService;
+
+    @MockBean
+    private DatabaseService databaseService;
 
     @MockBean
     private CredentialService credentialService;
@@ -92,17 +96,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
-    public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException,
+    public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException, ViewNotFoundException,
             DatabaseNotFoundException, TableExistsException, RemoteUnavailableException, SQLException,
             TableNotFoundException, QueryMalformedException, MetadataServiceException, ContainerNotFoundException {
 
         /* mock */
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO))
-                .thenReturn(TABLE_4_DTO);
-        when(schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_INTERNALNAME))
-                .thenReturn(TABLE_4_DTO);
+        when(databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO))
+                .thenReturn(TABLE_4_PRIVILEGED_DTO);
+        when(databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_INTERNALNAME))
+                .thenReturn(TABLE_4_PRIVILEGED_DTO);
 
         /* test */
         final ResponseEntity<TableDto> response = tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO);
@@ -144,7 +148,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doThrow(SQLException.class)
-                .when(tableService)
+                .when(databaseService)
                 .createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO);
 
         /* test */
@@ -171,7 +175,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
-        when(tableService.getStatistics(any(PrivilegedTableDto.class)))
+        when(tableService.getStatistics(any(TableDto.class)))
                 .thenReturn(TABLE_8_STATISTIC_DTO);
 
         /* test */
@@ -189,7 +193,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
         doThrow(SQLException.class)
                 .when(tableService)
-                .getStatistics(any(PrivilegedTableDto.class));
+                .getStatistics(any(TableDto.class));
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -276,14 +280,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void getData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException,
-            RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException {
+    public void getData_publicDataPrivateSchema_succeeds() throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException,
+            RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException,
+            DatabaseNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
         when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
-        when(tableService.getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
+        when(credentialService.getDatabase(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
@@ -298,7 +305,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void getData_head_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
             SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException,
-            MetadataServiceException, NotAllowedException {
+            MetadataServiceException, NotAllowedException, DatabaseNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
@@ -306,7 +313,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
         when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class)))
                 .thenReturn(3L);
-        when(tableService.getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
+        when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
         when(httpServletRequest.getMethod())
                 .thenReturn("HEAD");
@@ -357,14 +364,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void getData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
-            MetadataServiceException, QueryMalformedException {
+            MetadataServiceException, QueryMalformedException, DatabaseNotFoundException {
 
         /* mock */
         when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
+        when(credentialService.getDatabase(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
         doThrow(QueryMalformedException.class)
-                .when(tableService)
-                .getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null));
+                .when(subsetService)
+                .getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null));
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
 
@@ -397,15 +406,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @MethodSource("anyAccess_parameters")
     public void getData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException,
             TableNotFoundException, QueryMalformedException, RemoteUnavailableException, PaginationException,
-            MetadataServiceException, NotAllowedException {
+            MetadataServiceException, NotAllowedException, DatabaseNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
         when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
+        when(credentialService.getDatabase(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
                 .thenReturn(access);
-        when(tableService.getData(eq(DATABASE_1_PRIVILEGED_DTO), eq(TABLE_1_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
@@ -1139,14 +1150,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void exportData_succeeds() throws TableNotFoundException, NotAllowedException,
-            StorageUnavailableException, QueryMalformedException, RemoteUnavailableException, MetadataServiceException {
+    public void exportData_publicDataPrivateSchema_succeeds() throws TableNotFoundException, NotAllowedException, StorageUnavailableException,
+            QueryMalformedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
         when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
                 .thenReturn(TABLE_8_PRIVILEGED_DTO);
-        when(tableService.getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
+        when(credentialService.getDatabase(DATABASE_3_ID))
+                .thenReturn(DATABASE_3_PRIVILEGED_DTO);
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
                 .thenReturn(mock);
 
         /* test */
@@ -1157,9 +1170,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @ParameterizedTest
     @WithMockUser(username = USER_2_USERNAME)
     @MethodSource("anyAccess_parameters")
-    public void exportData_private_succeeds(String name, DatabaseAccessDto access) throws TableNotFoundException,
-            NotAllowedException, StorageUnavailableException, QueryMalformedException, RemoteUnavailableException,
-            MetadataServiceException {
+    public void exportData_privateDataPrivateSchema_succeeds(String name, DatabaseAccessDto access)
+            throws TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException,
+            RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
@@ -1167,7 +1180,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
         when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
                 .thenReturn(access);
-        when(tableService.getData(eq(DATABASE_1_PRIVILEGED_DTO), eq(TABLE_1_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
+        when(credentialService.getDatabase(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null)))
                 .thenReturn(mock);
 
         /* test */
@@ -1202,8 +1217,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getDatabase(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
-        when(tableService.getSchemas(DATABASE_3_PRIVILEGED_DTO))
-                .thenReturn(List.of(TABLE_8_DTO));
+        when(databaseService.exploreTables(DATABASE_3_PRIVILEGED_DTO))
+                .thenReturn(List.of(TABLE_8_PRIVILEGED_DTO));
 
         /* test */
         final ResponseEntity<List<TableDto>> response = tableEndpoint.getSchema(DATABASE_3_ID);
@@ -1239,8 +1254,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_3_ID))
                 .thenReturn(DATABASE_3_PRIVILEGED_DTO);
         doThrow(SQLException.class)
-                .when(tableService)
-                .getSchemas(DATABASE_3_PRIVILEGED_DTO);
+                .when(databaseService)
+                .exploreTables(DATABASE_3_PRIVILEGED_DTO);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -1329,7 +1344,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
         doThrow(SQLException.class)
                 .when(tableService)
-                .importDataset(any(PrivilegedTableDto.class), eq(request));
+                .importDataset(any(TableDto.class), eq(request));
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -1355,7 +1370,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
         doThrow(SQLException.class)
                 .when(tableService)
-                .importDataset(any(PrivilegedTableDto.class), eq(request));
+                .importDataset(any(TableDto.class), eq(request));
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
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 5f580a2fc12156c6702b4b54e215dd979611b5f9..b003ebfb4fd427c0b6bd92aef0595915f5c2bdbd 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
@@ -1,10 +1,12 @@
 package at.tuwien.endpoint;
 
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.endpoints.ViewEndpoint;
 import at.tuwien.exception.*;
 import at.tuwien.service.CredentialService;
-import at.tuwien.service.TableService;
+import at.tuwien.service.DatabaseService;
+import at.tuwien.service.SubsetService;
 import at.tuwien.service.ViewService;
 import at.tuwien.test.AbstractUnitTest;
 import jakarta.servlet.http.HttpServletRequest;
@@ -40,6 +42,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @MockBean
     private ViewService viewService;
 
+    @MockBean
+    private DatabaseService databaseService;
+
     @MockBean
     private CredentialService credentialService;
 
@@ -47,7 +52,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     private HttpServletRequest httpServletRequest;
 
     @MockBean
-    private TableService tableService;
+    private SubsetService subsetService;
 
     @Autowired
     private ViewEndpoint viewEndpoint;
@@ -68,8 +73,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO))
-                .thenReturn(VIEW_1_DTO);
+        when(databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
 
         /* test */
         final ResponseEntity<ViewDto> response = viewEndpoint.create(DATABASE_1_ID, VIEW_1_CREATE_DTO);
@@ -85,8 +90,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doThrow(SQLException.class)
-                .when(viewService)
-                .create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO);
+                .when(databaseService)
+                .createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -102,8 +107,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO))
-                .thenReturn(VIEW_1_DTO);
+        when(databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
@@ -135,7 +140,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
-        when(viewService.getSchemas(DATABASE_1_PRIVILEGED_DTO))
+        when(databaseService.exploreViews(DATABASE_1_PRIVILEGED_DTO))
                 .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO));
 
         /* test */
@@ -178,8 +183,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         when(credentialService.getDatabase(DATABASE_1_ID))
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doThrow(SQLException.class)
-                .when(viewService)
-                .getSchemas(DATABASE_1_PRIVILEGED_DTO);
+                .when(databaseService)
+                .exploreViews(DATABASE_1_PRIVILEGED_DTO);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -207,7 +212,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doNothing()
                 .when(viewService)
-                .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME);
+                .delete(VIEW_1_PRIVILEGED_DTO);
 
         /* test */
         final ResponseEntity<Void> response = viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID);
@@ -224,7 +229,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(SQLException.class)
                 .when(viewService)
-                .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME);
+                .delete(VIEW_1_PRIVILEGED_DTO);
 
         /* test */
         assertThrows(DatabaseUnavailableException.class, () -> {
@@ -242,7 +247,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         doNothing()
                 .when(viewService)
-                .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME);
+                .delete(VIEW_1_PRIVILEGED_DTO);
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
@@ -268,17 +273,19 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
-    public void getData_private_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException,
+    public void getData_privateDataPrivateSchema_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
             SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException,
-            NotAllowedException, MetadataServiceException, TableNotFoundException {
+            NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException {
         final Dataset<Row> mock = sparkSession.emptyDataFrame();
 
         /* mock */
         when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
                 .thenReturn(VIEW_1_PRIVILEGED_DTO);
+        when(credentialService.getDatabase(DATABASE_1_ID))
+                .thenReturn(DATABASE_1_PRIVILEGED_DTO);
         when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID))
                 .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO);
-        when(tableService.getData(eq(DATABASE_1_PRIVILEGED_DTO), eq(VIEW_1_INTERNAL_NAME), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
+        when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)))
                 .thenReturn(mock);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
@@ -293,7 +300,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
     public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
             SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException,
-            NotAllowedException, MetadataServiceException, TableNotFoundException {
+            NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException {
 
         /* mock */
         when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
@@ -323,17 +330,17 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_1_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
+            viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL);
         });
     }
 
@@ -359,15 +366,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_3_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_3_PRINCIPAL);
+            viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL);
         });
     }
 
@@ -377,15 +384,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_3_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_3_ID, null, USER_3_PRINCIPAL);
+            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL);
         });
     }
 
@@ -411,15 +418,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_1_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_3_ID, null, USER_1_PRINCIPAL);
+            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL);
         });
     }
 
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java
index f65de0707eec016f502d66f45e8f52b5811f042f..affb56208032bc818ce5f1dbe1d99008613ffa32 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java
@@ -1,16 +1,12 @@
 package at.tuwien.gateway;
 
 import at.tuwien.api.container.ContainerDto;
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
 import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.identifier.IdentifierBriefDto;
 import at.tuwien.api.user.UserDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
 import at.tuwien.exception.*;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
@@ -40,10 +36,6 @@ import static org.mockito.Mockito.when;
 @ExtendWith(SpringExtension.class)
 public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
 
-    @MockBean
-    @Qualifier("restTemplate")
-    private RestTemplate restTemplate;
-
     @MockBean
     @Qualifier("internalRestTemplate")
     private RestTemplate internalRestTemplate;
@@ -60,28 +52,22 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     public void getTableById_succeeds() throws TableNotFoundException, RemoteUnavailableException,
             MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
-        headers.set("X-Type", IMAGE_1_JDBC);
-        headers.set("X-Host", CONTAINER_1_HOST);
-        headers.set("X-Port", "" + CONTAINER_1_PORT);
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
-        headers.set("X-Database", DATABASE_1_INTERNALNAME);
-        headers.set("X-Table", TABLE_1_INTERNAL_NAME);
 
         /* mock */
         when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .headers(headers)
-                        .body(TABLE_1_DTO));
+                        .body(TABLE_1_PRIVILEGED_DTO));
 
         /* test */
-        final PrivilegedTableDto response = metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID);
+        final TableDto response = metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID);
         assertEquals(IMAGE_1_JDBC, response.getDatabase().getContainer().getImage().getJdbcMethod());
         assertEquals(CONTAINER_1_HOST, response.getDatabase().getContainer().getHost());
         assertEquals(CONTAINER_1_PORT, response.getDatabase().getContainer().getPort());
         assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getDatabase().getContainer().getUsername());
         assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getDatabase().getContainer().getPassword());
-        assertEquals(DATABASE_1_INTERNALNAME, response.getDatabase().getInternalName());
         assertEquals(TABLE_1_INTERNAL_NAME, response.getInternalName());
     }
 
@@ -119,7 +105,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
         /* mock */
         when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .body(TABLE_1_DTO));
+                        .body(TABLE_1_PRIVILEGED_DTO));
 
         /* test */
         assertThrows(MetadataServiceException.class, () -> {
@@ -129,7 +115,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
 
     @Test
     public void getTableById_headerMissing_fails() {
-        final List<String> customHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port");
+        final List<String> customHeaders = List.of("X-Username", "X-Password");
 
         for (int i = 0; i < customHeaders.size(); i++) {
             final HttpHeaders headers = new HttpHeaders();
@@ -140,7 +126,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
             when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class)))
                     .thenReturn(ResponseEntity.status(HttpStatus.OK)
                             .headers(headers)
-                            .body(TABLE_1_DTO));
+                            .body(TABLE_1_PRIVILEGED_DTO));
             /* test */
             assertThrows(MetadataServiceException.class, () -> {
                 metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID);
@@ -151,13 +137,8 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     @Test
     public void getTableById_emptyBody_fails() {
         final HttpHeaders headers = new HttpHeaders();
-        headers.set("X-Type", IMAGE_1_JDBC);
-        headers.set("X-Host", CONTAINER_1_HOST);
-        headers.set("X-Port", "" + CONTAINER_1_PORT);
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
-        headers.set("X-Database", DATABASE_1_INTERNALNAME);
-        headers.set("X-Table", TABLE_1_INTERNAL_NAME);
 
         /* mock */
         when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class)))
@@ -177,17 +158,15 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
-        headers.set("X-Host", CONTAINER_1_HOST);
-        headers.set("X-Port", "" + CONTAINER_1_PORT);
 
         /* mock */
-        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)))
+        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class)))
                 .thenReturn(ResponseEntity.ok()
                         .headers(headers)
                         .body(DATABASE_1_PRIVILEGED_DTO));
 
         /* test */
-        final PrivilegedDatabaseDto response = metadataServiceGateway.getDatabaseById(DATABASE_1_ID);
+        final DatabaseDto response = metadataServiceGateway.getDatabaseById(DATABASE_1_ID);
         assertEquals(DATABASE_1_ID, response.getId());
     }
 
@@ -197,7 +176,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
         /* mock */
         doThrow(HttpServerErrorException.class)
                 .when(internalRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class));
 
         /* test */
         assertThrows(RemoteUnavailableException.class, () -> {
@@ -211,7 +190,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
         /* mock */
         doThrow(HttpClientErrorException.NotFound.class)
                 .when(internalRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class));
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
@@ -223,7 +202,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     public void getDatabaseById_statusCode_fails() {
 
         /* mock */
-        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)))
+        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
                         .build());
 
@@ -240,7 +219,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
 
         /* mock */
-        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)))
+        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .headers(headers)
                         .build());
@@ -261,7 +240,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                 headers.add(customHeaders.get(j), "");
             }
             /* mock */
-            when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)))
+            when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class)))
                     .thenReturn(ResponseEntity.status(HttpStatus.OK)
                             .headers(headers)
                             .build());
@@ -285,7 +264,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .body(CONTAINER_1_DTO));
 
         /* test */
-        final PrivilegedContainerDto response = metadataServiceGateway.getContainerById(CONTAINER_1_ID);
+        final ContainerDto response = metadataServiceGateway.getContainerById(CONTAINER_1_ID);
         assertEquals(CONTAINER_1_ID, response.getId());
     }
 
@@ -373,22 +352,17 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     @Test
     public void getViewById_succeeds() throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
-        headers.set("X-Type", IMAGE_1_JDBC);
-        headers.set("X-Host", CONTAINER_1_HOST);
-        headers.set("X-Port", "" + CONTAINER_1_PORT);
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
-        headers.set("X-Database", DATABASE_1_INTERNALNAME);
-        headers.set("X-View", VIEW_1_INTERNAL_NAME);
 
         /* mock */
         when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(ViewDto.class)))
                 .thenReturn(ResponseEntity.ok()
                         .headers(headers)
-                        .body(VIEW_1_DTO));
+                        .body(VIEW_1_PRIVILEGED_DTO));
 
         /* test */
-        final PrivilegedViewDto response = metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID);
+        final ViewDto response = metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID);
         assertEquals(VIEW_1_ID, response.getId());
     }
 
@@ -458,12 +432,8 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     @Test
     public void getViewById_emptyBody_fails() {
         final HttpHeaders headers = new HttpHeaders();
-        headers.set("X-Type", IMAGE_1_JDBC);
-        headers.set("X-Host", CONTAINER_1_HOST);
-        headers.set("X-Port", "" + CONTAINER_1_PORT);
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
-        headers.set("X-Database", DATABASE_1_INTERNALNAME);
 
         /* mock */
         when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class)))
@@ -477,19 +447,6 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
         });
     }
 
-    @Test
-    public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException {
-
-        /* mock */
-        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)))
-                .thenReturn(ResponseEntity.ok()
-                        .body(USER_1_DTO));
-
-        /* test */
-        final UserDto response = metadataServiceGateway.getUserById(USER_1_ID);
-        assertEquals(USER_1_ID, response.getId());
-    }
-
     @Test
     public void getUserById_unavailable_fails() {
 
@@ -505,49 +462,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void getUserById_notFound_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.NotFound.class)
-                .when(internalRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            metadataServiceGateway.getUserById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void getUserById_statusCode_fails() {
-
-        /* mock */
-        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        assertThrows(MetadataServiceException.class, () -> {
-            metadataServiceGateway.getUserById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void getUserById_emptyBody_fails() {
-
-        /* mock */
-        when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)))
-                .thenReturn(ResponseEntity.ok()
-                        .build());
-
-        /* test */
-        assertThrows(MetadataServiceException.class, () -> {
-            metadataServiceGateway.getUserById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void getPrivilegedUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException,
+    public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException,
             MetadataServiceException {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
@@ -560,28 +475,14 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
                         .body(USER_1_DTO));
 
         /* test */
-        final PrivilegedUserDto response = metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
+        final UserDto response = metadataServiceGateway.getUserById(USER_1_ID);
         assertEquals(USER_1_ID, response.getId());
         assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getUsername());
         assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getPassword());
     }
 
     @Test
-    public void getPrivilegedUserById_unavailable_fails() {
-
-        /* mock */
-        doThrow(HttpServerErrorException.class)
-                .when(internalRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class));
-
-        /* test */
-        assertThrows(RemoteUnavailableException.class, () -> {
-            metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void getPrivilegedUserById_notFound_fails() {
+    public void getUserById_notFound_fails() {
 
         /* mock */
         doThrow(HttpClientErrorException.NotFound.class)
@@ -590,12 +491,12 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(UserNotFoundException.class, () -> {
-            metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
+            metadataServiceGateway.getUserById(USER_1_ID);
         });
     }
 
     @Test
-    public void getPrivilegedUserById_statusCode_fails() {
+    public void getUserById_statusCode_fails() {
 
         /* mock */
         when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)))
@@ -604,12 +505,12 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(MetadataServiceException.class, () -> {
-            metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
+            metadataServiceGateway.getUserById(USER_1_ID);
         });
     }
 
     @Test
-    public void getPrivilegedUserById_headerMissing_fails() {
+    public void getUserById_headerMissing_fails() {
         final List<String> customHeaders = List.of("X-Username", "X-Password");
 
         for (int i = 0; i < customHeaders.size(); i++) {
@@ -624,13 +525,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
 
             /* test */
             assertThrows(MetadataServiceException.class, () -> {
-                metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
+                metadataServiceGateway.getUserById(USER_1_ID);
             });
         }
     }
 
     @Test
-    public void getPrivilegedUserById_emptyBody_fails() {
+    public void getUserById_emptyBody_fails() {
         final HttpHeaders headers = new HttpHeaders();
         headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME);
         headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD);
@@ -643,7 +544,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(MetadataServiceException.class, () -> {
-            metadataServiceGateway.getPrivilegedUserById(USER_1_ID);
+            metadataServiceGateway.getUserById(USER_1_ID);
         });
     }
 
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
index 88bad7b06124df10f5a3cec690e993ac5b8ffcd5..bca5e1141082e320fe1bef132335fea7e30b7be3 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
@@ -5,7 +5,7 @@ import at.tuwien.config.MariaDbContainerConfig;
 import at.tuwien.exception.MetadataServiceException;
 import at.tuwien.exception.RemoteUnavailableException;
 import at.tuwien.exception.TableNotFoundException;
-import at.tuwien.gateway.MetadataServiceGateway;
+import at.tuwien.service.CredentialService;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -42,13 +42,13 @@ import static org.mockito.Mockito.when;
 public class DefaultListenerIntegrationTest extends AbstractUnitTest {
 
     @MockBean
-    private MetadataServiceGateway metadataServiceGateway;
+    private CredentialService credentialService;
 
     @Autowired
     private DefaultListener defaultListener;
 
     @Container
-    private static RabbitMQContainer rabbitContainer = new RabbitMQContainer("rabbitmq:3.10");
+    private static RabbitMQContainer rabbitContainer = new RabbitMQContainer(RABBITMQ_IMAGE);
 
     @Container
     private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
@@ -67,7 +67,7 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest {
         final Message request = buildMessage("dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>());
 
         /* mock */
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+        when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
 
         /* test */
@@ -83,8 +83,8 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest {
 
         /* mock */
         doThrow(TableNotFoundException.class)
-                .when(metadataServiceGateway)
-                .getTableById(DATABASE_1_ID, TABLE_1_ID);
+                .when(credentialService)
+                .getTable(DATABASE_1_ID, TABLE_1_ID);
 
         /* test */
         defaultListener.onMessage(request);
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
index 648e36caa938f11e564ce772b00c25ba24d18281..74042aa5788c38205d8b73abff31aadf162999e3 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
@@ -5,7 +5,7 @@ import at.tuwien.config.MariaDbContainerConfig;
 import at.tuwien.exception.MetadataServiceException;
 import at.tuwien.exception.RemoteUnavailableException;
 import at.tuwien.exception.TableNotFoundException;
-import at.tuwien.gateway.MetadataServiceGateway;
+import at.tuwien.service.CredentialService;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -38,7 +38,7 @@ import static org.mockito.Mockito.when;
 public class DefaultListenerUnitTest extends AbstractUnitTest {
 
     @MockBean
-    private MetadataServiceGateway metadataServiceGateway;
+    private CredentialService credentialService;
 
     @Autowired
     private DefaultListener defaultListener;
@@ -51,9 +51,10 @@ public class DefaultListenerUnitTest extends AbstractUnitTest {
 
     @BeforeEach
     public void beforeEach() throws SQLException {
+        genesis();
         /* metadata database */
         MariaDbConfig.dropAllDatabases(CONTAINER_1_PRIVILEGED_DTO);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO);
     }
 
     @Test
@@ -80,7 +81,7 @@ public class DefaultListenerUnitTest extends AbstractUnitTest {
         final Message request = buildMessage("dbrepo.1.1", "{,}", new HashMap<>());
 
         /* mock */
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
+        when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
 
         /* test */
@@ -95,8 +96,8 @@ public class DefaultListenerUnitTest extends AbstractUnitTest {
 
         /* mock */
         doThrow(TableNotFoundException.class)
-                .when(metadataServiceGateway)
-                .getTableById(DATABASE_1_ID, TABLE_1_ID);
+                .when(credentialService)
+                .getTable(DATABASE_1_ID, TABLE_1_ID);
 
         /* test */
         defaultListener.onMessage(request);
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 e48f0c048da2dd6c83934566e6e5d9956838ba62..120fe49d8f98f61e36840b69d8c33fa00bc27053 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
@@ -140,7 +140,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, 0L, 10L);
+            subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, 0L, 10L);
         } catch (Exception e) {
             /* ignore */
         }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java
index 5eccf50ed2568a40d868a0f819f763c026368d83..2c174e0a3da88a30e2e8ed8d739cf0200fd5a237 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java
@@ -45,14 +45,14 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
         genesis();
         /* metadata database */
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO);
     }
 
     @Test
     public void create_read_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ);
+        accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         for (String privilege : grantDefaultRead.split(",")) {
             assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim())));
@@ -63,7 +63,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
     public void create_writeOwn_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_OWN);
+        accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_OWN);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         for (String privilege : grantDefaultWrite.split(",")) {
             assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim())));
@@ -74,7 +74,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
     public void create_writeAll_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL);
+        accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_ALL);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         for (String privilege : grantDefaultWrite.split(",")) {
             assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim())));
@@ -85,7 +85,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
     public void update_read_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ);
+        accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         for (String privilege : grantDefaultRead.split(",")) {
             assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim())));
@@ -96,7 +96,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
     public void update_writeOwn_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_OWN);
+        accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_OWN);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         for (String privilege : grantDefaultWrite.split(",")) {
             assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim())));
@@ -107,7 +107,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
     public void update_writeAll_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL);
+        accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_ALL);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         for (String privilege : grantDefaultWrite.split(",")) {
             assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim())));
@@ -119,7 +119,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(DatabaseMalformedException.class, () -> {
-            accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_5_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL);
+            accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_5_DTO, AccessTypeDto.WRITE_ALL);
         });
     }
 
@@ -127,7 +127,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
     public void delete_succeeds() throws SQLException, DatabaseMalformedException {
 
         /* test */
-        accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO);
+        accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO);
         final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
         assertEquals(1, privileges.size());
         assertEquals("USAGE", privileges.get(0));
@@ -138,7 +138,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest {
 
         /* test */
         assertThrows(DatabaseMalformedException.class, () -> {
-            accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_5_PRIVILEGED_DTO);
+            accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_5_DTO);
         });
     }
 
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1579fbe95d8d04cbdbe41f87f5dc066b874b26c
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
@@ -0,0 +1,95 @@
+package at.tuwien.service;
+
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.config.MariaDbConfig;
+import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.exception.DatabaseMalformedException;
+import at.tuwien.exception.QueryStoreCreateException;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.containers.MariaDBContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+@Testcontainers
+public class ContainerServiceIntegrationTest extends AbstractUnitTest {
+
+    @Autowired
+    private ContainerService containerService;
+
+    @Container
+    private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
+
+    @BeforeAll
+    public static void beforeAll() throws InterruptedException {
+        Thread.sleep(1000) /* wait for test container some more */;
+    }
+
+    @BeforeEach
+    public void beforeEach() throws SQLException, InterruptedException {
+        genesis();
+        /* metadata database */
+        MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+        MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+        Thread.sleep(1000) /* wait for test container some more */;
+    }
+
+    @Test
+    public void create_succeeds() throws SQLException, DatabaseMalformedException {
+
+        /* mock */
+        MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+
+        /* test */
+        final DatabaseDto response = containerService.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL);
+        assertNull(response.getName());
+        assertEquals(DATABASE_1_INTERNALNAME, response.getInternalName());
+        assertEquals(EXCHANGE_DBREPO_NAME, response.getExchangeName());
+        assertNotNull(response.getOwner());
+        assertEquals(USER_1_ID, response.getOwner().getId());
+        assertNotNull(response.getContact());
+        assertEquals(USER_1_ID, response.getContact().getId());
+        assertNotNull(response.getContainer());
+        assertEquals(CONTAINER_1_ID, response.getContainer().getId());
+    }
+
+    @Test
+    public void create_exists_fails() {
+
+        /* test */
+        assertThrows(DatabaseMalformedException.class, () -> {
+            containerService.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL);
+        });
+    }
+
+    @Test
+    public void createQueryStore_succeeds() throws SQLException, QueryStoreCreateException, InterruptedException {
+
+        /* test */
+        createQueryStore_generic(DATABASE_1_INTERNALNAME);
+    }
+
+    protected void createQueryStore_generic(String databaseName) throws SQLException, QueryStoreCreateException {
+
+        /* test */
+        containerService.createQueryStore(CONTAINER_1_PRIVILEGED_DTO, databaseName);
+        final List<Map<String, Object>> response = MariaDbConfig.listQueryStore(DATABASE_1_PRIVILEGED_DTO);
+        assertEquals(0, response.size());
+    }
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java
index 160918bfaadbd5563dbf311e18f305efa9c6823f..07e283640a92bd68a774158d196578a0ab9fd23d 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java
@@ -1,11 +1,11 @@
 package at.tuwien.service;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.service.impl.CredentialServiceImpl;
@@ -51,7 +51,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
 
         /* test */
-        final PrivilegedDatabaseDto response = credentialService.getDatabase(DATABASE_1_ID);
+        final DatabaseDto response = credentialService.getDatabase(DATABASE_1_ID);
         assertNotNull(response);
         assertEquals(DATABASE_1_ID, response.getId());
     }
@@ -67,7 +67,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
         credentialService.getDatabase(DATABASE_1_ID);
 
         /* test */
-        final PrivilegedDatabaseDto response = credentialService.getDatabase(DATABASE_1_ID);
+        final DatabaseDto response = credentialService.getDatabase(DATABASE_1_ID);
         assertNotNull(response);
         assertEquals(DATABASE_1_ID, response.getId());
     }
@@ -82,12 +82,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1_PRIVILEGED_DTO);
 
         /* pre-condition */
-        final PrivilegedDatabaseDto tmp = credentialService.getDatabase(DATABASE_1_ID);
+        final DatabaseDto tmp = credentialService.getDatabase(DATABASE_1_ID);
         assertNotEquals(DATABASE_1_ID, tmp.getId());
         Thread.sleep(5000);
 
         /* test */
-        final PrivilegedDatabaseDto response = credentialService.getDatabase(DATABASE_1_ID);
+        final DatabaseDto response = credentialService.getDatabase(DATABASE_1_ID);
         assertNotNull(response);
         assertEquals(DATABASE_1_ID, response.getId());
     }
@@ -101,7 +101,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
 
         /* test */
-        final PrivilegedContainerDto response = credentialService.getContainer(CONTAINER_1_ID);
+        final ContainerDto response = credentialService.getContainer(CONTAINER_1_ID);
         assertNotNull(response);
         assertEquals(CONTAINER_1_ID, response.getId());
     }
@@ -112,12 +112,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
 
         /* mock */
         when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO)
+                .thenReturn(CONTAINER_1_DTO)
                 .thenThrow(RuntimeException.class) /* should never be thrown */;
         credentialService.getContainer(CONTAINER_1_ID);
 
         /* test */
-        final PrivilegedContainerDto response = credentialService.getContainer(CONTAINER_1_ID);
+        final ContainerDto response = credentialService.getContainer(CONTAINER_1_ID);
         assertNotNull(response);
         assertEquals(CONTAINER_1_ID, response.getId());
     }
@@ -132,12 +132,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
 
         /* pre-condition */
-        final PrivilegedContainerDto tmp = credentialService.getContainer(CONTAINER_1_ID);
+        final ContainerDto tmp = credentialService.getContainer(CONTAINER_1_ID);
         assertNotEquals(CONTAINER_1_ID, tmp.getId());
         Thread.sleep(5000);
 
         /* test */
-        final PrivilegedContainerDto response = credentialService.getContainer(CONTAINER_1_ID);
+        final ContainerDto response = credentialService.getContainer(CONTAINER_1_ID);
         assertNotNull(response);
         assertEquals(CONTAINER_1_ID, response.getId());
     }
@@ -147,11 +147,11 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
             UserNotFoundException {
 
         /* mock */
-        when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getUserById(USER_1_ID))
+                .thenReturn(USER_1_DTO);
 
         /* test */
-        final PrivilegedUserDto response = credentialService.getUser(USER_1_ID);
+        final UserDto response = credentialService.getUser(USER_1_ID);
         assertNotNull(response);
         assertEquals(USER_1_ID, response.getId());
     }
@@ -161,13 +161,13 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
             UserNotFoundException {
 
         /* mock */
-        when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID))
-                .thenReturn(USER_1_PRIVILEGED_DTO)
+        when(metadataServiceGateway.getUserById(USER_1_ID))
+                .thenReturn(USER_1_DTO)
                 .thenThrow(RuntimeException.class) /* should never be thrown */;
         credentialService.getUser(USER_1_ID);
 
         /* test */
-        final PrivilegedUserDto response = credentialService.getUser(USER_1_ID);
+        final UserDto response = credentialService.getUser(USER_1_ID);
         assertNotNull(response);
         assertEquals(USER_1_ID, response.getId());
     }
@@ -177,17 +177,17 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
             InterruptedException, UserNotFoundException {
 
         /* mock */
-        when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID))
-                .thenReturn(USER_2_PRIVILEGED_DTO) /* needs to be different id for test case */
-                .thenReturn(USER_1_PRIVILEGED_DTO);
+        when(metadataServiceGateway.getUserById(USER_1_ID))
+                .thenReturn(USER_2_DTO) /* needs to be different id for test case */
+                .thenReturn(USER_1_DTO);
 
         /* pre-condition */
-        final PrivilegedUserDto tmp = credentialService.getUser(USER_1_ID);
+        final UserDto tmp = credentialService.getUser(USER_1_ID);
         assertNotEquals(USER_1_ID, tmp.getId());
         Thread.sleep(5000);
 
         /* test */
-        final PrivilegedUserDto response = credentialService.getUser(USER_1_ID);
+        final UserDto response = credentialService.getUser(USER_1_ID);
         assertNotNull(response);
         assertEquals(USER_1_ID, response.getId());
     }
@@ -254,7 +254,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
 
         /* test */
-        final PrivilegedTableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
+        final TableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
         assertNotNull(response);
         assertEquals(TABLE_1_ID, response.getId());
     }
@@ -270,7 +270,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
         credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
 
         /* test */
-        final PrivilegedTableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
+        final TableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
         assertNotNull(response);
         assertEquals(TABLE_1_ID, response.getId());
     }
@@ -285,12 +285,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(TABLE_1_PRIVILEGED_DTO);
 
         /* pre-condition */
-        final PrivilegedTableDto tmp = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
+        final TableDto tmp = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
         assertNotEquals(TABLE_1_ID, tmp.getId());
         Thread.sleep(5000);
 
         /* test */
-        final PrivilegedTableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
+        final TableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID);
         assertNotNull(response);
         assertEquals(TABLE_1_ID, response.getId());
     }
@@ -304,7 +304,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(VIEW_1_PRIVILEGED_DTO);
 
         /* test */
-        final PrivilegedViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
+        final ViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
         assertNotNull(response);
         assertEquals(VIEW_1_ID, response.getId());
     }
@@ -319,7 +319,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
         credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
 
         /* test */
-        final PrivilegedViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
+        final ViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
         assertNotNull(response);
         assertEquals(VIEW_1_ID, response.getId());
     }
@@ -334,12 +334,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(VIEW_1_PRIVILEGED_DTO);
 
         /* pre-condition */
-        final PrivilegedViewDto tmp = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
+        final ViewDto tmp = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
         assertNotEquals(VIEW_1_ID, tmp.getId());
         Thread.sleep(5000);
 
         /* test */
-        final PrivilegedViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
+        final ViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID);
         assertNotNull(response);
         assertEquals(VIEW_1_ID, response.getId());
     }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
index 83d81715bd79a82b7306a3330d2d08e96bab82d0..6663a71d135033e5fb4a3b3810d04d54130e270a 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
@@ -1,12 +1,29 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.database.ViewColumnDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableBriefDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.database.table.columns.ColumnDto;
+import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
+import at.tuwien.api.database.table.constraints.ConstraintsDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
+import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto;
+import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
+import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
+import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto;
+import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
+import at.tuwien.api.database.table.constraints.unique.UniqueDto;
+import at.tuwien.api.database.table.internal.TableCreateDto;
+import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
-import at.tuwien.exception.DatabaseMalformedException;
+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.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -19,6 +36,9 @@ import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
 import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
 
 import static org.junit.jupiter.api.Assertions.*;
 
@@ -40,38 +60,47 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @BeforeEach
-    public void beforeEach() throws SQLException {
+    public void beforeEach() throws SQLException, InterruptedException {
         genesis();
         /* metadata database */
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_DTO);
+        Thread.sleep(1000) /* wait for test container some more */;
     }
 
     @Test
-    public void create_succeeds() throws SQLException, DatabaseMalformedException {
+    public void createView_succeeds() throws SQLException, ViewMalformedException {
 
         /* test */
-        final PrivilegedDatabaseDto response = databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL);
-        assertNull(response.getName());
-        assertEquals(DATABASE_1_INTERNALNAME, response.getInternalName());
-        assertEquals(EXCHANGE_DBREPO_NAME, response.getExchangeName());
-        assertNotNull(response.getOwner());
-        assertEquals(USER_1_ID, response.getOwner().getId());
-        assertNotNull(response.getContact());
-        assertEquals(USER_1_ID, response.getContact().getId());
-        assertNotNull(response.getContainer());
-        assertEquals(CONTAINER_1_ID, response.getContainer().getId());
+        databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO);
     }
 
     @Test
-    public void create_exists_fails() throws SQLException {
-
-        /* mock */
-        MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
+    public void exploreViews_succeeds() throws SQLException, ViewNotFoundException, DatabaseMalformedException {
 
         /* test */
-        assertThrows(DatabaseMalformedException.class, () -> {
-            databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL);
-        });
+        final List<ViewDto> response = databaseService.exploreViews(DATABASE_1_PRIVILEGED_DTO);
+        final ViewDto view0 = response.get(0);
+        assertEquals("not_in_metadata_db2", view0.getName());
+        assertEquals("not_in_metadata_db2", view0.getInternalName());
+        assertEquals(DATABASE_1_ID, view0.getVdbid());
+        assertEquals(USER_1_BRIEF_DTO, view0.getOwner());
+        assertFalse(view0.getIsInitialView());
+        assertEquals(DATABASE_1_PUBLIC, view0.getIsPublic());
+        assertEquals(DATABASE_1_SCHEMA_PUBLIC, view0.getIsSchemaPublic());
+        assertTrue(view0.getQuery().length() >= 69);
+        assertNotNull(view0.getQueryHash());
+        assertEquals(4, view0.getColumns().size());
+        final ViewColumnDto column0a = view0.getColumns().get(0);
+        assertEquals("date", column0a.getInternalName());
+        final ViewColumnDto column1a = view0.getColumns().get(1);
+        assertEquals("location", column1a.getInternalName());
+        final ViewColumnDto column2a = view0.getColumns().get(2);
+        assertEquals("MinTemp", column2a.getInternalName());
+        final ViewColumnDto column3a = view0.getColumns().get(3);
+        assertEquals("Rainfall", column3a.getInternalName());
     }
 
     @Test
@@ -82,7 +111,6 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest {
                 .build();
 
         /* mock */
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
         MariaDbConfig.grantWriteAccess(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME);
 
         /* pre-condition */
@@ -100,19 +128,616 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void update_notExists_fails() throws SQLException {
+    public void update_notExists_fails() {
         final UpdateUserPasswordDto request = UpdateUserPasswordDto.builder()
                 .username("i_do_not_exist")
                 .password(USER_1_PASSWORD)
                 .build();
 
-        /* mock */
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
-
         /* test */
         assertThrows(DatabaseMalformedException.class, () -> {
             databaseService.update(DATABASE_1_PRIVILEGED_DTO, request);
         });
     }
 
+    @Test
+    public void inspectTable_sameNameDifferentDb_succeeds() throws TableNotFoundException, SQLException {
+
+        /* mock */
+        MariaDbConfig.execute(DATABASE_2_PRIVILEGED_DTO, "CREATE TABLE not_in_metadata_db (wrong_id BIGINT NOT NULL PRIMARY KEY, given_name VARCHAR(255) NOT NULL, middle_name VARCHAR(255), family_name VARCHAR(255) NOT NULL, age INT NOT NULL) WITH SYSTEM VERSIONING;");
+
+        /* test */
+        final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db");
+        assertEquals("not_in_metadata_db", response.getInternalName());
+        assertEquals("not_in_metadata_db", response.getName());
+        assertEquals(DATABASE_1_ID, response.getTdbid());
+        assertTrue(response.getIsVersioned());
+        assertEquals(DATABASE_1_PUBLIC, response.getIsPublic());
+        final List<ColumnDto> columns = response.getColumns();
+        assertNotNull(columns);
+        assertEquals(5, columns.size());
+        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
+        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null);
+        assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
+        assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null);
+        final ConstraintsDto constraints = response.getConstraints();
+        assertNotNull(constraints);
+        final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey();
+        assertEquals(1, primaryKey.size());
+        final Set<String> checks = constraints.getChecks();
+        assertEquals(1, checks.size());
+        assertEquals(Set.of("`age` > 0 and `age` < 120"), checks);
+        final List<UniqueDto> uniques = constraints.getUniques();
+        assertEquals(1, uniques.size());
+        assertEquals(2, uniques.get(0).getColumns().size());
+        assertEquals("not_in_metadata_db", uniques.get(0).getTable().getName());
+        assertEquals("not_in_metadata_db", uniques.get(0).getTable().getInternalName());
+        assertEquals("given_name", uniques.get(0).getColumns().get(0).getInternalName());
+        assertEquals("family_name", uniques.get(0).getColumns().get(1).getInternalName());
+        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
+        assertEquals(0, foreignKeys.size());
+    }
+
+    @Test
+    public void inspectTableEnum_succeeds() throws TableNotFoundException, SQLException {
+
+        /* test */
+        final TableDto response = databaseService.inspectTable(DATABASE_2_PRIVILEGED_DTO, "experiments");
+        assertEquals("experiments", response.getInternalName());
+        assertEquals("experiments", response.getName());
+        assertEquals(DATABASE_2_ID, response.getTdbid());
+        assertTrue(response.getIsVersioned());
+        assertEquals(DATABASE_2_PUBLIC, response.getIsPublic());
+        assertNotNull(response.getOwner());
+        assertEquals(DATABASE_2_OWNER, response.getOwner().getId());
+        assertEquals(USER_2_NAME, response.getOwner().getName());
+        assertEquals(USER_2_USERNAME, response.getOwner().getUsername());
+        assertEquals(USER_2_FIRSTNAME, response.getOwner().getFirstname());
+        assertEquals(USER_2_LASTNAME, response.getOwner().getLastname());
+        assertEquals(USER_2_QUALIFIED_NAME, response.getOwner().getQualifiedName());
+        final List<IdentifierDto> identifiers = response.getIdentifiers();
+        assertNotNull(identifiers);
+        assertEquals(0, identifiers.size());
+        final List<ColumnDto> columns = response.getColumns();
+        assertNotNull(columns);
+        assertEquals(3, columns.size());
+        assertColumn(columns.get(0), null, null, DATABASE_2_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        assertColumn(columns.get(1), null, null, DATABASE_2_ID, "mode", "mode", ColumnTypeDto.ENUM, 3L, null, false, null);
+        assertEquals(2, columns.get(1).getEnums().size());
+        assertEquals(List.of("ABC", "DEF"), columns.get(1).getEnums());
+        assertColumn(columns.get(2), null, null, DATABASE_2_ID, "seq", "seq", ColumnTypeDto.SET, 5L, null, true, null);
+        assertEquals(3, columns.get(2).getSets().size());
+        assertEquals(List.of("1", "2", "3"), columns.get(2).getSets());
+        /* ignore rest (constraints) */
+    }
+
+    @Test
+    public void inspectTableFullConstraints_succeeds() throws TableNotFoundException, SQLException {
+
+        /* test */
+        final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "weather_aus");
+        assertEquals("weather_aus", response.getInternalName());
+        assertEquals("weather_aus", response.getName());
+        assertEquals(DATABASE_1_ID, response.getTdbid());
+        assertTrue(response.getIsVersioned());
+        assertEquals(DATABASE_1_PUBLIC, response.getIsPublic());
+        assertNotNull(response.getOwner());
+        assertEquals(USER_1_BRIEF_DTO, response.getOwner());
+        assertEquals(USER_1_NAME, response.getOwner().getName());
+        assertEquals(USER_1_USERNAME, response.getOwner().getUsername());
+        assertEquals(USER_1_FIRSTNAME, response.getOwner().getFirstname());
+        assertEquals(USER_1_LASTNAME, response.getOwner().getLastname());
+        assertEquals(USER_1_QUALIFIED_NAME, response.getOwner().getQualifiedName());
+        final List<IdentifierDto> identifiers = response.getIdentifiers();
+        assertNotNull(identifiers);
+        assertEquals(0, identifiers.size());
+        final List<ColumnDto> columns = response.getColumns();
+        assertNotNull(columns);
+        assertEquals(5, columns.size());
+        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 20L, 0L, false, null);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, null);
+        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, "Closest city");
+        assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null);
+        assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null);
+        final ConstraintsDto constraints = response.getConstraints();
+        final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey());
+        assertEquals(1, primaryKey.size());
+        final PrimaryKeyDto pk0 = primaryKey.get(0);
+        assertNull(pk0.getId());
+        assertNotNull(pk0.getTable());
+        assertNull(pk0.getTable().getId());
+        assertEquals("weather_aus", pk0.getTable().getName());
+        assertEquals("weather_aus", pk0.getTable().getInternalName());
+        assertEquals("Weather in Australia", pk0.getTable().getDescription());
+        assertNotNull(pk0.getColumn());
+        assertNull(pk0.getColumn().getId());
+        assertNull(pk0.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId());
+        assertNull(pk0.getColumn().getAlias());
+        assertEquals("id", pk0.getColumn().getName());
+        assertEquals("id", pk0.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType());
+        final List<UniqueDto> uniques = constraints.getUniques();
+        assertEquals(1, uniques.size());
+        final UniqueDto unique0 = uniques.get(0);
+        assertNotNull(unique0.getTable());
+        assertEquals("some_constraint", unique0.getName());
+        assertNull(unique0.getTable().getId());
+        assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getName());
+        assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getInternalName());
+        assertEquals(TABLE_1_DESCRIPTION, unique0.getTable().getDescription());
+        assertTrue(unique0.getTable().getIsVersioned());
+        assertNotNull(unique0.getColumns());
+        assertEquals(1, unique0.getColumns().size());
+        assertNull(unique0.getColumns().get(0).getId());
+        assertNull(unique0.getColumns().get(0).getTableId());
+        assertEquals("date", unique0.getColumns().get(0).getName());
+        assertEquals("date", unique0.getColumns().get(0).getInternalName());
+        final List<String> checks = new LinkedList<>(constraints.getChecks());
+        assertEquals("`mintemp` > 0", checks.get(0));
+        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
+        assertEquals(1, foreignKeys.size());
+        final ForeignKeyDto fk0 = foreignKeys.get(0);
+        assertNotNull(fk0.getName());
+        assertNotNull(fk0.getReferences());
+        final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0);
+        assertNull(fk0ref0.getId());
+        assertNotNull(fk0ref0.getColumn());
+        assertNotNull(fk0ref0.getReferencedColumn());
+        assertNotNull(fk0ref0.getForeignKey());
+        assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId());
+        assertNull(fk0ref0.getColumn().getId());
+        assertNull(fk0ref0.getColumn().getTableId());
+        assertEquals("location", fk0ref0.getColumn().getName());
+        assertEquals("location", fk0ref0.getColumn().getInternalName());
+        assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId());
+        assertNull(fk0ref0.getReferencedColumn().getId());
+        assertNull(fk0ref0.getReferencedColumn().getTableId());
+        assertEquals("location", fk0ref0.getReferencedColumn().getName());
+        assertEquals("location", fk0ref0.getReferencedColumn().getInternalName());
+        assertNotNull(fk0.getOnUpdate());
+        assertEquals(ReferenceTypeDto.RESTRICT, fk0.getOnUpdate());
+        assertNotNull(fk0.getOnDelete());
+        assertEquals(ReferenceTypeDto.SET_NULL, fk0.getOnDelete());
+        final TableBriefDto fk0table = fk0.getTable();
+        assertNull(fk0table.getId());
+        assertEquals(DATABASE_1_ID, fk0table.getDatabaseId());
+        assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getName());
+        assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getInternalName());
+        assertNotNull(fk0.getOnDelete());
+        assertNotNull(fk0.getOnUpdate());
+        assertNotNull(fk0.getReferencedTable());
+        assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getName());
+        assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getInternalName());
+    }
+
+    @Test
+    public void inspectTable_multipleForeignKeyReferences_succeeds() throws TableNotFoundException, SQLException {
+
+        /* test */
+        final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_foreign_keys");
+        final ConstraintsDto constraints = response.getConstraints();
+        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
+        assertEquals(1, foreignKeys.size());
+        final ForeignKeyDto fk0 = foreignKeys.get(0);
+        assertNotNull(fk0.getName());
+        assertNotNull(fk0.getReferences());
+        final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0);
+        assertNull(fk0ref0.getId());
+        assertNotNull(fk0ref0.getColumn());
+        assertNotNull(fk0ref0.getReferencedColumn());
+        assertNotNull(fk0ref0.getForeignKey());
+        assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId());
+        assertNull(fk0ref0.getColumn().getId());
+        assertNull(fk0ref0.getColumn().getTableId());
+        assertEquals("weather_id", fk0ref0.getColumn().getName());
+        assertEquals("weather_id", fk0ref0.getColumn().getInternalName());
+        assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId());
+        assertNull(fk0ref0.getReferencedColumn().getId());
+        assertNull(fk0ref0.getReferencedColumn().getTableId());
+        assertEquals("id", fk0ref0.getReferencedColumn().getName());
+        assertEquals("id", fk0ref0.getReferencedColumn().getInternalName());
+        final ForeignKeyReferenceDto fk0ref1 = fk0.getReferences().get(1);
+        assertNull(fk0ref1.getId());
+        assertNotNull(fk0ref1.getColumn());
+        assertNotNull(fk0ref1.getReferencedColumn());
+        assertNotNull(fk0ref1.getForeignKey());
+        assertEquals(DATABASE_1_ID, fk0ref1.getColumn().getDatabaseId());
+        assertNull(fk0ref1.getColumn().getId());
+        assertNull(fk0ref1.getColumn().getTableId());
+        assertEquals("other_id", fk0ref1.getColumn().getName());
+        assertEquals("other_id", fk0ref1.getColumn().getInternalName());
+        assertEquals(DATABASE_1_ID, fk0ref1.getReferencedColumn().getDatabaseId());
+        assertNull(fk0ref1.getReferencedColumn().getId());
+        assertNull(fk0ref1.getReferencedColumn().getTableId());
+        assertEquals("other_id", fk0ref1.getReferencedColumn().getName());
+        assertEquals("other_id", fk0ref1.getReferencedColumn().getInternalName());
+        final TableBriefDto fk0refT0 = fk0.getTable();
+        assertNull(fk0refT0.getId());
+        assertEquals(DATABASE_1_ID, fk0refT0.getDatabaseId());
+        assertEquals("complex_foreign_keys", fk0refT0.getName());
+        assertEquals("complex_foreign_keys", fk0refT0.getInternalName());
+        assertNotNull(fk0.getReferencedTable());
+        assertEquals("complex_primary_key", fk0.getReferencedTable().getName());
+        assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName());
+        assertNotNull(fk0.getOnDelete());
+        assertNotNull(fk0.getOnUpdate());
+    }
+
+    @Test
+    public void inspectTable_multiplePrimaryKey_succeeds() throws TableNotFoundException, SQLException {
+
+        /* test */
+        final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_primary_key");
+        final ConstraintsDto constraints = response.getConstraints();
+        final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey());
+        assertEquals(2, primaryKey.size());
+        final PrimaryKeyDto pk0 = primaryKey.get(0);
+        assertNull(pk0.getId());
+        assertNotNull(pk0.getTable());
+        assertNull(pk0.getTable().getId());
+        assertEquals("complex_primary_key", pk0.getTable().getName());
+        assertEquals("complex_primary_key", pk0.getTable().getInternalName());
+        assertNotNull(pk0.getColumn());
+        assertNull(pk0.getColumn().getId());
+        assertNull(pk0.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId());
+        assertNull(pk0.getColumn().getAlias());
+        assertEquals("id", pk0.getColumn().getName());
+        assertEquals("id", pk0.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType());
+        final PrimaryKeyDto pk1 = primaryKey.get(1);
+        assertNull(pk1.getId());
+        assertNotNull(pk1.getTable());
+        assertNull(pk1.getTable().getId());
+        assertEquals("complex_primary_key", pk1.getTable().getName());
+        assertEquals("complex_primary_key", pk1.getTable().getInternalName());
+        assertNotNull(pk1.getColumn());
+        assertNull(pk1.getColumn().getId());
+        assertNull(pk1.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, pk1.getColumn().getDatabaseId());
+        assertNull(pk1.getColumn().getAlias());
+        assertEquals("other_id", pk1.getColumn().getName());
+        assertEquals("other_id", pk1.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.BIGINT, pk1.getColumn().getColumnType());
+    }
+
+    @Test
+    public void inspectTable_exoticBoolean_succeeds() throws TableNotFoundException, SQLException {
+
+        /* test */
+        final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "exotic_boolean");
+        final ConstraintsDto constraints = response.getConstraints();
+        final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey());
+        assertEquals(1, primaryKey.size());
+        final PrimaryKeyDto pk0 = primaryKey.get(0);
+        assertNull(pk0.getId());
+        assertNotNull(pk0.getTable());
+        assertNull(pk0.getTable().getId());
+        assertEquals("exotic_boolean", pk0.getTable().getName());
+        assertEquals("exotic_boolean", pk0.getTable().getInternalName());
+        assertNotNull(pk0.getColumn());
+        assertNull(pk0.getColumn().getId());
+        assertNull(pk0.getColumn().getTableId());
+        assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId());
+        assertNull(pk0.getColumn().getAlias());
+        assertEquals("bool_default", pk0.getColumn().getName());
+        assertEquals("bool_default", pk0.getColumn().getInternalName());
+        assertEquals(ColumnTypeDto.BOOL, pk0.getColumn().getColumnType());
+        final List<ColumnDto> columns = response.getColumns();
+        assertEquals(3, columns.size());
+        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null);
+        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null);
+    }
+
+    @Test
+    public void inspectView_succeeds() throws SQLException, ViewNotFoundException {
+
+        /* test */
+        final ViewDto response = databaseService.inspectView(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db2");
+        assertEquals("not_in_metadata_db2", response.getInternalName());
+        assertEquals("not_in_metadata_db2", response.getName());
+        assertEquals(DATABASE_1_ID, response.getVdbid());
+        assertEquals(USER_1_BRIEF_DTO, response.getOwner());
+        assertFalse(response.getIsInitialView());
+        assertEquals(DATABASE_1_PUBLIC, response.getIsPublic());
+        assertTrue(response.getQuery().length() >= 69);
+        assertNotNull(response.getQueryHash());
+        assertEquals(4, response.getColumns().size());
+        final ViewColumnDto column0 = response.getColumns().get(0);
+        assertNotNull(column0.getName());
+        assertEquals("date", column0.getInternalName());
+        assertEquals(DATABASE_1_ID, column0.getDatabaseId());
+        final ViewColumnDto column1 = response.getColumns().get(1);
+        assertNotNull(column1.getName());
+        assertEquals("location", column1.getInternalName());
+        assertEquals(DATABASE_1_ID, column1.getDatabaseId());
+        final ViewColumnDto column2 = response.getColumns().get(2);
+        assertNotNull(column2.getName());
+        assertEquals("MinTemp", column2.getInternalName());
+        assertEquals(DATABASE_1_ID, column2.getDatabaseId());
+        final ViewColumnDto column3 = response.getColumns().get(3);
+        assertNotNull(column3.getName());
+        assertEquals("Rainfall", column3.getInternalName());
+        assertEquals(DATABASE_1_ID, column3.getDatabaseId());
+    }
+
+    @Test
+    public void getSchemas_succeeds() throws TableNotFoundException, SQLException, DatabaseMalformedException {
+
+        /* test */
+        final List<TableDto> response = databaseService.exploreTables(DATABASE_1_PRIVILEGED_DTO);
+        assertEquals(4, response.size());
+        final TableDto table0 = response.get(0);
+        Assertions.assertEquals("complex_foreign_keys", table0.getInternalName());
+        Assertions.assertEquals("complex_foreign_keys", table0.getName());
+        Assertions.assertEquals(DATABASE_1_ID, table0.getTdbid());
+        assertTrue(table0.getIsVersioned());
+        Assertions.assertEquals(DATABASE_1_PUBLIC, table0.getIsPublic());
+        final List<ColumnDto> columns0 = table0.getColumns();
+        assertNotNull(columns0);
+        Assertions.assertEquals(3, columns0.size());
+        assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        final ConstraintsDto constraints0 = table0.getConstraints();
+        assertNotNull(constraints0);
+        assertEquals(1, constraints0.getPrimaryKey().size());
+        final PrimaryKeyDto pk0 = new LinkedList<>(constraints0.getPrimaryKey()).get(0);
+        assertNull(pk0.getId());
+        assertNull(pk0.getColumn().getId());
+        assertEquals("id", pk0.getColumn().getName());
+        assertEquals("id", pk0.getColumn().getInternalName());
+        assertEquals(1, constraints0.getForeignKeys().size());
+        final ForeignKeyDto fk0 = constraints0.getForeignKeys().get(0);
+        assertNotNull(fk0.getName());
+        assertNull(fk0.getTable().getId());
+        assertEquals("complex_foreign_keys", fk0.getTable().getName());
+        assertEquals("complex_foreign_keys", fk0.getTable().getInternalName());
+        assertNull(fk0.getReferencedTable().getId());
+        assertEquals("complex_primary_key", fk0.getReferencedTable().getName());
+        assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName());
+        assertEquals(2, fk0.getReferences().size());
+        final ForeignKeyReferenceDto fk0r0 = fk0.getReferences().get(0);
+        assertEquals("weather_id", fk0r0.getColumn().getName());
+        assertEquals("weather_id", fk0r0.getColumn().getInternalName());
+        assertNotNull(fk0r0.getColumn().getName());
+        assertNotNull(fk0r0.getForeignKey());
+        assertEquals("id", fk0r0.getReferencedColumn().getName());
+        assertEquals("id", fk0r0.getReferencedColumn().getInternalName());
+        final ForeignKeyReferenceDto fk0r1 = fk0.getReferences().get(1);
+        assertEquals("other_id", fk0r1.getColumn().getName());
+        assertEquals("other_id", fk0r1.getColumn().getInternalName());
+        assertNotNull(fk0r1.getColumn().getName());
+        assertNotNull(fk0r1.getForeignKey());
+        assertEquals("other_id", fk0r1.getReferencedColumn().getName());
+        assertEquals("other_id", fk0r1.getReferencedColumn().getInternalName());
+        assertEquals(0, constraints0.getChecks().size());
+        assertEquals(0, constraints0.getUniques().size());
+        /* table 1 */
+        final TableDto table1 = response.get(1);
+        Assertions.assertEquals("complex_primary_key", table1.getInternalName());
+        Assertions.assertEquals("complex_primary_key", table1.getName());
+        Assertions.assertEquals(DATABASE_1_ID, table1.getTdbid());
+        assertTrue(table1.getIsVersioned());
+        Assertions.assertEquals(DATABASE_1_PUBLIC, table1.getIsPublic());
+        final List<ColumnDto> columns1 = table1.getColumns();
+        assertNotNull(columns1);
+        Assertions.assertEquals(2, columns1.size());
+        assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        final ConstraintsDto constraints1 = table1.getConstraints();
+        assertNotNull(constraints1);
+        assertEquals(2, constraints1.getPrimaryKey().size());
+        final PrimaryKeyDto pk10 = new LinkedList<>(constraints1.getPrimaryKey()).get(0);
+        assertNull(pk10.getId());
+        assertNull(pk10.getColumn().getId());
+        assertEquals("id", pk10.getColumn().getName());
+        assertEquals("id", pk10.getColumn().getInternalName());
+        final PrimaryKeyDto pk11 = new LinkedList<>(constraints1.getPrimaryKey()).get(1);
+        assertNull(pk11.getId());
+        assertNull(pk11.getColumn().getId());
+        assertEquals("other_id", pk11.getColumn().getName());
+        assertEquals("other_id", pk11.getColumn().getInternalName());
+        assertEquals(0, constraints1.getForeignKeys().size());
+        assertEquals(0, constraints1.getChecks().size());
+        assertEquals(0, constraints1.getUniques().size());
+        /* table 2 */
+        final TableDto table2 = response.get(2);
+        Assertions.assertEquals("exotic_boolean", table2.getInternalName());
+        Assertions.assertEquals("exotic_boolean", table2.getName());
+        Assertions.assertEquals(DATABASE_1_ID, table2.getTdbid());
+        assertTrue(table2.getIsVersioned());
+        Assertions.assertEquals(DATABASE_1_PUBLIC, table2.getIsPublic());
+        final List<ColumnDto> columns2 = table2.getColumns();
+        assertNotNull(columns2);
+        Assertions.assertEquals(3, columns2.size());
+        assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null);
+        assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null);
+        assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null);
+        final ConstraintsDto constraints2 = table2.getConstraints();
+        assertNotNull(constraints2);
+        final Set<PrimaryKeyDto> primaryKey2 = constraints2.getPrimaryKey();
+        Assertions.assertEquals(1, primaryKey2.size());
+        final Set<String> checks2 = constraints2.getChecks();
+        Assertions.assertEquals(0, checks2.size());
+        final List<UniqueDto> uniques2 = constraints2.getUniques();
+        Assertions.assertEquals(0, uniques2.size());
+        /* table 3 */
+        final TableDto table3 = response.get(3);
+        Assertions.assertEquals("not_in_metadata_db", table3.getInternalName());
+        Assertions.assertEquals("not_in_metadata_db", table3.getName());
+        Assertions.assertEquals(DATABASE_1_ID, table3.getTdbid());
+        assertTrue(table3.getIsVersioned());
+        Assertions.assertEquals(DATABASE_1_PUBLIC, table3.getIsPublic());
+        final List<ColumnDto> columns3 = table3.getColumns();
+        assertNotNull(columns3);
+        Assertions.assertEquals(5, columns3.size());
+        assertColumn(columns3.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
+        assertColumn(columns3.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
+        assertColumn(columns3.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null);
+        assertColumn(columns3.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
+        assertColumn(columns3.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null);
+        final ConstraintsDto constraints3 = table3.getConstraints();
+        assertNotNull(constraints3);
+        final Set<PrimaryKeyDto> primaryKey3 = constraints3.getPrimaryKey();
+        Assertions.assertEquals(1, primaryKey3.size());
+        final Set<String> checks3 = constraints3.getChecks();
+        Assertions.assertEquals(1, checks3.size());
+        Assertions.assertEquals(Set.of("`age` > 0 and `age` < 120"), checks3);
+        final List<UniqueDto> uniques3 = constraints3.getUniques();
+        Assertions.assertEquals(1, uniques3.size());
+        Assertions.assertEquals(2, uniques3.get(0).getColumns().size());
+        Assertions.assertEquals("not_in_metadata_db", uniques3.get(0).getTable().getInternalName());
+        Assertions.assertEquals("given_name", uniques3.get(0).getColumns().get(0).getInternalName());
+        Assertions.assertEquals("family_name", uniques3.get(0).getColumns().get(1).getInternalName());
+    }
+
+    @Test
+    public void createTable_succeeds() throws TableNotFoundException, TableMalformedException, SQLException,
+            TableExistsException {
+
+        /* test */
+        final TableDto response = databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO);
+        assertEquals(TABLE_4_INTERNALNAME, response.getName());
+        assertEquals(TABLE_4_INTERNALNAME, response.getInternalName());
+        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, null);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "value", "value", ColumnTypeDto.DECIMAL, 10L, 10L, true, 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
+    public void createTable_malformed_fails() {
+        final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder()
+                .name("missing_foreign_key")
+                .columns(List.of())
+                .constraints(CreateTableConstraintsDto.builder()
+                        .foreignKeys(List.of(CreateForeignKeyDto.builder()
+                                .columns(List.of("i_do_not_exist"))
+                                .referencedTable("neither_do_i")
+                                .referencedColumns(List.of("behold"))
+                                .build()))
+                        .build())
+                .build();
+
+        /* test */
+        assertThrows(TableMalformedException.class, () -> {
+            databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, request);
+        });
+    }
+
+    @Test
+    public void createTable_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(CreateTableColumnDto.builder()
+                                .name("name")
+                                .type(ColumnTypeDto.VARCHAR)
+                                .size(255L)
+                                .nullAllowed(false)
+                                .build(),
+                        CreateTableColumnDto.builder()
+                                .name("lat")
+                                .type(ColumnTypeDto.DECIMAL)
+                                .size(10L)
+                                .d(10L)
+                                .nullAllowed(false)
+                                .build(),
+                        CreateTableColumnDto.builder()
+                                .name("lng")
+                                .type(ColumnTypeDto.DECIMAL)
+                                .size(10L)
+                                .d(10L)
+                                .nullAllowed(false)
+                                .build()))
+                .constraints(CreateTableConstraintsDto.builder()
+                        .primaryKey(Set.of("lat", "lng"))
+                        .foreignKeys(List.of())
+                        .checks(Set.of())
+                        .uniques(List.of())
+                        .build())
+                .build();
+
+        /* test */
+        final TableDto response = databaseService.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);
+        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "lat", "lat", ColumnTypeDto.DECIMAL, 10L, 10L, false, null);
+        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "lng", "lng", ColumnTypeDto.DECIMAL, 10L, 10L, false, 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 createTable_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException,
+            TableExistsException {
+
+        /* mock */
+        MariaDbConfig.dropTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNAL_NAME);
+
+        /* test */
+        final TableDto response = databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_CREATE_INTERNAL_DTO);
+        assertEquals(TABLE_1_INTERNAL_NAME, response.getName());
+        assertEquals(TABLE_1_INTERNAL_NAME, response.getInternalName());
+        assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size());
+    }
+
+    protected static void assertViewColumn(ViewColumnDto column, ViewColumnDto other) {
+        assertNotNull(column);
+        assertNotNull(other);
+        assertEquals(column.getId(), other.getId());
+        assertEquals(column.getDatabaseId(), other.getDatabaseId());
+        assertEquals(column.getName(), other.getName());
+        assertEquals(column.getInternalName(), other.getInternalName());
+        assertEquals(column.getColumnType(), other.getColumnType());
+        assertEquals(column.getSize(), other.getSize());
+        assertEquals(column.getD(), other.getD());
+        assertEquals(column.getIsNullAllowed(), other.getIsNullAllowed());
+        assertEquals(column.getDescription(), other.getDescription());
+    }
+
+    protected static void assertColumn(ColumnDto column, Long id, Long tableId, Long databaseId, String name,
+                                       String internalName, ColumnTypeDto type, Long size, Long d, Boolean nullAllowed,
+                                       String description) {
+        log.trace("assert column: {}", internalName);
+        assertNotNull(column);
+        assertEquals(id, column.getId());
+        assertEquals(tableId, column.getTableId());
+        assertEquals(databaseId, column.getDatabaseId());
+        assertEquals(name, column.getName());
+        assertEquals(internalName, column.getInternalName());
+        assertEquals(type, column.getColumnType());
+        assertEquals(size, column.getSize());
+        assertEquals(d, column.getD());
+        assertEquals(nullAllowed, column.getIsNullAllowed());
+        assertEquals(description, column.getDescription());
+    }
+
 }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
index bd57eafacc47a1107e309be0fba94de75371bc95..18b2dd8e01bc8d8e10f1de9bea9798846868bc6d 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
@@ -53,7 +53,7 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest {
         genesis();
         /* metadata database */
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO);
     }
 
     @Test
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java
deleted file mode 100644
index 2a0ad624dbbb8399cf9d360148c96bd0524c8453..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java
+++ /dev/null
@@ -1,416 +0,0 @@
-package at.tuwien.service;
-
-import at.tuwien.api.database.ViewColumnDto;
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.columns.ColumnTypeDto;
-import at.tuwien.api.database.table.constraints.ConstraintsDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
-import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto;
-import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
-import at.tuwien.api.database.table.constraints.unique.UniqueDto;
-import at.tuwien.api.identifier.IdentifierDto;
-import at.tuwien.config.MariaDbConfig;
-import at.tuwien.config.MariaDbContainerConfig;
-import at.tuwien.exception.TableNotFoundException;
-import at.tuwien.exception.ViewNotFoundException;
-import at.tuwien.test.AbstractUnitTest;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.testcontainers.containers.MariaDBContainer;
-import org.testcontainers.junit.jupiter.Container;
-import org.testcontainers.junit.jupiter.Testcontainers;
-
-import java.sql.SQLException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-@Log4j2
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-@Testcontainers
-public class SchemaServiceIntegrationTest extends AbstractUnitTest {
-
-    @Autowired
-    private SchemaService schemaService;
-
-    @Container
-    private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
-
-    @BeforeEach
-    public void beforeEach() throws SQLException {
-        genesis();
-        /* metadata database */
-        MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
-        MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_DTO);
-    }
-
-    @Test
-    public void inspectTable_sameNameDifferentDb_succeeds() throws TableNotFoundException, SQLException {
-
-        /* mock */
-        MariaDbConfig.execute(DATABASE_2_PRIVILEGED_DTO, "CREATE TABLE not_in_metadata_db (wrong_id BIGINT NOT NULL PRIMARY KEY, given_name VARCHAR(255) NOT NULL, middle_name VARCHAR(255), family_name VARCHAR(255) NOT NULL, age INT NOT NULL) WITH SYSTEM VERSIONING;");
-
-        /* test */
-        final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db");
-        assertEquals("not_in_metadata_db", response.getInternalName());
-        assertEquals("not_in_metadata_db", response.getName());
-        assertEquals(DATABASE_1_ID, response.getTdbid());
-        assertTrue(response.getIsVersioned());
-        assertEquals(DATABASE_1_PUBLIC, response.getIsPublic());
-        final List<ColumnDto> columns = response.getColumns();
-        assertNotNull(columns);
-        assertEquals(5, columns.size());
-        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
-        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null);
-        assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
-        assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null);
-        final ConstraintsDto constraints = response.getConstraints();
-        assertNotNull(constraints);
-        final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey();
-        assertEquals(1, primaryKey.size());
-        final Set<String> checks = constraints.getChecks();
-        assertEquals(1, checks.size());
-        assertEquals(Set.of("`age` > 0 and `age` < 120"), checks);
-        final List<UniqueDto> uniques = constraints.getUniques();
-        assertEquals(1, uniques.size());
-        assertEquals(2, uniques.get(0).getColumns().size());
-        assertEquals("not_in_metadata_db", uniques.get(0).getTable().getName());
-        assertEquals("not_in_metadata_db", uniques.get(0).getTable().getInternalName());
-        assertEquals("given_name", uniques.get(0).getColumns().get(0).getInternalName());
-        assertEquals("family_name", uniques.get(0).getColumns().get(1).getInternalName());
-        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
-        assertEquals(0, foreignKeys.size());
-    }
-
-    @Test
-    public void inspectTableEnum_succeeds() throws TableNotFoundException, SQLException {
-
-        /* test */
-        final TableDto response = schemaService.inspectTable(DATABASE_2_PRIVILEGED_DTO, "experiments");
-        assertEquals("experiments", response.getInternalName());
-        assertEquals("experiments", response.getName());
-        assertEquals(DATABASE_2_ID, response.getTdbid());
-        assertTrue(response.getIsVersioned());
-        assertEquals(DATABASE_2_PUBLIC, response.getIsPublic());
-        assertNotNull(response.getOwner());
-        assertEquals(DATABASE_2_OWNER, response.getOwner().getId());
-        assertEquals(USER_2_NAME, response.getOwner().getName());
-        assertEquals(USER_2_USERNAME, response.getOwner().getUsername());
-        assertEquals(USER_2_FIRSTNAME, response.getOwner().getFirstname());
-        assertEquals(USER_2_LASTNAME, response.getOwner().getLastname());
-        assertEquals(USER_2_QUALIFIED_NAME, response.getOwner().getQualifiedName());
-        final List<IdentifierDto> identifiers = response.getIdentifiers();
-        assertNotNull(identifiers);
-        assertEquals(0, identifiers.size());
-        final List<ColumnDto> columns = response.getColumns();
-        assertNotNull(columns);
-        assertEquals(3, columns.size());
-        assertColumn(columns.get(0), null, null, DATABASE_2_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        assertColumn(columns.get(1), null, null, DATABASE_2_ID, "mode", "mode", ColumnTypeDto.ENUM, 3L, null, false, null);
-        assertEquals(2, columns.get(1).getEnums().size());
-        assertEquals(List.of("ABC", "DEF"), columns.get(1).getEnums());
-        assertColumn(columns.get(2), null, null, DATABASE_2_ID, "seq", "seq", ColumnTypeDto.SET, 5L, null, true, null);
-        assertEquals(3, columns.get(2).getSets().size());
-        assertEquals(List.of("1", "2", "3"), columns.get(2).getSets());
-        /* ignore rest (constraints) */
-    }
-
-    @Test
-    public void inspectTableFullConstraints_succeeds() throws TableNotFoundException, SQLException {
-
-        /* test */
-        final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "weather_aus");
-        assertEquals("weather_aus", response.getInternalName());
-        assertEquals("weather_aus", response.getName());
-        assertEquals(DATABASE_1_ID, response.getTdbid());
-        assertTrue(response.getIsVersioned());
-        assertEquals(DATABASE_1_PUBLIC, response.getIsPublic());
-        assertNotNull(response.getOwner());
-        assertEquals(DATABASE_1_OWNER, response.getOwner().getId());
-        assertEquals(USER_1_NAME, response.getOwner().getName());
-        assertEquals(USER_1_USERNAME, response.getOwner().getUsername());
-        assertEquals(USER_1_FIRSTNAME, response.getOwner().getFirstname());
-        assertEquals(USER_1_LASTNAME, response.getOwner().getLastname());
-        assertEquals(USER_1_QUALIFIED_NAME, response.getOwner().getQualifiedName());
-        final List<IdentifierDto> identifiers = response.getIdentifiers();
-        assertNotNull(identifiers);
-        assertEquals(0, identifiers.size());
-        final List<ColumnDto> columns = response.getColumns();
-        assertNotNull(columns);
-        assertEquals(5, columns.size());
-        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 20L, 0L, false, null);
-        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, null);
-        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, "Closest city");
-        assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null);
-        assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null);
-        final ConstraintsDto constraints = response.getConstraints();
-        final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey());
-        assertEquals(1, primaryKey.size());
-        final PrimaryKeyDto pk0 = primaryKey.get(0);
-        assertNull(pk0.getId());
-        assertNotNull(pk0.getTable());
-        assertNull(pk0.getTable().getId());
-        assertEquals("weather_aus", pk0.getTable().getName());
-        assertEquals("weather_aus", pk0.getTable().getInternalName());
-        assertEquals("Weather in Australia", pk0.getTable().getDescription());
-        assertNotNull(pk0.getColumn());
-        assertNull(pk0.getColumn().getId());
-        assertNull(pk0.getColumn().getTableId());
-        assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId());
-        assertNull(pk0.getColumn().getAlias());
-        assertEquals("id", pk0.getColumn().getName());
-        assertEquals("id", pk0.getColumn().getInternalName());
-        assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType());
-        final List<UniqueDto> uniques = constraints.getUniques();
-        assertEquals(1, uniques.size());
-        final UniqueDto unique0 = uniques.get(0);
-        assertNotNull(unique0.getTable());
-        assertEquals("some_constraint", unique0.getName());
-        assertNull(unique0.getTable().getId());
-        assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getName());
-        assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getInternalName());
-        assertEquals(TABLE_1_DESCRIPTION, unique0.getTable().getDescription());
-        assertTrue(unique0.getTable().getIsVersioned());
-        assertNotNull(unique0.getColumns());
-        assertEquals(1, unique0.getColumns().size());
-        assertNull(unique0.getColumns().get(0).getId());
-        assertNull(unique0.getColumns().get(0).getTableId());
-        assertEquals("date", unique0.getColumns().get(0).getName());
-        assertEquals("date", unique0.getColumns().get(0).getInternalName());
-        final List<String> checks = new LinkedList<>(constraints.getChecks());
-        assertEquals("`mintemp` > 0", checks.get(0));
-        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
-        assertEquals(1, foreignKeys.size());
-        final ForeignKeyDto fk0 = foreignKeys.get(0);
-        assertNotNull(fk0.getName());
-        assertNotNull(fk0.getReferences());
-        final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0);
-        assertNull(fk0ref0.getId());
-        assertNotNull(fk0ref0.getColumn());
-        assertNotNull(fk0ref0.getReferencedColumn());
-        assertNotNull(fk0ref0.getForeignKey());
-        assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId());
-        assertNull(fk0ref0.getColumn().getId());
-        assertNull(fk0ref0.getColumn().getTableId());
-        assertEquals("location", fk0ref0.getColumn().getName());
-        assertEquals("location", fk0ref0.getColumn().getInternalName());
-        assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId());
-        assertNull(fk0ref0.getReferencedColumn().getId());
-        assertNull(fk0ref0.getReferencedColumn().getTableId());
-        assertEquals("location", fk0ref0.getReferencedColumn().getName());
-        assertEquals("location", fk0ref0.getReferencedColumn().getInternalName());
-        assertNotNull(fk0.getOnUpdate());
-        assertEquals(ReferenceTypeDto.RESTRICT, fk0.getOnUpdate());
-        assertNotNull(fk0.getOnDelete());
-        assertEquals(ReferenceTypeDto.SET_NULL, fk0.getOnDelete());
-        final TableBriefDto fk0table = fk0.getTable();
-        assertNull(fk0table.getId());
-        assertEquals(DATABASE_1_ID, fk0table.getDatabaseId());
-        assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getName());
-        assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getInternalName());
-        assertNotNull(fk0.getOnDelete());
-        assertNotNull(fk0.getOnUpdate());
-        assertNotNull(fk0.getReferencedTable());
-        assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getName());
-        assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getInternalName());
-    }
-
-    @Test
-    public void inspectTable_multipleForeignKeyReferences_succeeds() throws TableNotFoundException, SQLException {
-
-        /* test */
-        final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_foreign_keys");
-        final ConstraintsDto constraints = response.getConstraints();
-        final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys();
-        assertEquals(1, foreignKeys.size());
-        final ForeignKeyDto fk0 = foreignKeys.get(0);
-        assertNotNull(fk0.getName());
-        assertNotNull(fk0.getReferences());
-        final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0);
-        assertNull(fk0ref0.getId());
-        assertNotNull(fk0ref0.getColumn());
-        assertNotNull(fk0ref0.getReferencedColumn());
-        assertNotNull(fk0ref0.getForeignKey());
-        assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId());
-        assertNull(fk0ref0.getColumn().getId());
-        assertNull(fk0ref0.getColumn().getTableId());
-        assertEquals("weather_id", fk0ref0.getColumn().getName());
-        assertEquals("weather_id", fk0ref0.getColumn().getInternalName());
-        assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId());
-        assertNull(fk0ref0.getReferencedColumn().getId());
-        assertNull(fk0ref0.getReferencedColumn().getTableId());
-        assertEquals("id", fk0ref0.getReferencedColumn().getName());
-        assertEquals("id", fk0ref0.getReferencedColumn().getInternalName());
-        final ForeignKeyReferenceDto fk0ref1 = fk0.getReferences().get(1);
-        assertNull(fk0ref1.getId());
-        assertNotNull(fk0ref1.getColumn());
-        assertNotNull(fk0ref1.getReferencedColumn());
-        assertNotNull(fk0ref1.getForeignKey());
-        assertEquals(DATABASE_1_ID, fk0ref1.getColumn().getDatabaseId());
-        assertNull(fk0ref1.getColumn().getId());
-        assertNull(fk0ref1.getColumn().getTableId());
-        assertEquals("other_id", fk0ref1.getColumn().getName());
-        assertEquals("other_id", fk0ref1.getColumn().getInternalName());
-        assertEquals(DATABASE_1_ID, fk0ref1.getReferencedColumn().getDatabaseId());
-        assertNull(fk0ref1.getReferencedColumn().getId());
-        assertNull(fk0ref1.getReferencedColumn().getTableId());
-        assertEquals("other_id", fk0ref1.getReferencedColumn().getName());
-        assertEquals("other_id", fk0ref1.getReferencedColumn().getInternalName());
-        final TableBriefDto fk0refT0 = fk0.getTable();
-        assertNull(fk0refT0.getId());
-        assertEquals(DATABASE_1_ID, fk0refT0.getDatabaseId());
-        assertEquals("complex_foreign_keys", fk0refT0.getName());
-        assertEquals("complex_foreign_keys", fk0refT0.getInternalName());
-        assertNotNull(fk0.getReferencedTable());
-        assertEquals("complex_primary_key", fk0.getReferencedTable().getName());
-        assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName());
-        assertNotNull(fk0.getOnDelete());
-        assertNotNull(fk0.getOnUpdate());
-    }
-
-    @Test
-    public void inspectTable_multiplePrimaryKey_succeeds() throws TableNotFoundException, SQLException {
-
-        /* test */
-        final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_primary_key");
-        final ConstraintsDto constraints = response.getConstraints();
-        final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey());
-        assertEquals(2, primaryKey.size());
-        final PrimaryKeyDto pk0 = primaryKey.get(0);
-        assertNull(pk0.getId());
-        assertNotNull(pk0.getTable());
-        assertNull(pk0.getTable().getId());
-        assertEquals("complex_primary_key", pk0.getTable().getName());
-        assertEquals("complex_primary_key", pk0.getTable().getInternalName());
-        assertNotNull(pk0.getColumn());
-        assertNull(pk0.getColumn().getId());
-        assertNull(pk0.getColumn().getTableId());
-        assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId());
-        assertNull(pk0.getColumn().getAlias());
-        assertEquals("id", pk0.getColumn().getName());
-        assertEquals("id", pk0.getColumn().getInternalName());
-        assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType());
-        final PrimaryKeyDto pk1 = primaryKey.get(1);
-        assertNull(pk1.getId());
-        assertNotNull(pk1.getTable());
-        assertNull(pk1.getTable().getId());
-        assertEquals("complex_primary_key", pk1.getTable().getName());
-        assertEquals("complex_primary_key", pk1.getTable().getInternalName());
-        assertNotNull(pk1.getColumn());
-        assertNull(pk1.getColumn().getId());
-        assertNull(pk1.getColumn().getTableId());
-        assertEquals(DATABASE_1_ID, pk1.getColumn().getDatabaseId());
-        assertNull(pk1.getColumn().getAlias());
-        assertEquals("other_id", pk1.getColumn().getName());
-        assertEquals("other_id", pk1.getColumn().getInternalName());
-        assertEquals(ColumnTypeDto.BIGINT, pk1.getColumn().getColumnType());
-    }
-
-    @Test
-    public void inspectTable_exoticBoolean_succeeds() throws TableNotFoundException, SQLException {
-
-        /* test */
-        final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "exotic_boolean");
-        final ConstraintsDto constraints = response.getConstraints();
-        final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey());
-        assertEquals(1, primaryKey.size());
-        final PrimaryKeyDto pk0 = primaryKey.get(0);
-        assertNull(pk0.getId());
-        assertNotNull(pk0.getTable());
-        assertNull(pk0.getTable().getId());
-        assertEquals("exotic_boolean", pk0.getTable().getName());
-        assertEquals("exotic_boolean", pk0.getTable().getInternalName());
-        assertNotNull(pk0.getColumn());
-        assertNull(pk0.getColumn().getId());
-        assertNull(pk0.getColumn().getTableId());
-        assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId());
-        assertNull(pk0.getColumn().getAlias());
-        assertEquals("bool_default", pk0.getColumn().getName());
-        assertEquals("bool_default", pk0.getColumn().getInternalName());
-        assertEquals(ColumnTypeDto.BOOL, pk0.getColumn().getColumnType());
-        final List<ColumnDto> columns = response.getColumns();
-        assertEquals(3, columns.size());
-        assertColumn(columns.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null);
-        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null);
-        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null);
-    }
-
-    @Test
-    public void inspectView_succeeds() throws SQLException, ViewNotFoundException {
-
-        /* test */
-        final ViewDto response = schemaService.inspectView(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db2");
-        assertEquals("not_in_metadata_db2", response.getInternalName());
-        assertEquals("not_in_metadata_db2", response.getName());
-        assertEquals(DATABASE_1_ID, response.getVdbid());
-        assertEquals(DATABASE_1_OWNER, response.getOwner().getId());
-        assertFalse(response.getIsInitialView());
-        assertEquals(DATABASE_1_PUBLIC, response.getIsPublic());
-        assertTrue(response.getQuery().length() >= 69);
-        assertNotNull(response.getQueryHash());
-        assertEquals(4, response.getColumns().size());
-        final ViewColumnDto column0 = response.getColumns().get(0);
-        assertNotNull(column0.getName());
-        assertEquals("date", column0.getInternalName());
-        assertEquals(DATABASE_1_ID, column0.getDatabaseId());
-        final ViewColumnDto column1 = response.getColumns().get(1);
-        assertNotNull(column1.getName());
-        assertEquals("location", column1.getInternalName());
-        assertEquals(DATABASE_1_ID, column1.getDatabaseId());
-        final ViewColumnDto column2 = response.getColumns().get(2);
-        assertNotNull(column2.getName());
-        assertEquals("MinTemp", column2.getInternalName());
-        assertEquals(DATABASE_1_ID, column2.getDatabaseId());
-        final ViewColumnDto column3 = response.getColumns().get(3);
-        assertNotNull(column3.getName());
-        assertEquals("Rainfall", column3.getInternalName());
-        assertEquals(DATABASE_1_ID, column3.getDatabaseId());
-    }
-
-    protected static void assertViewColumn(ViewColumnDto column, ViewColumnDto other) {
-        assertNotNull(column);
-        assertNotNull(other);
-        assertEquals(column.getId(), other.getId());
-        assertEquals(column.getDatabaseId(), other.getDatabaseId());
-        assertEquals(column.getName(), other.getName());
-        assertEquals(column.getInternalName(), other.getInternalName());
-        assertEquals(column.getColumnType(), other.getColumnType());
-        assertEquals(column.getSize(), other.getSize());
-        assertEquals(column.getD(), other.getD());
-        assertEquals(column.getIsNullAllowed(), other.getIsNullAllowed());
-        assertEquals(column.getDescription(), other.getDescription());
-    }
-
-    protected static void assertColumn(ColumnDto column, Long id, Long tableId, Long databaseId, String name,
-                                       String internalName, ColumnTypeDto type, Long size, Long d, Boolean nullAllowed,
-                                       String description) {
-        log.trace("assert column: {}", internalName);
-        assertNotNull(column);
-        assertEquals(id, column.getId());
-        assertEquals(tableId, column.getTableId());
-        assertEquals(databaseId, column.getDatabaseId());
-        assertEquals(name, column.getName());
-        assertEquals(internalName, column.getInternalName());
-        assertEquals(type, column.getColumnType());
-        assertEquals(size, column.getSize());
-        assertEquals(d, column.getD());
-        assertEquals(nullAllowed, column.getIsNullAllowed());
-        assertEquals(description, column.getDescription());
-    }
-
-}
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 0eab9c6ff3e012950dd011f472ca65e67c4912e9..56115690b503ce3c71bb241fdd84704710a0bb0b 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
@@ -21,7 +21,6 @@ import org.testcontainers.junit.jupiter.Testcontainers;
 
 import java.sql.SQLException;
 import java.util.List;
-import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.when;
@@ -46,7 +45,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
         genesis();
         /* metadata database */
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO);
     }
 
     @Test
@@ -129,25 +128,6 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
         assertFalse(response.getIsPersisted());
     }
 
-    @Test
-    public void createQueryStore_succeeds() throws SQLException, QueryStoreCreateException, InterruptedException {
-
-        /* mock */
-        MariaDbConfig.dropQueryStore(DATABASE_1_PRIVILEGED_DTO);
-
-        /* test */
-        createQueryStore_generic(DATABASE_1_INTERNALNAME);
-    }
-
-    @Test
-    public void createQueryStore_fails() {
-
-        /* test */
-        assertThrows(QueryStoreCreateException.class, () -> {
-            createQueryStore_generic(DATABASE_1_INTERNALNAME);
-        });
-    }
-
     protected void findById_generic(Long queryId) throws RemoteUnavailableException, SQLException,
             UserNotFoundException, QueryNotFoundException, MetadataServiceException, DatabaseNotFoundException,
             InterruptedException {
@@ -201,16 +181,4 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest {
         queryService.persist(DATABASE_1_PRIVILEGED_DTO, queryId, persist);
     }
 
-    protected void createQueryStore_generic(String databaseName) throws SQLException, QueryStoreCreateException,
-            InterruptedException {
-
-        /* pre-condition */
-        Thread.sleep(1000) /* wait for test container some more */;
-
-        /* test */
-        queryService.createQueryStore(CONTAINER_1_PRIVILEGED_DTO, databaseName);
-        final List<Map<String, Object>> response = MariaDbConfig.listQueryStore(DATABASE_1_PRIVILEGED_DTO);
-        assertEquals(0, response.size());
-    }
-
 }
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 383c44770f251876836190f7729834c6d8ba84b5..f235f39d63a905e34017933bcc6365c85a299442 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
@@ -2,31 +2,21 @@ package at.tuwien.service;
 
 import at.tuwien.api.database.query.ImportDto;
 import at.tuwien.api.database.table.*;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.columns.ColumnStatisticDto;
-import at.tuwien.api.database.table.columns.ColumnTypeDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
-import at.tuwien.api.database.table.constraints.ConstraintsDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
-import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
-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.S3Config;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.test.AbstractUnitTest;
 import com.google.common.io.Files;
 import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.context.DynamicPropertyRegistry;
 import org.springframework.test.context.DynamicPropertySource;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -44,11 +34,12 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.sql.SQLException;
 import java.time.Instant;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
-import static at.tuwien.service.SchemaServiceIntegrationTest.assertColumn;
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.when;
 
 @Log4j2
 @SpringBootTest
@@ -65,9 +56,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     @Autowired
     private S3Config s3Config;
 
-    @MockBean
-    private MetadataServiceGateway metadataServiceGateway;
-
     @Container
     private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
 
@@ -91,8 +79,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
         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);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_PRIVILEGED_DTO);
         /* s3 */
         if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3Bucket()))) {
             s3Client.createBucket(CreateBucketRequest.builder()
@@ -107,8 +95,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
-            TableNotFoundException, TableMalformedException, QueryMalformedException, MetadataServiceException {
+    public void updateTuple_succeeds() throws SQLException, TableMalformedException, QueryMalformedException {
         /* modify row based on primary key */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -122,12 +109,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 1", Set.of("id", "date", "location", "mintemp", "rainfall"));
@@ -139,9 +120,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_modifyPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            MetadataServiceException {
+    public void updateTuple_modifyPrimaryKey_succeeds() throws SQLException, TableMalformedException,
+            QueryMalformedException {
         /* modify row primary key based on primary key */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -156,12 +136,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 4", Set.of("id", "date", "location", "mintemp", "rainfall"));
@@ -173,9 +147,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_missingPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            MetadataServiceException {
+    public void updateTuple_missingPrimaryKey_succeeds() throws SQLException, TableMalformedException,
+            QueryMalformedException {
         /* modify row based on non-primary key column */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -189,12 +162,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 1", Set.of("id", "date", "location", "mintemp", "rainfall"));
@@ -206,9 +173,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updateTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            MetadataServiceException {
+    public void updateTuple_notInOrder_succeeds() throws SQLException, TableMalformedException,
+            QueryMalformedException {
         /* modify row based on non-primary key column */
         final TupleUpdateDto request = TupleUpdateDto.builder()
                 .data(new HashMap<>() {{
@@ -222,12 +188,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 1", Set.of("id", "date", "location", "mintemp", "rainfall"));
@@ -239,9 +199,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
-            TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException,
-            StorageNotFoundException, MetadataServiceException {
+    public void createTuple_succeeds() throws SQLException, TableMalformedException, QueryMalformedException,
+            StorageUnavailableException, StorageNotFoundException {
         /* add row with primary key */
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -253,12 +212,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.createTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 4", Set.of("id", "date", "location", "mintemp", "rainfall"));
@@ -270,9 +223,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTuple_autogeneratedBlob_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
-            TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException,
-            StorageNotFoundException, MetadataServiceException, IOException {
+    public void createTuple_autogeneratedBlob_succeeds() throws SQLException, TableMalformedException,
+            QueryMalformedException, StorageUnavailableException, StorageNotFoundException, IOException {
         /* add row with primary key */
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -282,10 +234,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 .build();
 
         /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID))
-                .thenReturn(TABLE_8_PRIVILEGED_DTO);
         s3Client.putObject(PutObjectRequest.builder()
                 .key("s3key")
                 .bucket(s3Config.getS3Bucket())
@@ -299,9 +247,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void createTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            StorageUnavailableException, StorageNotFoundException, MetadataServiceException {
+    public void createTuple_notInOrder_succeeds() throws SQLException, TableMalformedException, QueryMalformedException,
+            StorageUnavailableException, StorageNotFoundException {
         /* add row with primary key */
         final TupleDto request = TupleDto.builder()
                 .data(new HashMap<>() {{
@@ -313,12 +260,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.createTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 4", Set.of("id", "date", "location", "mintemp", "rainfall"));
@@ -330,8 +271,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void deleteTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException,
-            TableNotFoundException, TableMalformedException, QueryMalformedException, MetadataServiceException {
+    public void deleteTuple_succeeds() throws SQLException, TableMalformedException, QueryMalformedException {
         /* delete row based on primary key */
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
@@ -339,12 +279,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.deleteTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id FROM weather_aus WHERE id = 1", Set.of("id"));
@@ -352,9 +286,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
     }
 
     @Test
-    public void deleteTuple_withoutPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException,
-            ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException,
-            MetadataServiceException {
+    public void deleteTuple_withoutPrimaryKey_succeeds() throws SQLException, TableMalformedException,
+            QueryMalformedException {
         /* remove row based on non-primary key */
         final TupleDeleteDto request = TupleDeleteDto.builder()
                 .keys(new HashMap<>() {{
@@ -363,169 +296,12 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
                 }})
                 .build();
 
-        /* mock */
-        when(metadataServiceGateway.getContainerById(CONTAINER_1_ID))
-                .thenReturn(CONTAINER_1_PRIVILEGED_DTO);
-        when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID))
-                .thenReturn(TABLE_1_PRIVILEGED_DTO);
-
         /* test */
         tableService.deleteTuple(TABLE_1_PRIVILEGED_DTO, request);
         final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id FROM weather_aus WHERE id = 1", Set.of("id"));
         assertEquals(0, result.size());
     }
 
-    @Test
-    public void getSchemas_succeeds() throws TableNotFoundException, SQLException, DatabaseMalformedException {
-
-        /* test */
-        final List<TableDto> response = tableService.getSchemas(DATABASE_1_PRIVILEGED_DTO);
-        assertEquals(4, response.size());
-        final TableDto table0 = response.get(0);
-        Assertions.assertEquals("complex_foreign_keys", table0.getInternalName());
-        Assertions.assertEquals("complex_foreign_keys", table0.getName());
-        Assertions.assertEquals(DATABASE_1_ID, table0.getTdbid());
-        assertTrue(table0.getIsVersioned());
-        Assertions.assertEquals(DATABASE_1_PUBLIC, table0.getIsPublic());
-        final List<ColumnDto> columns0 = table0.getColumns();
-        assertNotNull(columns0);
-        Assertions.assertEquals(3, columns0.size());
-        assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        final ConstraintsDto constraints0 = table0.getConstraints();
-        assertNotNull(constraints0);
-        assertEquals(1, constraints0.getPrimaryKey().size());
-        final PrimaryKeyDto pk0 = new LinkedList<>(constraints0.getPrimaryKey()).get(0);
-        assertNull(pk0.getId());
-        assertNull(pk0.getColumn().getId());
-        assertEquals("id", pk0.getColumn().getName());
-        assertEquals("id", pk0.getColumn().getInternalName());
-        assertEquals(1, constraints0.getForeignKeys().size());
-        final ForeignKeyDto fk0 = constraints0.getForeignKeys().get(0);
-        assertNotNull(fk0.getName());
-        assertNull(fk0.getTable().getId());
-        assertEquals("complex_foreign_keys", fk0.getTable().getName());
-        assertEquals("complex_foreign_keys", fk0.getTable().getInternalName());
-        assertNull(fk0.getReferencedTable().getId());
-        assertEquals("complex_primary_key", fk0.getReferencedTable().getName());
-        assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName());
-        assertEquals(2, fk0.getReferences().size());
-        final ForeignKeyReferenceDto fk0r0 = fk0.getReferences().get(0);
-        assertEquals("weather_id", fk0r0.getColumn().getName());
-        assertEquals("weather_id", fk0r0.getColumn().getInternalName());
-        assertNotNull(fk0r0.getColumn().getName());
-        assertNotNull(fk0r0.getForeignKey());
-        assertEquals("id", fk0r0.getReferencedColumn().getName());
-        assertEquals("id", fk0r0.getReferencedColumn().getInternalName());
-        final ForeignKeyReferenceDto fk0r1 = fk0.getReferences().get(1);
-        assertEquals("other_id", fk0r1.getColumn().getName());
-        assertEquals("other_id", fk0r1.getColumn().getInternalName());
-        assertNotNull(fk0r1.getColumn().getName());
-        assertNotNull(fk0r1.getForeignKey());
-        assertEquals("other_id", fk0r1.getReferencedColumn().getName());
-        assertEquals("other_id", fk0r1.getReferencedColumn().getInternalName());
-        assertEquals(0, constraints0.getChecks().size());
-        assertEquals(0, constraints0.getUniques().size());
-        /* table 1 */
-        final TableDto table1 = response.get(1);
-        Assertions.assertEquals("complex_primary_key", table1.getInternalName());
-        Assertions.assertEquals("complex_primary_key", table1.getName());
-        Assertions.assertEquals(DATABASE_1_ID, table1.getTdbid());
-        assertTrue(table1.getIsVersioned());
-        Assertions.assertEquals(DATABASE_1_PUBLIC, table1.getIsPublic());
-        final List<ColumnDto> columns1 = table1.getColumns();
-        assertNotNull(columns1);
-        Assertions.assertEquals(2, columns1.size());
-        assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        final ConstraintsDto constraints1 = table1.getConstraints();
-        assertNotNull(constraints1);
-        assertEquals(2, constraints1.getPrimaryKey().size());
-        final PrimaryKeyDto pk10 = new LinkedList<>(constraints1.getPrimaryKey()).get(0);
-        assertNull(pk10.getId());
-        assertNull(pk10.getColumn().getId());
-        assertEquals("id", pk10.getColumn().getName());
-        assertEquals("id", pk10.getColumn().getInternalName());
-        final PrimaryKeyDto pk11 = new LinkedList<>(constraints1.getPrimaryKey()).get(1);
-        assertNull(pk11.getId());
-        assertNull(pk11.getColumn().getId());
-        assertEquals("other_id", pk11.getColumn().getName());
-        assertEquals("other_id", pk11.getColumn().getInternalName());
-        assertEquals(0, constraints1.getForeignKeys().size());
-        assertEquals(0, constraints1.getChecks().size());
-        assertEquals(0, constraints1.getUniques().size());
-        /* table 2 */
-        final TableDto table2 = response.get(2);
-        Assertions.assertEquals("exotic_boolean", table2.getInternalName());
-        Assertions.assertEquals("exotic_boolean", table2.getName());
-        Assertions.assertEquals(DATABASE_1_ID, table2.getTdbid());
-        assertTrue(table2.getIsVersioned());
-        Assertions.assertEquals(DATABASE_1_PUBLIC, table2.getIsPublic());
-        final List<ColumnDto> columns2 = table2.getColumns();
-        assertNotNull(columns2);
-        Assertions.assertEquals(3, columns2.size());
-        assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null);
-        assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null);
-        assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null);
-        final ConstraintsDto constraints2 = table2.getConstraints();
-        assertNotNull(constraints2);
-        final Set<PrimaryKeyDto> primaryKey2 = constraints2.getPrimaryKey();
-        Assertions.assertEquals(1, primaryKey2.size());
-        final Set<String> checks2 = constraints2.getChecks();
-        Assertions.assertEquals(0, checks2.size());
-        final List<UniqueDto> uniques2 = constraints2.getUniques();
-        Assertions.assertEquals(0, uniques2.size());
-        /* table 3 */
-        final TableDto table3 = response.get(3);
-        Assertions.assertEquals("not_in_metadata_db", table3.getInternalName());
-        Assertions.assertEquals("not_in_metadata_db", table3.getName());
-        Assertions.assertEquals(DATABASE_1_ID, table3.getTdbid());
-        assertTrue(table3.getIsVersioned());
-        Assertions.assertEquals(DATABASE_1_PUBLIC, table3.getIsPublic());
-        final List<ColumnDto> columns3 = table3.getColumns();
-        assertNotNull(columns3);
-        Assertions.assertEquals(5, columns3.size());
-        assertColumn(columns3.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null);
-        assertColumn(columns3.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
-        assertColumn(columns3.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null);
-        assertColumn(columns3.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null);
-        assertColumn(columns3.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null);
-        final ConstraintsDto constraints3 = table3.getConstraints();
-        assertNotNull(constraints3);
-        final Set<PrimaryKeyDto> primaryKey3 = constraints3.getPrimaryKey();
-        Assertions.assertEquals(1, primaryKey3.size());
-        final Set<String> checks3 = constraints3.getChecks();
-        Assertions.assertEquals(1, checks3.size());
-        Assertions.assertEquals(Set.of("`age` > 0 and `age` < 120"), checks3);
-        final List<UniqueDto> uniques3 = constraints3.getUniques();
-        Assertions.assertEquals(1, uniques3.size());
-        Assertions.assertEquals(2, uniques3.get(0).getColumns().size());
-        Assertions.assertEquals("not_in_metadata_db", uniques3.get(0).getTable().getInternalName());
-        Assertions.assertEquals("given_name", uniques3.get(0).getColumns().get(0).getInternalName());
-        Assertions.assertEquals("family_name", uniques3.get(0).getColumns().get(1).getInternalName());
-    }
-
-    @Test
-    public void create_succeeds() throws TableNotFoundException, TableMalformedException, SQLException,
-            TableExistsException {
-
-        /* test */
-        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());
-        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, null);
-        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "value", "value", ColumnTypeDto.DECIMAL, 10L, 10L, true, 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
     @Disabled("Not stable CI/CD")
     public void getStatistics_succeeds() throws TableMalformedException, SQLException, TableNotFoundException {
@@ -556,100 +332,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest {
         assertNotNull(column4.getStdDev());
     }
 
-    @Test
-    public void create_malformed_fails() {
-        final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder()
-                .name("missing_foreign_key")
-                .columns(List.of())
-                .constraints(ConstraintsCreateDto.builder()
-                        .foreignKeys(List.of(ForeignKeyCreateDto.builder()
-                                .columns(List.of("i_do_not_exist"))
-                                .referencedTable("neither_do_i")
-                                .referencedColumns(List.of("behold"))
-                                .build()))
-                        .build())
-                .build();
-
-        /* test */
-        assertThrows(TableMalformedException.class, () -> {
-            tableService.createTable(DATABASE_1_PRIVILEGED_DTO, request);
-        });
-    }
-
-    @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);
-        assertColumn(columns.get(1), null, null, DATABASE_1_ID, "lat", "lat", ColumnTypeDto.DECIMAL, 10L, 10L, false, null);
-        assertColumn(columns.get(2), null, null, DATABASE_1_ID, "lng", "lng", ColumnTypeDto.DECIMAL, 10L, 10L, false, 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 {
-
-        /* mock */
-        MariaDbConfig.dropTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNAL_NAME);
-
-        /* test */
-        final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_CREATE_INTERNAL_DTO);
-        assertEquals(TABLE_1_NAME, response.getName());
-        assertEquals(TABLE_1_INTERNAL_NAME, response.getInternalName());
-        assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size());
-    }
-
     @Test
     public void delete_succeeds() throws SQLException, QueryMalformedException {
 
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
index b5555611c666f60f0af6e2d8a122dc11ec3264dd..2edf7f5f28a2e607ba55eb38ca82547f112a60f5 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
@@ -1,12 +1,8 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.ViewColumnDto;
-import at.tuwien.api.database.ViewDto;
 import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
-import at.tuwien.exception.DatabaseMalformedException;
 import at.tuwien.exception.ViewMalformedException;
-import at.tuwien.exception.ViewNotFoundException;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -20,9 +16,6 @@ import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
 import java.sql.SQLException;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.*;
 
 @Log4j2
 @SpringBootTest
@@ -41,46 +34,14 @@ public class ViewServiceIntegrationTest extends AbstractUnitTest {
         genesis();
         /* metadata database */
         MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME);
-        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO);
+        MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO);
     }
 
     @Test
     public void delete_succeeds() throws SQLException, ViewMalformedException {
 
         /* test */
-        viewService.delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME);
-    }
-
-    @Test
-    public void create_succeeds() throws SQLException, ViewMalformedException {
-
-        /* test */
-        viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO);
-    }
-
-    @Test
-    public void getSchemas_succeeds() throws SQLException, ViewNotFoundException, DatabaseMalformedException {
-
-        /* test */
-        final List<ViewDto> response = viewService.getSchemas(DATABASE_1_PRIVILEGED_DTO);
-        final ViewDto view0 = response.get(0);
-        assertEquals("not_in_metadata_db2", view0.getName());
-        assertEquals("not_in_metadata_db2", view0.getInternalName());
-        assertEquals(DATABASE_1_ID, view0.getVdbid());
-        assertEquals(DATABASE_1_OWNER, view0.getOwner().getId());
-        assertFalse(view0.getIsInitialView());
-        assertEquals(DATABASE_1_PUBLIC, view0.getIsPublic());
-        assertTrue(view0.getQuery().length() >= 69);
-        assertNotNull(view0.getQueryHash());
-        assertEquals(4, view0.getColumns().size());
-        final ViewColumnDto column0a = view0.getColumns().get(0);
-        assertEquals("date", column0a.getInternalName());
-        final ViewColumnDto column1a = view0.getColumns().get(1);
-        assertEquals("location", column1a.getInternalName());
-        final ViewColumnDto column2a = view0.getColumns().get(2);
-        assertEquals("MinTemp", column2a.getInternalName());
-        final ViewColumnDto column3a = view0.getColumns().get(3);
-        assertEquals("Rainfall", column3a.getInternalName());
+        viewService.delete(VIEW_1_PRIVILEGED_DTO);
     }
 
 }
diff --git a/dbrepo-data-service/services/pom.xml b/dbrepo-data-service/services/pom.xml
index 666cda76a43da22b1993729bf9df8c58ca4d75e9..04ddee3c59536698ac1fb63cd094f93410941328 100644
--- a/dbrepo-data-service/services/pom.xml
+++ b/dbrepo-data-service/services/pom.xml
@@ -6,18 +6,18 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>services</artifactId>
     <name>dbrepo-data-service-services</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
             <groupId>at.tuwien</groupId>
             <artifactId>dbrepo-data-service-querystore</artifactId>
-            <version>1.6.1</version>
+            <version>1.6.3</version>
         </dependency>
     </dependencies>
 
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java
index 45654157d1a7564d6504e08bd6d6d5fa5d24b206..c798537b5b378822a82119b2ffcb7ec4c7bf1384 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java
@@ -1,11 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.user.UserDto;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import org.springframework.beans.factory.annotation.Value;
@@ -22,13 +22,13 @@ public class CacheConfig {
     private Long credentialCacheTimeout;
 
     @Bean
-    public Cache<UUID, PrivilegedUserDto> userCache() {
-        return new ExpiryCache<UUID, PrivilegedUserDto>().build();
+    public Cache<UUID, UserDto> userCache() {
+        return new ExpiryCache<UUID, UserDto>().build();
     }
 
     @Bean
-    public Cache<Long, PrivilegedViewDto> viewCache() {
-        return new ExpiryCache<Long, PrivilegedViewDto>().build();
+    public Cache<Long, ViewDto> viewCache() {
+        return new ExpiryCache<Long, ViewDto>().build();
     }
 
     @Bean
@@ -37,18 +37,18 @@ public class CacheConfig {
     }
 
     @Bean
-    public Cache<Long, PrivilegedTableDto> tableCache() {
-        return new ExpiryCache<Long, PrivilegedTableDto>().build();
+    public Cache<Long, TableDto> tableCache() {
+        return new ExpiryCache<Long, TableDto>().build();
     }
 
     @Bean
-    public Cache<Long, PrivilegedDatabaseDto> databaseCache() {
-        return new ExpiryCache<Long, PrivilegedDatabaseDto>().build();
+    public Cache<Long, DatabaseDto> databaseCache() {
+        return new ExpiryCache<Long, DatabaseDto>().build();
     }
 
     @Bean
-    public Cache<Long, PrivilegedContainerDto> containerCache() {
-        return new ExpiryCache<Long, PrivilegedContainerDto>().build();
+    public Cache<Long, ContainerDto> containerCache() {
+        return new ExpiryCache<Long, ContainerDto>().build();
     }
 
     class ExpiryCache<K, T> {
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 e2851071dad176ca44a9f2d0952a0392101ad2eb..f7fe2f207512791b17144cea27cedcc5f7bfd2b9 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
@@ -1,13 +1,12 @@
 package at.tuwien.gateway;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.identifier.IdentifierBriefDto;
 import at.tuwien.api.user.UserDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
 import at.tuwien.exception.*;
 import jakarta.validation.constraints.NotNull;
 
@@ -20,12 +19,12 @@ public interface MetadataServiceGateway {
      * Get a container with given id from the metadata service.
      *
      * @param containerId The container id
-     * @return The container with privileged connection information, if successful.
+     * @return The container with  connection information, if successful.
      * @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.
      */
-    PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
+    ContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
             ContainerNotFoundException, MetadataServiceException;
 
     /**
@@ -37,7 +36,7 @@ public interface MetadataServiceGateway {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
+    DatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
             MetadataServiceException;
 
     /**
@@ -50,7 +49,7 @@ public interface MetadataServiceGateway {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException,
+    TableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException,
             MetadataServiceException;
 
     /**
@@ -63,7 +62,7 @@ public interface MetadataServiceGateway {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException,
+    ViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException,
             MetadataServiceException;
 
     /**
@@ -77,18 +76,6 @@ public interface MetadataServiceGateway {
      */
     UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException;
 
-    /**
-     * Get a user with given user id from the metadata service.
-     *
-     * @param userId The user id.
-     * @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.
-     */
-    PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
-            MetadataServiceException;
-
     /**
      * Get database access for a given user and database id from the metadata service.
      *
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 7d834992cc73b689bc990b6639061ae1ca2ddb71..7b02192b7ed0209bae55614808e5c236d03da6ef 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
@@ -1,17 +1,12 @@
 package at.tuwien.gateway.impl;
 
 import at.tuwien.api.container.ContainerDto;
-import at.tuwien.api.container.image.ImageDto;
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
 import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.identifier.IdentifierBriefDto;
 import at.tuwien.api.user.UserDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
 import at.tuwien.config.GatewayConfig;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
@@ -36,27 +31,24 @@ import java.util.UUID;
 @Service
 public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
 
-    private final RestTemplate restTemplate;
     private final RestTemplate internalRestTemplate;
     private final GatewayConfig gatewayConfig;
     private final MetadataMapper metadataMapper;
 
     @Autowired
     public MetadataServiceGatewayImpl(@Qualifier("internalRestTemplate") RestTemplate internalRestTemplate,
-                                      RestTemplate restTemplate, GatewayConfig gatewayConfig,
-                                      MetadataMapper metadataMapper) {
-        this.restTemplate = restTemplate;
+                                      GatewayConfig gatewayConfig, MetadataMapper metadataMapper) {
         this.internalRestTemplate = internalRestTemplate;
         this.gatewayConfig = gatewayConfig;
         this.metadataMapper = metadataMapper;
     }
 
     @Override
-    public PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
+    public ContainerDto getContainerById(Long containerId) throws RemoteUnavailableException,
             ContainerNotFoundException, MetadataServiceException {
         final ResponseEntity<ContainerDto> response;
         final String url = "/api/container/" + containerId;
-        log.debug("get privileged container info from metadata service: {}", url);
+        log.debug("get  container info from metadata service: {}", url);
         try {
             response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY,
                     ContainerDto.class);
@@ -73,16 +65,16 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         final List<String> expectedHeaders = List.of("X-Username", "X-Password");
         if (!response.getHeaders().keySet().containsAll(expectedHeaders)) {
-            log.error("Failed to find all privileged container headers");
+            log.error("Failed to find all  container headers");
             log.debug("expected headers: {}", expectedHeaders);
             log.debug("found headers: {}", response.getHeaders().keySet());
-            throw new MetadataServiceException("Failed to find all privileged container headers");
+            throw new MetadataServiceException("Failed to find all  container headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find container with id {}: body is empty", containerId);
             throw new MetadataServiceException("Failed to find container with id " + containerId + ": body is empty");
         }
-        final PrivilegedContainerDto container = metadataMapper.containerDtoToPrivilegedContainerDto(response.getBody());
+        final ContainerDto container = metadataMapper.containerDtoToContainerDto(response.getBody());
         container.setUsername(response.getHeaders().get("X-Username").get(0));
         container.setPassword(response.getHeaders().get("X-Password").get(0));
         container.setLastRetrieved(Instant.now());
@@ -90,13 +82,13 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
     }
 
     @Override
-    public PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
+    public DatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
             MetadataServiceException {
-        final ResponseEntity<PrivilegedDatabaseDto> response;
+        final ResponseEntity<DatabaseDto> response;
         final String url = "/api/database/" + id;
-        log.debug("get privileged database info from metadata service: {}", url);
+        log.debug("get  database info from metadata service: {}", url);
         try {
-            response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, PrivilegedDatabaseDto.class);
+            response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, DatabaseDto.class);
         } catch (ResourceAccessException | HttpServerErrorException e) {
             log.error("Failed to find database with id {}: {}", id, e.getMessage());
             throw new RemoteUnavailableException("Failed to find database: " + e.getMessage(), e);
@@ -108,32 +100,30 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
             log.error("Failed to find database with id {}: service responded unsuccessful: {}", id, response.getStatusCode());
             throw new MetadataServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode());
         }
-        final List<String> expectedHeaders = List.of("X-Username", "X-Password", "X-Host", "X-Port");
+        final List<String> expectedHeaders = List.of("X-Username", "X-Password");
         if (!response.getHeaders().keySet().containsAll(expectedHeaders)) {
-            log.error("Failed to find all privileged database headers");
+            log.error("Failed to find all  database headers");
             log.debug("expected headers: {}", expectedHeaders);
             log.debug("found headers: {}", response.getHeaders().keySet());
-            throw new MetadataServiceException("Failed to find all privileged database headers");
+            throw new MetadataServiceException("Failed to find all  database headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find database with id {}: body is empty", id);
             throw new MetadataServiceException("Failed to find database with id " + id + ": body is empty");
         }
-        final PrivilegedDatabaseDto database = response.getBody();
+        final DatabaseDto database = response.getBody();
         database.getContainer().setUsername(response.getHeaders().get("X-Username").get(0));
         database.getContainer().setPassword(response.getHeaders().get("X-Password").get(0));
-        database.getContainer().setHost(response.getHeaders().get("X-Host").get(0));
-        database.getContainer().setPort(Integer.parseInt(response.getHeaders().get("X-Port").get(0)));
         database.setLastRetrieved(Instant.now());
         return database;
     }
 
     @Override
-    public PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException,
+    public TableDto getTableById(Long databaseId, Long id) throws TableNotFoundException,
             RemoteUnavailableException, MetadataServiceException {
         final ResponseEntity<TableDto> response;
         final String url = "/api/database/" + databaseId + "/table/" + id;
-        log.debug("get privileged table info from metadata service: {}", url);
+        log.debug("get  table info from metadata service: {}", url);
         try {
             response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, TableDto.class);
         } catch (ResourceAccessException | HttpServerErrorException e) {
@@ -147,35 +137,30 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
             log.error("Failed to find table with id {}: service responded unsuccessful: {}", id, response.getStatusCode());
             throw new MetadataServiceException("Failed to find table: service responded unsuccessful: " + response.getStatusCode());
         }
-        final List<String> expectedHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Table");
+        final List<String> expectedHeaders = List.of("X-Username", "X-Password");
         if (!response.getHeaders().keySet().containsAll(expectedHeaders)) {
-            log.error("Failed to find all privileged table headers");
+            log.error("Failed to find all  table headers");
             log.debug("expected headers: {}", expectedHeaders);
             log.debug("found headers: {}", response.getHeaders().keySet());
-            throw new MetadataServiceException("Failed to find all privileged table headers");
+            throw new MetadataServiceException("Failed to find all  table headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find table with id {}: body is empty", id);
             throw new MetadataServiceException("Failed to find table with id " + id + ": body is empty");
         }
-        final PrivilegedTableDto table = metadataMapper.tableDtoToPrivilegedTableDto(response.getBody());
-        table.getDatabase().getContainer().getImage().setJdbcMethod(response.getHeaders().get("X-Type").get(0));
-        table.getDatabase().getContainer().setHost(response.getHeaders().get("X-Host").get(0));
-        table.getDatabase().getContainer().setPort(Integer.parseInt(response.getHeaders().get("X-Port").get(0)));
+        final TableDto table = metadataMapper.tableDtoToTableDto(response.getBody());
         table.getDatabase().getContainer().setUsername(response.getHeaders().get("X-Username").get(0));
         table.getDatabase().getContainer().setPassword(response.getHeaders().get("X-Password").get(0));
-        table.getDatabase().setInternalName(response.getHeaders().get("X-Database").get(0));
-        table.setInternalName(response.getHeaders().get("X-Table").get(0));
         table.setLastRetrieved(Instant.now());
         return table;
     }
 
     @Override
-    public PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException,
+    public ViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException,
             ViewNotFoundException, MetadataServiceException {
         final ResponseEntity<ViewDto> response;
         final String url = "/api/database/" + databaseId + "/view/" + id;
-        log.debug("get privileged view info from metadata service: {}", url);
+        log.debug("get  view info from metadata service: {}", url);
         try {
             response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ViewDto.class);
         } catch (ResourceAccessException | HttpServerErrorException e) {
@@ -189,31 +174,20 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
             log.error("Failed to find view with id {}: service responded unsuccessful: {}", id, response.getStatusCode());
             throw new MetadataServiceException("Failed to find view: service responded unsuccessful: " + response.getStatusCode());
         }
-        final List<String> expectedHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-View");
+        final List<String> expectedHeaders = List.of("X-Username", "X-Password");
         if (!response.getHeaders().keySet().containsAll(expectedHeaders)) {
-            log.error("Failed to find all privileged view headers");
+            log.error("Failed to find all  view headers");
             log.debug("expected headers: {}", expectedHeaders);
             log.debug("found headers: {}", response.getHeaders().keySet());
-            throw new MetadataServiceException("Failed to find all privileged view headers");
+            throw new MetadataServiceException("Failed to find all  view headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find view with id {}: body is empty", id);
             throw new MetadataServiceException("Failed to find view with id " + id + ": body is empty");
         }
-        final PrivilegedViewDto view = metadataMapper.viewDtoToPrivilegedViewDto(response.getBody());
-        view.setDatabase(PrivilegedDatabaseDto.builder()
-                .internalName(response.getHeaders().get("X-Database").get(0))
-                .container(PrivilegedContainerDto.builder()
-                        .host(response.getHeaders().get("X-Host").get(0))
-                        .port(Integer.parseInt(response.getHeaders().get("X-Port").get(0)))
-                        .username(response.getHeaders().get("X-Username").get(0))
-                        .password(response.getHeaders().get("X-Password").get(0))
-                        .image(ImageDto.builder()
-                                .jdbcMethod(response.getHeaders().get("X-Type").get(0))
-                                .build())
-                        .build())
-                .build());
-        view.setInternalName(response.getHeaders().get("X-View").get(0));
+        final ViewDto view = metadataMapper.viewDtoToViewDto(response.getBody());
+        view.getDatabase().getContainer().setUsername(response.getHeaders().get("X-Username").get(0));
+        view.getDatabase().getContainer().setPassword(response.getHeaders().get("X-Password").get(0));
         view.setLastRetrieved(Instant.now());
         return view;
     }
@@ -223,33 +197,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
             MetadataServiceException {
         final ResponseEntity<UserDto> response;
         final String url = "/api/user/" + userId;
-        log.debug("get user info from metadata service: {}", url);
-        try {
-            response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class);
-        } catch (ResourceAccessException | HttpServerErrorException e) {
-            log.error("Failed to find user with id {}: {}", userId, e.getMessage());
-            throw new RemoteUnavailableException("Failed to find user: " + e.getMessage(), e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to find user with id {}: not found: {}", userId, e.getMessage());
-            throw new UserNotFoundException("Failed to find user: " + e.getMessage(), e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.OK)) {
-            log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode());
-            throw new MetadataServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode());
-        }
-        if (response.getBody() == null) {
-            log.error("Failed to find user with id {}: body is empty", userId);
-            throw new MetadataServiceException("Failed to find user with id " + userId + ": body is empty");
-        }
-        return response.getBody();
-    }
-
-    @Override
-    public PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException,
-            MetadataServiceException {
-        final ResponseEntity<UserDto> response;
-        final String url = "/api/user/" + userId;
-        log.debug("get privileged user info from metadata service: {}", url);
+        log.debug("get  user info from metadata service: {}", url);
         try {
             response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class);
         } catch (ResourceAccessException | HttpServerErrorException e) {
@@ -265,16 +213,16 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway {
         }
         final List<String> expectedHeaders = List.of("X-Username", "X-Password");
         if (!response.getHeaders().keySet().containsAll(expectedHeaders)) {
-            log.error("Failed to find all privileged user headers");
+            log.error("Failed to find all  user headers");
             log.debug("expected headers: {}", expectedHeaders);
             log.debug("found headers: {}", response.getHeaders().keySet());
-            throw new MetadataServiceException("Failed to find all privileged user headers");
+            throw new MetadataServiceException("Failed to find all  user headers");
         }
         if (response.getBody() == null) {
             log.error("Failed to find user with id {}: body is empty", userId);
             throw new MetadataServiceException("Failed to find user with id " + userId + ": body is empty");
         }
-        final PrivilegedUserDto user = metadataMapper.userDtoToPrivilegedUserDto(response.getBody());
+        final UserDto user = metadataMapper.userDtoToUserDto(response.getBody());
         user.setUsername(response.getHeaders().get("X-Username").get(0));
         user.setPassword(response.getHeaders().get("X-Password").get(0));
         user.setLastRetrieved(Instant.now());
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
index fac47a3d80f6030f5e7d4d561c4262123e9feea7..d2a66ab548d44192638801189f0bd36294f6c321 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
@@ -1,8 +1,10 @@
 package at.tuwien.listener;
 
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.MetadataServiceGateway;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.exception.MetadataServiceException;
+import at.tuwien.exception.RemoteUnavailableException;
+import at.tuwien.exception.TableNotFoundException;
+import at.tuwien.service.CredentialService;
 import at.tuwien.service.QueueService;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -26,14 +28,13 @@ public class DefaultListener implements MessageListener {
 
     private final ObjectMapper objectMapper;
     private final QueueService queueService;
-    private final MetadataServiceGateway metadataServiceGateway;
+    private final CredentialService credentialService;
 
     @Autowired
-    public DefaultListener(ObjectMapper objectMapper, QueueService queueService,
-                           MetadataServiceGateway metadataServiceGateway) {
+    public DefaultListener(ObjectMapper objectMapper, QueueService queueService, CredentialService credentialService) {
         this.objectMapper = objectMapper;
         this.queueService = queueService;
-        this.metadataServiceGateway = metadataServiceGateway;
+        this.credentialService = credentialService;
     }
 
     @Override
@@ -57,7 +58,7 @@ public class DefaultListener implements MessageListener {
         log.trace("received message for table with id {} of database id {}: {} bytes", tableId, databaseId, message.getMessageProperties().getContentLength());
         final Map<String, Object> body;
         try {
-            final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId);
+            final TableDto table = credentialService.getTable(databaseId, tableId);
             body = objectMapper.readValue(message.getBody(), typeRef);
             queueService.insert(table, body);
         } catch (IOException e) {
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java
index 5b96a5934b83e2c4636590f7515f70c04aef5826..956d50b0dd8705d8dd3f783b2c73270d10cf2398 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java
@@ -99,6 +99,7 @@ public interface DataMapper {
                 .vdbid(database.getId())
                 .isInitialView(false)
                 .isPublic(database.getIsPublic())
+                .isSchemaPublic(database.getIsSchemaPublic())
                 .query(resultSet.getString(9))
                 .queryHash(Hashing.sha256()
                         .hashString(resultSet.getString(9), StandardCharsets.UTF_8)
@@ -176,7 +177,6 @@ public interface DataMapper {
     default ViewDto resultSetToTable(ResultSet resultSet, ViewDto view, QueryConfig queryConfig) throws SQLException {
         final ViewColumnDto column = ViewColumnDto.builder()
                 .ordinalPosition(resultSet.getInt(1) - 1) /* start at zero */
-                .autoGenerated(resultSet.getString(2) != null && resultSet.getString(2).startsWith("nextval"))
                 .isNullAllowed(resultSet.getString(3).equals("YES"))
                 .columnType(ColumnTypeDto.valueOf(resultSet.getString(4).toUpperCase()))
                 .d(resultSet.getString(7) != null ? resultSet.getLong(7) : null)
@@ -256,7 +256,7 @@ public interface DataMapper {
             if (optional2.isPresent()) {
                 optional2.get()
                         .getColumns()
-                        .add(column);
+                        .add(columnDtoToColumnBriefDto(column));
                 return table;
             }
             if (type.equals("UNIQUE")) {
@@ -264,7 +264,7 @@ public interface DataMapper {
                         .getUniques()
                         .add(UniqueDto.builder()
                                 .name(name)
-                                .columns(new LinkedList<>(List.of(column)))
+                                .columns(new LinkedList<>(List.of(columnDtoToColumnBriefDto(column))))
                                 .build());
                 return table;
             }
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 db848cab7ef8b59f1bfaac58aa5d7c008410732f..8be9ef68e3dff7246a061664d10273eee95d24f0 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
@@ -1,12 +1,12 @@
 package at.tuwien.mapper;
 
+import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TupleDeleteDto;
 import at.tuwien.api.database.table.TupleDto;
 import at.tuwien.api.database.table.TupleUpdateDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.TableMalformedException;
 import at.tuwien.utils.MariaDbUtil;
@@ -231,19 +231,13 @@ public interface MariaDbMapper {
         return statement.toString();
     }
 
-    default String tableCreateDtoToSequenceName(at.tuwien.api.database.table.internal.TableCreateDto data) {
-        final String name = "seq_" + nameToInternalName(data.getName()) + "_id";
-        log.trace("mapped table name {} to sequence name {}", data.getName(), name);
-        return name;
-    }
-
     /**
      * Maps the desired data type to a MySQL string with the default MySQL 8 values for each
      *
      * @param data The column definition.
      * @return The MySQL string.
      */
-    default String columnTypeDtoToDataType(ColumnCreateDto data) {
+    default String columnTypeDtoToDataType(CreateTableColumnDto data) {
         return switch (data.getType()) {
             case CHAR -> "CHAR(" + Objects.requireNonNullElse(data.getSize(), "1") + ")";
             case VARCHAR -> "VARCHAR(" + Objects.requireNonNullElse(data.getSize(), "255") + ")";
@@ -266,7 +260,7 @@ public interface MariaDbMapper {
         };
     }
 
-    default String columnCreateDtoToPrimaryKeyLengthSpecification(ColumnCreateDto data) {
+    default String columnCreateDtoToPrimaryKeyLengthSpecification(CreateTableColumnDto data) {
         if (EnumSet.of(ColumnTypeDto.BLOB, ColumnTypeDto.TEXT).contains(data.getType())) {
             return "(" + Objects.requireNonNullElse(data.getIndexLength(), 255) + ")";
         }
@@ -315,7 +309,7 @@ public interface MariaDbMapper {
                 .append("` (");
         log.trace("primary key column(s) exist: {}", data.getConstraints().getPrimaryKey());
         final int[] idx = {0};
-        for (ColumnCreateDto column : data.getColumns()) {
+        for (CreateTableColumnDto column : data.getColumns()) {
             stringBuilder.append(idx[0]++ > 0 ? ", " : "")
                     .append("`")
                     .append(nameToInternalName(column.getName()))
@@ -342,11 +336,11 @@ public interface MariaDbMapper {
                                 .getPrimaryKey()
                                 .stream()
                                 .map(c -> {
-                                    final Optional<ColumnCreateDto> optional = data.getColumns()
+                                    final Optional<CreateTableColumnDto> optional = data.getColumns()
                                             .stream()
                                             .filter(cc -> cc.getName().equals(c))
                                             .findFirst();
-                                    log.trace("lookup {} in columns: {}", c, data.getColumns().stream().map(ColumnCreateDto::getName).toList());
+                                    log.trace("lookup {} in columns: {}", c, data.getColumns().stream().map(CreateTableColumnDto::getName).toList());
                                     return "`" + nameToInternalName(c) + "`" + columnCreateDtoToPrimaryKeyLengthSpecification(optional.get());
                                 })
                                 .toArray(String[]::new)))
@@ -519,7 +513,7 @@ public interface MariaDbMapper {
         return statement.toString();
     }
 
-    default String tupleToRawDeleteQuery(PrivilegedTableDto table, TupleDeleteDto data) throws TableMalformedException {
+    default String tupleToRawDeleteQuery(TableDto table, TupleDeleteDto data) throws TableMalformedException {
         log.trace("table csv to delete query, table.id={}, data.keys={}", table.getId(), data.getKeys());
         if (table.getColumns().isEmpty()) {
             throw new TableMalformedException("Columns are not known");
@@ -540,7 +534,7 @@ public interface MariaDbMapper {
         return statement.toString();
     }
 
-    default String tupleToRawUpdateQuery(PrivilegedTableDto table, TupleUpdateDto data)
+    default String tupleToRawUpdateQuery(TableDto table, TupleUpdateDto data)
             throws TableMalformedException {
         if (table.getColumns().isEmpty()) {
             throw new TableMalformedException("Columns are not known");
@@ -579,7 +573,7 @@ public interface MariaDbMapper {
         return statement.toString();
     }
 
-    default String tupleToRawCreateQuery(PrivilegedTableDto table, TupleDto data) throws TableMalformedException {
+    default String tupleToRawCreateQuery(TableDto table, TupleDto data) throws TableMalformedException {
         if (table.getColumns().isEmpty()) {
             throw new TableMalformedException("Columns are not known");
         }
@@ -731,27 +725,54 @@ public interface MariaDbMapper {
         }
     }
 
-    default String selectRawSelectQuery(String query, Instant timestamp, Long page, Long size) {
-        query = query.toLowerCase(Locale.ROOT)
-                .trim();
-        if (query.matches(";$")) {
-            /* remove last semicolon */
-            query = query.substring(0, query.length() - 1);
-        }
+    default String rawSelectQuery(String query, Instant timestamp, Long page, Long size) {
         /* query check (this is enforced by the db also) */
         final StringBuilder statement = new StringBuilder("SELECT * FROM (")
-                .append(query)
-                .append(") FOR SYSTEM_TIME AS OF TIMESTAMP '")
-                .append(mariaDbFormatter.format(timestamp))
-                .append("' as tbl");
+                .append(query);
+        statement.append(")");
+        if (timestamp != null) {
+            statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '")
+                    .append(mariaDbFormatter.format(timestamp))
+                    .append("'");
+        }
+        statement.append(" as tbl");
         /* pagination */
-        log.trace("pagination size/limit of {}", size);
-        statement.append(" LIMIT ")
-                .append(size);
-        log.trace("pagination page/offset of {}", page);
-        statement.append(" OFFSET ")
-                .append(page * size);
-        statement.append(";");
+        if (size != null && page != null) {
+            log.trace("pagination size/limit of {}", size);
+            statement.append(" LIMIT ")
+                    .append(size);
+            log.trace("pagination page/offset of {}", page);
+            statement.append(" OFFSET ")
+                    .append(page * size);
+        }
+        log.trace("mapped select query: {}", statement);
+        return statement.toString();
+    }
+
+    default String defaultRawSelectQuery(String databaseName, String tableOrViewName, Instant timestamp, Long page,
+                                         Long size) {
+        /* query check (this is enforced by the db also) */
+        final StringBuilder statement = new StringBuilder("SELECT * FROM (SELECT * FROM `")
+                .append(databaseName)
+                .append("`.`")
+                .append(tableOrViewName)
+                .append("`");
+        if (timestamp != null) {
+            statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '")
+                    .append(mariaDbFormatter.format(timestamp))
+                    .append("'");
+        }
+        statement.append(" as tbl");
+        /* pagination */
+        if (size != null && page != null) {
+            log.trace("pagination size/limit of {}", size);
+            statement.append(" LIMIT ")
+                    .append(size);
+            log.trace("pagination page/offset of {}", page);
+            statement.append(" OFFSET ")
+                    .append(page * size);
+        }
+        statement.append(") as tbl2");
         log.trace("mapped select query: {}", statement);
         return statement.toString();
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java
index 0adfafa8f96c1c63dafea3a8edd6f45230f88a3d..116737e2ed01bbcfb890174881d9abb14f5e1614 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java
@@ -2,28 +2,23 @@ package at.tuwien.mapper;
 
 import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.container.image.ImageDto;
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
 import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.ViewColumnDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.database.table.TableBriefDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.identifier.IdentifierBriefDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
 
-@Mapper(componentModel = "spring", imports = {PrivilegedDatabaseDto.class, PrivilegedContainerDto.class, ImageDto.class})
+@Mapper(componentModel = "spring", imports = {DatabaseDto.class, ContainerDto.class, ImageDto.class})
 public interface MetadataMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class);
@@ -32,28 +27,21 @@ public interface MetadataMapper {
         return subset.getQueryHash();
     }
 
-    PrivilegedContainerDto containerDtoToPrivilegedContainerDto(ContainerDto data);
+    ContainerDto containerDtoToContainerDto(ContainerDto data);
 
-    DatabaseDto privilegedDatabaseDtoToDatabaseDto(PrivilegedDatabaseDto data);
-
-    DatabaseBriefDto privilegedDatabaseDtoToDatabaseBriefDto(PrivilegedDatabaseDto data);
-
-    TableDto privilegedTableDtoToTableDto(PrivilegedTableDto data);
+    DatabaseBriefDto databaseDtoToDatabaseBriefDto(DatabaseDto data);
 
     ColumnDto viewColumnDtoToColumnDto(ViewColumnDto data);
 
     ViewColumnDto columnDtoToViewColumnDto(ColumnDto data);
 
-    @Mappings({
-            @Mapping(target = "database", expression = "java(PrivilegedDatabaseDto.builder().container(PrivilegedContainerDto.builder().image(new ImageDto()).build()).build())")
-    })
-    PrivilegedTableDto tableDtoToPrivilegedTableDto(TableDto data);
+    TableDto tableDtoToTableDto(TableDto data);
 
-    PrivilegedViewDto viewDtoToPrivilegedViewDto(ViewDto data);
+    ViewDto viewDtoToViewDto(ViewDto data);
 
-    ContainerDto privilegedContainerDtoToContainerDto(PrivilegedContainerDto data);
+    ContainerDto ContainerDtoToContainerDto(ContainerDto data);
 
-    PrivilegedUserDto userDtoToPrivilegedUserDto(UserDto data);
+    UserDto userDtoToUserDto(UserDto data);
 
     UserBriefDto userDtoToUserBriefDto(UserDto data);
 
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java
index 89707ce8f2a834ca8aee1acd7d57ac238dfe9fb9..c42fc28101ba6498e2723f4b02acca6c6d6c2a1b 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java
@@ -1,8 +1,8 @@
 package at.tuwien.service;
 
 import at.tuwien.api.database.AccessTypeDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.DatabaseMalformedException;
 
 import java.sql.SQLException;
@@ -18,7 +18,7 @@ public interface AccessService {
      * @throws SQLException               The connection to the database could not be established.
      * @throws DatabaseMalformedException The database schema is malformed.
      */
-    void create(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException,
+    void create(DatabaseDto database, UserDto user, AccessTypeDto access) throws SQLException,
             DatabaseMalformedException;
 
     /**
@@ -30,7 +30,7 @@ public interface AccessService {
      * @throws SQLException               The connection to the database could not be established.
      * @throws DatabaseMalformedException The database schema is malformed.
      */
-    void update(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException,
+    void update(DatabaseDto database, UserDto user, AccessTypeDto access) throws SQLException,
             DatabaseMalformedException;
 
     /**
@@ -41,6 +41,5 @@ public interface AccessService {
      * @throws SQLException               The connection to the database could not be established.
      * @throws DatabaseMalformedException The database schema is malformed.
      */
-    void delete(PrivilegedDatabaseDto database, PrivilegedUserDto user) throws SQLException,
-            DatabaseMalformedException;
+    void delete(DatabaseDto database, UserDto user) throws SQLException, DatabaseMalformedException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ContainerService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ContainerService.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f9e92ed7899149b518ef6018bade9818e1a4bc5
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ContainerService.java
@@ -0,0 +1,33 @@
+package at.tuwien.service;
+
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.internal.CreateDatabaseDto;
+import at.tuwien.exception.DatabaseMalformedException;
+import at.tuwien.exception.QueryStoreCreateException;
+
+import java.sql.SQLException;
+
+public interface ContainerService {
+
+    /**
+     * Creates a database in the given container.
+     * @param container The container.
+     * @param data The database metadata.
+     * @return The created database, if successful.
+     * @throws SQLException The connection to the database could not be established.
+     * @throws DatabaseMalformedException The database schema is malformed.
+     */
+    DatabaseDto createDatabase(ContainerDto container, CreateDatabaseDto data) throws SQLException,
+            DatabaseMalformedException;
+
+    /**
+     * Creates the query store in the container and database.
+     *
+     * @param container    The container.
+     * @param databaseName The database name.
+     * @throws SQLException              The connection to the database could not be established.
+     * @throws QueryStoreCreateException The query store could not be created.
+     */
+    void createQueryStore(ContainerDto container, String databaseName) throws SQLException, QueryStoreCreateException;
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java
index ff09d6672fe23904181d1e7600a263b847146e0d..fe3df343dba29ca489a8559e1cc741b7cc03359c 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java
@@ -1,11 +1,11 @@
 package at.tuwien.service;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.*;
 
 import java.util.UUID;
@@ -22,7 +22,7 @@ public interface CredentialService {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedDatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
+    DatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
             MetadataServiceException;
 
     /**
@@ -35,7 +35,7 @@ public interface CredentialService {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedContainerDto getContainer(Long id) throws ContainerNotFoundException, RemoteUnavailableException,
+    ContainerDto getContainer(Long id) throws ContainerNotFoundException, RemoteUnavailableException,
             MetadataServiceException;
 
     /**
@@ -49,7 +49,7 @@ public interface CredentialService {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedTableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException,
+    TableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException,
             MetadataServiceException, TableNotFoundException;
 
     /**
@@ -63,7 +63,7 @@ public interface CredentialService {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException,
+    ViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException,
             MetadataServiceException, ViewNotFoundException;
 
     /**
@@ -76,7 +76,7 @@ public interface CredentialService {
      * @throws RemoteUnavailableException The remote service is not available.
      * @throws MetadataServiceException   The remote service returned invalid data.
      */
-    PrivilegedUserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException,
+    UserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException,
             UserNotFoundException;
 
     /**
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java
index 271b2abb82918027053a357c648a1d2ac1926278..c325d7b33a06b9dd5d773262d79a512893b67643 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java
@@ -1,27 +1,89 @@
 package at.tuwien.service;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.database.internal.CreateDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.database.table.internal.TableCreateDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.exception.*;
 
 import java.sql.SQLException;
+import java.util.List;
 
 public interface DatabaseService {
 
     /**
-     * Creates a database in the given container.
-     * @param container The container.
-     * @param data The database metadata.
-     * @return The created database, if successful.
+     * Inspects the schema (columns with names, data types) of a view with given name in the given database.
+     * @param database The database.
+     * @param viewName The view name.
+     * @return The inspected view if successful.
      * @throws SQLException The connection to the database could not be established.
-     * @throws DatabaseMalformedException The database schema is malformed.
+     * @throws ViewNotFoundException The view was not found in the given database.
+     */
+    ViewDto inspectView(DatabaseDto database, String viewName) throws SQLException, ViewNotFoundException;
+
+    /**
+     * Creates a table in given data database with table definition.
+     *
+     * @param database The data database object.
+     * @param data     The table definition.
+     * @return The generated table.
+     * @throws SQLException            Query statement is malformed.
+     * @throws TableMalformedException The table schema is malformed.
+     * @throws TableExistsException    The table name already exists in the information_schema.
+     * @throws TableNotFoundException  The table could not be inspected in the metadata database.
+     */
+    TableDto createTable(DatabaseDto database, TableCreateDto data) throws SQLException,
+            TableMalformedException, TableExistsException, TableNotFoundException;
+
+    /**
+     * Creates a view in given data database with view definition.
+     * @param database The data database object.
+     * @param data The view definition.
+     * @return The generated view.
+     * @throws SQLException
+     * @throws ViewMalformedException
+     */
+    ViewDto createView(DatabaseDto database, CreateViewDto data) throws SQLException,
+            ViewMalformedException;
+
+    /**
+     * Gets the metadata schema for a given database.
+     *
+     * @param database The database.
+     * @return The list of view metadata.
+     * @throws SQLException               The connection to the data database was unsuccessful.
+     * @throws DatabaseMalformedException The columns that are referenced in the views are unknown to the Metadata Database. Call {@link TableService#getSchemas(DatabaseDto)} beforehand.
+     * @throws ViewNotFoundException      The view with given name was not found.
+     */
+    List<ViewDto> exploreViews(DatabaseDto database) throws SQLException, DatabaseMalformedException,
+            ViewNotFoundException;
+
+    /**
+     * Get table schemas from the information_schema in the data database.
+     *
+     * @param database The data database  object.
+     * @return List of tables, if successful.
+     * @throws SQLException               Failed to parse SQL query, contains invalid syntax.
+     * @throws TableNotFoundException     The table could not be inspected in the data database.
+     * @throws DatabaseMalformedException The database inspection was unsuccessful, likely due to a bug in the mapping.
      */
-    PrivilegedDatabaseDto create(PrivilegedContainerDto container, CreateDatabaseDto data) throws SQLException,
+    List<TableDto> exploreTables(DatabaseDto database) throws SQLException, TableNotFoundException,
             DatabaseMalformedException;
 
+    /**
+     * Inspects the schema (columns with names, data types, unique-, check-, primary- and foreign key constraints) of
+     * a table with given name in the given database.
+     *
+     * @param database The database.
+     * @param tableName The table name.
+     * @return The inspected table if successful.
+     * @throws SQLException The connection to the database could not be established.
+     * @throws TableNotFoundException The table was not found in the given database.
+     */
+    TableDto inspectTable(DatabaseDto database, String tableName) throws SQLException, TableNotFoundException;
+
     /**
      * Updates a user's password in a given database.
      * @param database The database.
@@ -29,6 +91,6 @@ public interface DatabaseService {
      * @throws SQLException The connection to the database could not be established.
      * @throws DatabaseMalformedException The database schema is malformed.
      */
-    void update(PrivilegedDatabaseDto database, UpdateUserPasswordDto data) throws SQLException,
+    void update(DatabaseDto database, UpdateUserPasswordDto data) throws SQLException,
             DatabaseMalformedException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java
index 79a23932b5aee74da800c0b41023a7257fa4d32b..6a03f5d767115314f6683ae726caaaf26538ebf9 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java
@@ -1,6 +1,6 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
+import at.tuwien.api.database.table.TableDto;
 
 import java.sql.SQLException;
 import java.util.Map;
@@ -14,5 +14,5 @@ public interface QueueService {
      * @param data     The data.
      * @throws SQLException The connection to the database could not be established.
      */
-    void insert(PrivilegedTableDto table, Map<String, Object> data) throws SQLException;
+    void insert(TableDto table, Map<String, Object> data) throws SQLException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SchemaService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SchemaService.java
deleted file mode 100644
index f5ef05b44aed27a8fb43dbd123b5096e36c2283d..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SchemaService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package at.tuwien.service;
-
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.exception.*;
-
-import java.sql.SQLException;
-
-public interface SchemaService {
-
-    /**
-     * Inspects the schema (columns with names, data types, unique-, check-, primary- and foreign key constraints) of
-     * a table with given name in the given database.
-     * @param database The database.
-     * @param tableName The table name.
-     * @return The inspected table if successful.
-     * @throws SQLException The connection to the database could not be established.
-     * @throws TableNotFoundException The table was not found in the given database.
-     */
-    TableDto inspectTable(PrivilegedDatabaseDto database, String tableName) throws SQLException,
-            TableNotFoundException;
-
-    /**
-     * Inspects the schema (columns with names, data types) of a view with given name in the given database.
-     * @param database The database.
-     * @param viewName The table name.
-     * @return The inspected view if successful.
-     * @throws SQLException The connection to the database could not be established.
-     * @throws ViewNotFoundException The view was not found in the given database.
-     */
-    ViewDto inspectView(PrivilegedDatabaseDto database, String viewName) throws SQLException, ViewNotFoundException;
-}
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 4a3455fbc4e10f9632148fbe12e92f4298973f9d..e2fc56002799d26e75fc05ca496cb76d330cdb07 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
@@ -1,7 +1,7 @@
 package at.tuwien.service;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.SortTypeDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.exception.*;
 import org.apache.spark.sql.Dataset;
@@ -14,33 +14,6 @@ import java.util.UUID;
 
 public interface SubsetService {
 
-    /**
-     * Creates the query store in the container and database.
-     *
-     * @param container    The container.
-     * @param databaseName The database name.
-     * @throws SQLException              The connection to the database could not be established.
-     * @throws QueryStoreCreateException The query store could not be created.
-     */
-    void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException,
-            QueryStoreCreateException;
-
-    /**
-     * Retrieve data from a subset in a database and optionally paginate with number of page and size of results.
-     *
-     * @param database The database.
-     * @param subset   The subset.
-     * @param page     The page number.
-     * @param size     Te result size.
-     * @return The data.
-     * @throws ViewMalformedException  The view is malformed.
-     * @throws SQLException            The connection to the database could not be established.
-     * @throws QueryMalformedException The mapped query produced a database error.
-     * @throws TableNotFoundException  The database table is malformed.
-     */
-    Dataset<Row> getData(PrivilegedDatabaseDto database, QueryDto subset, Long page, Long size)
-            throws ViewMalformedException, SQLException, QueryMalformedException, TableNotFoundException;
-
     /**
      * Creates a subset from the given statement at given time in the given database.
      *
@@ -52,7 +25,7 @@ public interface SubsetService {
      * @throws QueryStoreInsertException The query store refused to insert the query.
      * @throws SQLException              The connection to the database could not be established.
      */
-    Long create(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId)
+    Long create(DatabaseDto database, String statement, Instant timestamp, UUID userId)
             throws QueryStoreInsertException, SQLException;
 
     /**
@@ -64,9 +37,24 @@ public interface SubsetService {
      * @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,
+    Long reExecuteCount(DatabaseDto database, QueryDto query) throws TableMalformedException,
             SQLException, QueryMalformedException;
 
+    /**
+     * Retrieve data from a subset in a database and optionally paginate with number of page and size of results.
+     *
+     * @param database The database.
+     * @param query   The query statements.
+     * @param page     The page number.
+     * @param size     Te result size.
+     * @return The data.
+     * @throws QueryMalformedException The mapped query produced a database error.
+     * @throws TableNotFoundException  The database table is malformed.
+     */
+    Dataset<Row> getData(DatabaseDto database, String query, Instant timestamp, Long page, Long size,
+                         SortTypeDto sortDirection, String sortColumn) throws QueryMalformedException,
+            TableNotFoundException;
+
     /**
      * Finds all queries in the query store of the given database id and query id.
      *
@@ -75,11 +63,11 @@ public interface SubsetService {
      * @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 RemoteUnavailableException The  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,
+    List<QueryDto> findAll(DatabaseDto database, Boolean filterPersisted) throws SQLException,
             QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException;
 
     /**
@@ -93,7 +81,7 @@ public interface SubsetService {
      * @throws QueryMalformedException The mapped query produced a database error.
      * @throws TableMalformedException The database table is malformed.
      */
-    Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp)
+    Long executeCountNonPersistent(DatabaseDto database, String statement, Instant timestamp)
             throws SQLException, QueryMalformedException, TableMalformedException;
 
     /**
@@ -104,12 +92,12 @@ public interface SubsetService {
      * @return The 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 RemoteUnavailableException The  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,
+    QueryDto findById(DatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException,
             RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException, MetadataServiceException;
 
     /**
@@ -122,7 +110,7 @@ public interface SubsetService {
      * @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,
+    Long storeQuery(DatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException,
             QueryStoreInsertException;
 
     /**
@@ -134,7 +122,7 @@ public interface SubsetService {
      * @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,
+    void persist(DatabaseDto database, Long queryId, Boolean persist) throws SQLException,
             QueryStorePersistException;
 
     /**
@@ -144,5 +132,5 @@ public interface SubsetService {
      * @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;
+    void deleteStaleQueries(DatabaseDto database) throws SQLException, QueryStoreGCException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java
index 0564639874b53e07ba5c900d85688af14552ec39..f664a82cf32050512f5eeb7d9e2b206289153568 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java
@@ -1,14 +1,8 @@
 package at.tuwien.service;
 
-import at.tuwien.api.SortTypeDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.database.query.ImportDto;
 import at.tuwien.api.database.table.*;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.api.database.table.internal.TableCreateDto;
 import at.tuwien.exception.*;
-import org.apache.spark.sql.Dataset;
-import org.apache.spark.sql.Row;
 
 import java.sql.SQLException;
 import java.time.Instant;
@@ -16,18 +10,6 @@ import java.util.List;
 
 public interface TableService {
 
-    /**
-     * Get table schemas from the information_schema in the data database.
-     *
-     * @param database The data database privileged object.
-     * @return List of tables, if successful.
-     * @throws SQLException               Failed to parse SQL query, contains invalid syntax.
-     * @throws TableNotFoundException     The table could not be inspected in the data database.
-     * @throws DatabaseMalformedException The database inspection was unsuccessful, likely due to a bug in the mapping.
-     */
-    List<TableDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, TableNotFoundException,
-            DatabaseMalformedException;
-
     /**
      * Generate table statistic for a given table. Only numerical columns are calculated.
      *
@@ -37,36 +19,9 @@ public interface TableService {
      * @throws TableMalformedException The table statistic generation was unsuccessful, likely due to a bug in the mapping.
      * @throws TableNotFoundException  The table could not be inspected in the data database.
      */
-    TableStatisticDto getStatistics(PrivilegedTableDto table) throws SQLException, TableMalformedException,
+    TableStatisticDto getStatistics(TableDto table) throws SQLException, TableMalformedException,
             TableNotFoundException;
 
-    /**
-     * Finds a table with given data database and table name.
-     *
-     * @param database  The data database.
-     * @param tableName The table name.
-     * @return The table, if successful.
-     * @throws TableNotFoundException  The table could not be inspected in the data database.
-     * @throws SQLException            Failed to parse SQL query, contains invalid syntax.
-     * @throws QueryMalformedException The inspection query is malformed.
-     */
-    TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException,
-            QueryMalformedException;
-
-    /**
-     * Creates a table in given data database with table definition.
-     *
-     * @param database The data database privileged object.
-     * @param data     The table definition.
-     * @return The created table, if successful.
-     * @throws SQLException            Query statement is malformed.
-     * @throws TableMalformedException The table schema is malformed.
-     * @throws TableExistsException    The table name already exists in the information_schema.
-     * @throws TableNotFoundException  The table could not be inspected in the metadata database.
-     */
-    TableDto createTable(PrivilegedDatabaseDto database, TableCreateDto data) throws SQLException,
-            TableMalformedException, TableExistsException, TableNotFoundException;
-
     /**
      * Updating table description.
      *
@@ -76,7 +31,7 @@ public interface TableService {
      * @throws TableMalformedException The table schema is malformed.
      * @throws TableNotFoundException  The table could not be inspected in the metadata database.
      */
-    void updateTable(PrivilegedTableDto table, TableUpdateDto data) throws SQLException,
+    void updateTable(TableDto table, TableUpdateDto data) throws SQLException,
             TableMalformedException, TableNotFoundException;
 
     /**
@@ -86,7 +41,7 @@ public interface TableService {
      * @throws SQLException            Failed to parse SQL query, contains invalid syntax.
      * @throws QueryMalformedException The drop table query is malformed.
      */
-    void delete(PrivilegedTableDto table) throws SQLException, QueryMalformedException;
+    void delete(TableDto table) throws SQLException, QueryMalformedException;
 
     /**
      * Obtains the table history for a given table object.
@@ -97,7 +52,7 @@ public interface TableService {
      * @throws SQLException           Failed to parse SQL query, contains invalid syntax.
      * @throws TableNotFoundException The table could not be found in the data database.
      */
-    List<TableHistoryDto> history(PrivilegedTableDto table, Long size) throws SQLException, TableNotFoundException;
+    List<TableHistoryDto> history(TableDto table, Long size) throws SQLException, TableNotFoundException;
 
     /**
      * Obtains the table data tuples count at time.
@@ -108,7 +63,7 @@ public interface TableService {
      * @throws SQLException            Failed to parse SQL query, contains invalid syntax.
      * @throws QueryMalformedException The count query is malformed, likely due to a bug in the application.
      */
-    Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException,
+    Long getCount(TableDto table, Instant timestamp) throws SQLException,
             QueryMalformedException;
 
     /**
@@ -123,7 +78,7 @@ public interface TableService {
      * @throws SQLException                Failed to parse SQL query, contains invalid syntax.
      * @throws QueryMalformedException     The import query is malformed, likely due to a bug in the application.
      */
-    void importDataset(PrivilegedTableDto table, ImportDto data) throws MalformedException, StorageNotFoundException,
+    void importDataset(TableDto table, ImportDto data) throws MalformedException, StorageNotFoundException,
             StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException;
 
     /**
@@ -135,7 +90,7 @@ public interface TableService {
      * @throws TableMalformedException The tuple is malformed and does not fit the table schema.
      * @throws QueryMalformedException The delete query is malformed, likely due to a bug in the application.
      */
-    void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException,
+    void deleteTuple(TableDto table, TupleDeleteDto data) throws SQLException,
             TableMalformedException, QueryMalformedException;
 
     /**
@@ -149,7 +104,7 @@ public interface TableService {
      * @throws StorageUnavailableException Failed to establish a connection with the Storage Service.
      * @throws StorageNotFoundException    The storage service was not able to find the dataset for import.
      */
-    void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException,
+    void createTuple(TableDto table, TupleDto data) throws SQLException,
             QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException;
 
     /**
@@ -161,10 +116,6 @@ public interface TableService {
      * @throws QueryMalformedException The update query is malformed, likely due to a bug in the application.
      * @throws TableMalformedException The tuple is malformed and does not fit the table schema.
      */
-    void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException,
+    void updateTuple(TableDto table, TupleUpdateDto data) throws SQLException,
             QueryMalformedException, TableMalformedException;
-
-    Dataset<Row> getData(PrivilegedDatabaseDto database, String tableOrView, Instant timestamp,
-                         Long page, Long size, SortTypeDto sortDirection, String sortColumn)
-            throws QueryMalformedException, TableNotFoundException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java
index ec7a723261372d1414f0590e74ef915bb62264f4..8f721f9974b0a35d5158fba0d67f9bf7a95faf70 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java
@@ -1,66 +1,22 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.query.QueryDto;
-import at.tuwien.exception.DatabaseMalformedException;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.ViewMalformedException;
-import at.tuwien.exception.ViewNotFoundException;
 
 import java.sql.SQLException;
 import java.time.Instant;
-import java.util.List;
 
 public interface ViewService {
 
-    Boolean existsByName(PrivilegedDatabaseDto database, String name) throws SQLException,
-            QueryMalformedException;
-
-    /**
-     * Gets the metadata schema for a given database.
-     *
-     * @param database The database.
-     * @return The list of view metadata.
-     * @throws SQLException               The connection to the data database was unsuccessful.
-     * @throws DatabaseMalformedException The columns that are referenced in the views are unknown to the Metadata Database. Call {@link TableService#getSchemas(PrivilegedDatabaseDto)} beforehand.
-     * @throws ViewNotFoundException      The view with given name was not found.
-     */
-    List<ViewDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, DatabaseMalformedException,
-            ViewNotFoundException;
-
-    /**
-     * Creates a view if not already exists.
-     * @param database
-     * @param subset
-     * @return
-     * @throws ViewMalformedException
-     * @throws SQLException
-     */
-    ViewDto create(PrivilegedDatabaseDto database, QueryDto subset) throws ViewMalformedException, SQLException;
-
-    /**
-     * Creates a view in the given data database.
-     *
-     * @param database The data database.
-     * @param data     The view.
-     * @throws SQLException           The connection to the data database was unsuccessful.
-     * @throws ViewMalformedException The query is malformed and was rejected by the data database.
-     */
-    ViewDto create(PrivilegedDatabaseDto database, ViewCreateDto data) throws SQLException,
-            ViewMalformedException;
-
     /**
      * Deletes a view.
      *
-     * @param database The database.
-     * @param viewName The view name.
+     * @param view The view.
      * @throws SQLException           The connection to the data database was unsuccessful.
      * @throws ViewMalformedException The query is malformed and was rejected by the data database.
      */
-    void delete(PrivilegedDatabaseDto database, String viewName) throws SQLException, ViewMalformedException;
+    void delete(ViewDto view) throws SQLException, ViewMalformedException;
 
     /**
      * Counts tuples in a view at system-versioned timestamp.
@@ -71,5 +27,5 @@ public interface ViewService {
      * @throws SQLException            The connection to the data database was unsuccessful.
      * @throws QueryMalformedException The query is malformed and was rejected by the data database.
      */
-    Long count(PrivilegedViewDto view, Instant timestamp) throws SQLException, QueryMalformedException;
+    Long count(ViewDto view, Instant timestamp) throws SQLException, QueryMalformedException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java
index c50ac2f0d6bc9f298dfc0a334d524f5e15a91170..be049663b7eb0e3ff2e0f10ccee8e3ee2fc5b759 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java
@@ -1,8 +1,8 @@
 package at.tuwien.service.impl;
 
 import at.tuwien.api.database.AccessTypeDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.DatabaseMalformedException;
 import at.tuwien.mapper.MariaDbMapper;
 import at.tuwien.service.AccessService;
@@ -17,7 +17,7 @@ import java.sql.SQLException;
 
 @Log4j2
 @Service
-public class AccessServiceMariaDbImpl extends HibernateConnector implements AccessService {
+public class AccessServiceMariaDbImpl extends DataConnector implements AccessService {
 
     @Value("${dbrepo.grant.default.read}")
     private String grantDefaultRead;
@@ -33,9 +33,9 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce
     }
 
     @Override
-    public void create(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access)
+    public void create(DatabaseDto database, UserDto user, AccessTypeDto access)
             throws SQLException, DatabaseMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* create user if not exists */
@@ -71,9 +71,9 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce
     }
 
     @Override
-    public void update(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access)
+    public void update(DatabaseDto database, UserDto user, AccessTypeDto access)
             throws DatabaseMalformedException, SQLException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* grant access */
@@ -96,9 +96,9 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce
     }
 
     @Override
-    public void delete(PrivilegedDatabaseDto database, PrivilegedUserDto user) throws DatabaseMalformedException,
+    public void delete(DatabaseDto database, UserDto user) throws DatabaseMalformedException,
             SQLException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* revoke access */
@@ -109,7 +109,7 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce
             /* apply access rights */
             start = System.currentTimeMillis();
             connection.prepareStatement(mariaDbMapper.databaseFlushPrivilegesQuery())
-                            .execute();
+                    .execute();
             log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
             connection.commit();
         } catch (SQLException e) {
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceMariaDbImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..aedba1aed2902b35b424832d117e200dcc02aca9
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceMariaDbImpl.java
@@ -0,0 +1,103 @@
+package at.tuwien.service.impl;
+
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.internal.CreateDatabaseDto;
+import at.tuwien.api.user.UserBriefDto;
+import at.tuwien.config.RabbitConfig;
+import at.tuwien.exception.DatabaseMalformedException;
+import at.tuwien.exception.QueryStoreCreateException;
+import at.tuwien.mapper.MariaDbMapper;
+import at.tuwien.service.ContainerService;
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+@Log4j2
+@Service
+public class ContainerServiceMariaDbImpl extends DataConnector implements ContainerService {
+
+    private final RabbitConfig rabbitConfig;
+    private final MariaDbMapper mariaDbMapper;
+
+    @Autowired
+    public ContainerServiceMariaDbImpl(RabbitConfig rabbitConfig, MariaDbMapper mariaDbMapper) {
+        this.rabbitConfig = rabbitConfig;
+        this.mariaDbMapper = mariaDbMapper;
+    }
+
+    @Override
+    public DatabaseDto createDatabase(ContainerDto container, CreateDatabaseDto data) throws SQLException,
+            DatabaseMalformedException {
+        final ComboPooledDataSource dataSource = getDataSource(container);
+        final Connection connection = dataSource.getConnection();
+        try {
+            /* create database if not exists */
+            final long start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.databaseCreateDatabaseQuery(data.getInternalName()))
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            connection.commit();
+        } catch (SQLException e) {
+            connection.rollback();
+            log.error("Failed to create database access: {}", e.getMessage());
+            throw new DatabaseMalformedException("Failed to create database access: " + e.getMessage(), e);
+        } finally {
+            dataSource.close();
+        }
+        log.info("Created database with name {}", data.getInternalName());
+        return DatabaseDto.builder()
+                .internalName(data.getInternalName())
+                .exchangeName(rabbitConfig.getExchangeName())
+                .owner(UserBriefDto.builder()
+                        .id(data.getUserId())
+                        .build())
+                .contact(UserBriefDto.builder()
+                        .id(data.getUserId())
+                        .build())
+                .container(container)
+                .build();
+    }
+
+    @Override
+    public void createQueryStore(ContainerDto container, String databaseName) throws SQLException,
+            QueryStoreCreateException {
+        final ComboPooledDataSource dataSource = getDataSource(container, databaseName);
+        final Connection connection = dataSource.getConnection();
+        try {
+            /* create query store */
+            long start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.queryStoreCreateSequenceRawQuery())
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.queryStoreCreateTableRawQuery())
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.queryStoreCreateHashTableProcedureRawQuery())
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.queryStoreCreateStoreQueryProcedureRawQuery())
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.queryStoreCreateInternalStoreQueryProcedureRawQuery())
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            connection.commit();
+        } catch (SQLException e) {
+            connection.rollback();
+            log.error("Failed to create query store: {}", e.getMessage());
+            throw new QueryStoreCreateException("Failed to create query store: " + e.getMessage(), e);
+        } finally {
+            dataSource.close();
+        }
+        log.info("Created query store in database with name {}", databaseName);
+    }
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java
index 05b9e0a3feec4930111b5cdad5f839c132daaeac..fbc800bf4719bee556dc597ad593de93b8e9e0be 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java
@@ -1,11 +1,11 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.user.UserDto;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.service.CredentialService;
@@ -21,19 +21,19 @@ import java.util.UUID;
 public class CredentialServiceImpl implements CredentialService {
 
     private final MetadataServiceGateway gateway;
-    private final Cache<UUID, PrivilegedUserDto> userCache;
-    private final Cache<Long, PrivilegedViewDto> viewCache;
+    private final Cache<UUID, UserDto> userCache;
+    private final Cache<Long, ViewDto> viewCache;
     private final Cache<Long, DatabaseAccessDto> accessCache;
-    private final Cache<Long, PrivilegedTableDto> tableCache;
-    private final Cache<Long, PrivilegedDatabaseDto> databaseCache;
-    private final Cache<Long, PrivilegedContainerDto> containerCache;
+    private final Cache<Long, TableDto> tableCache;
+    private final Cache<Long, DatabaseDto> databaseCache;
+    private final Cache<Long, ContainerDto> containerCache;
 
     @Autowired
-    public CredentialServiceImpl(MetadataServiceGateway gateway, Cache<UUID, PrivilegedUserDto> userCache,
-                                 Cache<Long, PrivilegedViewDto> viewCache, Cache<Long, DatabaseAccessDto> accessCache,
-                                 Cache<Long, PrivilegedTableDto> tableCache,
-                                 Cache<Long, PrivilegedDatabaseDto> databaseCache,
-                                 Cache<Long, PrivilegedContainerDto> containerCache) {
+    public CredentialServiceImpl(MetadataServiceGateway gateway, Cache<UUID, UserDto> userCache,
+                                 Cache<Long, ViewDto> viewCache, Cache<Long, DatabaseAccessDto> accessCache,
+                                 Cache<Long, TableDto> tableCache,
+                                 Cache<Long, DatabaseDto> databaseCache,
+                                 Cache<Long, ContainerDto> containerCache) {
         this.gateway = gateway;
         this.userCache = userCache;
         this.viewCache = viewCache;
@@ -44,29 +44,29 @@ public class CredentialServiceImpl implements CredentialService {
     }
 
     @Override
-    public PrivilegedDatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
+    public DatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException,
             MetadataServiceException {
-        final PrivilegedDatabaseDto cacheDatabase = databaseCache.getIfPresent(id);
+        final DatabaseDto cacheDatabase = databaseCache.getIfPresent(id);
         if (cacheDatabase != null) {
             log.trace("found database with id {} in cache", id);
             return cacheDatabase;
         }
         log.debug("database with id {} not it cache (anymore): reload from metadata service", id);
-        final PrivilegedDatabaseDto database = gateway.getDatabaseById(id);
+        final DatabaseDto database = gateway.getDatabaseById(id);
         databaseCache.put(id, database);
         return database;
     }
 
     @Override
-    public PrivilegedTableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException,
+    public TableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException,
             MetadataServiceException, TableNotFoundException {
-        final PrivilegedTableDto cacheTable = tableCache.getIfPresent(tableId);
+        final TableDto cacheTable = tableCache.getIfPresent(tableId);
         if (cacheTable != null) {
             log.trace("found table with id {} in cache", tableId);
             return cacheTable;
         }
         log.debug("table with id {} not it cache (anymore): reload from metadata service", tableId);
-        final PrivilegedTableDto table = gateway.getTableById(databaseId, tableId);
+        final TableDto table = gateway.getTableById(databaseId, tableId);
         tableCache.put(tableId, table);
         return table;
     }
@@ -78,43 +78,43 @@ public class CredentialServiceImpl implements CredentialService {
     }
 
     @Override
-    public PrivilegedContainerDto getContainer(Long id) throws RemoteUnavailableException, MetadataServiceException,
+    public ContainerDto getContainer(Long id) throws RemoteUnavailableException, MetadataServiceException,
             ContainerNotFoundException {
-        final PrivilegedContainerDto cacheContainer = containerCache.getIfPresent(id);
+        final ContainerDto cacheContainer = containerCache.getIfPresent(id);
         if (cacheContainer != null) {
             log.trace("found container with id {} in cache", id);
             return cacheContainer;
         }
         log.debug("container with id {} not it cache (anymore): reload from metadata service", id);
-        final PrivilegedContainerDto container = gateway.getContainerById(id);
+        final ContainerDto container = gateway.getContainerById(id);
         containerCache.put(id, container);
         return container;
     }
 
     @Override
-    public PrivilegedViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException,
+    public ViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException,
             MetadataServiceException, ViewNotFoundException {
-        final PrivilegedViewDto cacheView = viewCache.getIfPresent(viewId);
+        final ViewDto cacheView = viewCache.getIfPresent(viewId);
         if (cacheView != null) {
             log.trace("found view with id {} in cache", viewId);
             return cacheView;
         }
         log.debug("view with id {} not it cache (anymore): reload from metadata service", viewId);
-        final PrivilegedViewDto view = gateway.getViewById(databaseId, viewId);
+        final ViewDto view = gateway.getViewById(databaseId, viewId);
         viewCache.put(viewId, view);
         return view;
     }
 
     @Override
-    public PrivilegedUserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException,
+    public UserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException,
             UserNotFoundException {
-        final PrivilegedUserDto cacheUser = userCache.getIfPresent(id);
+        final UserDto cacheUser = userCache.getIfPresent(id);
         if (cacheUser != null) {
             log.trace("found user with id {} in cache", id);
             return cacheUser;
         }
         log.debug("user with id {} not it cache (anymore): reload from metadata service", id);
-        final PrivilegedUserDto user = gateway.getPrivilegedUserById(id);
+        final UserDto user = gateway.getUserById(id);
         userCache.put(id, user);
         return user;
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DataConnector.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DataConnector.java
new file mode 100644
index 0000000000000000000000000000000000000000..37a345426ae560aee202d5acbcc4d62d79f85f2b
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DataConnector.java
@@ -0,0 +1,74 @@
+package at.tuwien.service.impl;
+
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.stereotype.Service;
+
+@Log4j2
+@Service
+public abstract class DataConnector {
+
+    public ComboPooledDataSource getDataSource(ContainerDto container, String databaseName) {
+        final ComboPooledDataSource dataSource = new ComboPooledDataSource();
+        dataSource.setJdbcUrl(getJdbcUrl(container, databaseName));
+        dataSource.setUser(container.getUsername());
+        dataSource.setPassword(container.getPassword());
+        dataSource.setInitialPoolSize(5);
+        dataSource.setMinPoolSize(5);
+        dataSource.setAcquireIncrement(5);
+        dataSource.setMaxPoolSize(20);
+        dataSource.setMaxStatements(100);
+        return dataSource;
+    }
+
+    public ComboPooledDataSource getDataSource(ViewDto view) {
+        return getDataSource(view.getDatabase().getContainer(), view.getDatabase().getInternalName());
+    }
+
+    public ComboPooledDataSource getDataSource(TableDto table) {
+        return getDataSource(table.getDatabase().getContainer(), table.getDatabase().getInternalName());
+    }
+
+    public ComboPooledDataSource getDataSource(ContainerDto container) {
+        return getDataSource(container, null);
+    }
+
+    public ComboPooledDataSource getDataSource(DatabaseDto database) {
+        return getDataSource(database.getContainer(), database.getInternalName());
+    }
+
+    public String getSparkUrl(ContainerDto container, String databaseName) {
+        final StringBuilder sb = new StringBuilder(getJdbcUrl(container, databaseName))
+                .append("?sessionVariables=sql_mode='ANSI_QUOTES'");
+        log.trace("mapped container to spark url: {}", sb.toString());
+        return sb.toString();
+    }
+
+    public String getSparkUrl(TableDto table) {
+        return getSparkUrl(table.getDatabase().getContainer(), table.getDatabase().getInternalName());
+    }
+
+    public String getSparkUrl(DatabaseDto databaseDto) {
+        return getSparkUrl(databaseDto.getContainer(), databaseDto.getInternalName());
+    }
+
+    public String getJdbcUrl(ContainerDto container, String databaseName) {
+        final StringBuilder stringBuilder = new StringBuilder("jdbc:")
+                .append(container.getImage().getJdbcMethod())
+                .append("://")
+                .append(container.getHost())
+                .append(":")
+                .append(container.getPort());
+        if (databaseName != null) {
+            stringBuilder.append("/")
+                    .append(databaseName);
+        }
+        log.trace("mapped jdbc url: {}", stringBuilder);
+        return stringBuilder.toString();
+    }
+
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java
index a15c22f55e9c7731de47e81d114431961114877d..4d899c99782f99813c3618dd4c051a2a2a0f2da8 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java
@@ -1,72 +1,320 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
-import at.tuwien.api.database.internal.CreateDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.user.UserBriefDto;
+import at.tuwien.api.database.CreateViewDto;
+import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.ViewDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.database.table.constraints.unique.UniqueDto;
+import at.tuwien.api.database.table.internal.TableCreateDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
-import at.tuwien.config.RabbitConfig;
-import at.tuwien.exception.DatabaseMalformedException;
+import at.tuwien.config.QueryConfig;
+import at.tuwien.exception.*;
+import at.tuwien.mapper.DataMapper;
 import at.tuwien.mapper.MariaDbMapper;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.DatabaseService;
+import com.google.common.hash.Hashing;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.nio.charset.StandardCharsets;
 import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
 
 @Log4j2
 @Service
-public class DatabaseServiceMariaDbImpl extends HibernateConnector implements DatabaseService {
+public class DatabaseServiceMariaDbImpl extends DataConnector implements DatabaseService {
 
-    private final RabbitConfig rabbitConfig;
+    private final DataMapper dataMapper;
+    private final QueryConfig queryConfig;
     private final MariaDbMapper mariaDbMapper;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public DatabaseServiceMariaDbImpl(RabbitConfig rabbitConfig, MariaDbMapper mariaDbMapper) {
-        this.rabbitConfig = rabbitConfig;
+    public DatabaseServiceMariaDbImpl(DataMapper dataMapper, QueryConfig queryConfig, MariaDbMapper mariaDbMapper,
+                                      MetadataMapper metadataMapper) {
+        this.dataMapper = dataMapper;
+        this.queryConfig = queryConfig;
         this.mariaDbMapper = mariaDbMapper;
+        this.metadataMapper = metadataMapper;
     }
 
     @Override
-    public PrivilegedDatabaseDto create(PrivilegedContainerDto container, CreateDatabaseDto data) throws SQLException,
-            DatabaseMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(container, null);
+    public ViewDto inspectView(DatabaseDto database, String viewName) throws SQLException, ViewNotFoundException {
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
-            /* create database if not exists */
+            /* obtain only view metadata */
+            long start = System.currentTimeMillis();
+            final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseViewSelectRawQuery());
+            statement1.setString(1, database.getInternalName());
+            statement1.setString(2, viewName);
+            log.trace("1={}, 2={}", database.getInternalName(), viewName);
+            final ResultSet resultSet1 = statement1.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            if (!resultSet1.next()) {
+                throw new ViewNotFoundException("Failed to find view in the information schema");
+            }
+            final ViewDto view = dataMapper.schemaResultSetToView(database, resultSet1);
+            view.setVdbid(database.getId());
+            view.setOwner(database.getOwner());
+            /* obtain view columns */
+            start = System.currentTimeMillis();
+            final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery());
+            statement2.setString(1, database.getInternalName());
+            statement2.setString(2, view.getInternalName());
+            log.trace("1={}, 2={}", database.getInternalName(), view.getInternalName());
+            final ResultSet resultSet2 = statement2.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            TableDto tmp = TableDto.builder()
+                    .columns(new LinkedList<>())
+                    .build();
+            while (resultSet2.next()) {
+                tmp = dataMapper.resultSetToTable(resultSet2, tmp);
+            }
+            view.setColumns(tmp.getColumns()
+                    .stream()
+                    .map(metadataMapper::columnDtoToViewColumnDto)
+                    .toList());
+            view.getColumns()
+                    .forEach(column -> column.setDatabaseId(database.getId()));
+            log.debug("obtained metadata for view {}.{}", database.getInternalName(), view.getInternalName());
+            return view;
+        } finally {
+            dataSource.close();
+        }
+    }
+
+    @Override
+    public TableDto createTable(DatabaseDto database, TableCreateDto data) throws SQLException,
+            TableMalformedException, TableExistsException, TableNotFoundException {
+        final String tableName = mariaDbMapper.nameToInternalName(data.getName());
+        final ComboPooledDataSource dataSource = getDataSource(database);
+        final Connection connection = dataSource.getConnection();
+        try {
+            /* create table if not exists */
             final long start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.databaseCreateDatabaseQuery(data.getInternalName()))
+            connection.prepareStatement(mariaDbMapper.tableCreateDtoToCreateTableRawQuery(data))
                     .execute();
             log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
             connection.commit();
         } catch (SQLException e) {
             connection.rollback();
-            log.error("Failed to create database access: {}", e.getMessage());
-            throw new DatabaseMalformedException("Failed to create database access: " + e.getMessage(), e);
+            if (e.getMessage().contains("already exists")) {
+                log.error("Failed to create table: already exists");
+                throw new TableExistsException("Failed to create table: already exists", e);
+            }
+            log.error("Failed to create table: {}", e.getMessage());
+            throw new TableMalformedException("Failed to create table: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        log.info("Created database with name {}", data.getInternalName());
-        return PrivilegedDatabaseDto.builder()
-                .internalName(data.getInternalName())
-                .exchangeName(rabbitConfig.getExchangeName())
-                .owner(UserBriefDto.builder()
-                        .id(data.getUserId())
-                        .build())
-                .contact(UserBriefDto.builder()
-                        .id(data.getUserId())
-                        .build())
-                .container(container)
+        log.info("Created table with name {}", tableName);
+        final TableDto table = inspectTable(database, tableName);
+        return table;
+    }
+
+    @Override
+    public ViewDto createView(DatabaseDto database, CreateViewDto data) throws SQLException,
+            ViewMalformedException {
+        final ComboPooledDataSource dataSource = getDataSource(database);
+        final Connection connection = dataSource.getConnection();
+        ViewDto view = ViewDto.builder()
+                .name(data.getName())
+                .internalName(mariaDbMapper.nameToInternalName(data.getName()))
+                .query(data.getQuery())
+                .queryHash(Hashing.sha256()
+                        .hashString(data.getQuery(), StandardCharsets.UTF_8)
+                        .toString())
+                .isPublic(database.getIsPublic())
+                .owner(database.getOwner())
+                .identifiers(new LinkedList<>())
+                .isInitialView(false)
+                .vdbid(database.getId())
+                .columns(new LinkedList<>())
                 .build();
+        try {
+            /* create view if not exists */
+            final long start = System.currentTimeMillis();
+            connection.prepareStatement(mariaDbMapper.viewCreateRawQuery(view.getInternalName(), data.getQuery()))
+                    .execute();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            /* select view columns */
+            final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery());
+            statement2.setString(1, database.getInternalName());
+            statement2.setString(2, view.getInternalName());
+            final ResultSet resultSet2 = statement2.executeQuery();
+            while (resultSet2.next()) {
+                view = dataMapper.resultSetToTable(resultSet2, view, queryConfig);
+            }
+            connection.commit();
+        } catch (SQLException e) {
+            connection.rollback();
+            log.error("Failed to create view: {}", e.getMessage());
+            throw new ViewMalformedException("Failed to create view: " + e.getMessage(), e);
+        } finally {
+            dataSource.close();
+        }
+        log.info("Created view with name {}", view.getName());
+        return view;
+    }
+
+    @Override
+    public List<ViewDto> exploreViews(DatabaseDto database) throws SQLException, DatabaseMalformedException,
+            ViewNotFoundException {
+        final ComboPooledDataSource dataSource = getDataSource(database);
+        final Connection connection = dataSource.getConnection();
+        final List<ViewDto> views = new LinkedList<>();
+        try {
+            /* inspect tables before views */
+            final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseViewsSelectRawQuery());
+            statement.setString(1, database.getInternalName());
+            final long start = System.currentTimeMillis();
+            final ResultSet resultSet1 = statement.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            while (resultSet1.next()) {
+                final String viewName = resultSet1.getString(1);
+                if (viewName.length() == 64) {
+                    log.trace("view {}.{} seems to be a subset view (name length = 64), skip.", database.getInternalName(), viewName);
+                    continue;
+                }
+                if (database.getViews().stream().anyMatch(v -> v.getInternalName().equals(viewName))) {
+                    log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), viewName);
+                    continue;
+                }
+                if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(viewName))) {
+                    views.add(inspectView(database, viewName));
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Failed to get view schemas: {}", e.getMessage());
+            throw new DatabaseMalformedException("Failed to get view schemas: " + e.getMessage(), e);
+        } finally {
+            dataSource.close();
+        }
+        log.info("Found {} view schema(s)", views.size());
+        return views;
+    }
+
+    @Override
+    public List<TableDto> exploreTables(DatabaseDto database) throws SQLException, TableNotFoundException,
+            DatabaseMalformedException {
+        final ComboPooledDataSource dataSource = getDataSource(database);
+        final Connection connection = dataSource.getConnection();
+        final List<TableDto> tables = new LinkedList<>();
+        try {
+            /* inspect tables before views */
+            final long start = System.currentTimeMillis();
+            final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseTablesSelectRawQuery());
+            statement.setString(1, database.getInternalName());
+            final ResultSet resultSet1 = statement.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            while (resultSet1.next()) {
+                final String tableName = resultSet1.getString(1);
+                if (database.getTables().stream().anyMatch(t -> t.getInternalName().equals(tableName))) {
+                    log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), tableName);
+                    continue;
+                }
+                final TableDto table = inspectTable(database, tableName);
+                if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(tableName))) {
+                    tables.add(table);
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Failed to get table schemas: {}", e.getMessage());
+            throw new DatabaseMalformedException("Failed to get table schemas: " + e.getMessage(), e);
+        } finally {
+            dataSource.close();
+        }
+        log.info("Found {} table schema(s)", tables.size());
+        return tables;
+    }
+
+    @Override
+    public TableDto inspectTable(DatabaseDto database, String tableName) throws SQLException, TableNotFoundException {
+        log.trace("inspecting table: {}.{}", database.getInternalName(), tableName);
+        final ComboPooledDataSource dataSource = getDataSource(database);
+        final Connection connection = dataSource.getConnection();
+        try {
+            /* obtain only table metadata */
+            long start = System.currentTimeMillis();
+            final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseTableSelectRawQuery());
+            statement1.setString(1, database.getInternalName());
+            statement1.setString(2, tableName);
+            log.trace("1={}, 2={}", database.getInternalName(), tableName);
+            TableDto table = dataMapper.schemaResultSetToTable(database, statement1.executeQuery());
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            /* obtain columns metadata */
+            start = System.currentTimeMillis();
+            final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery());
+            statement2.setString(1, database.getInternalName());
+            statement2.setString(2, tableName);
+            log.trace("1={}, 2={}", database.getInternalName(), tableName);
+            final ResultSet resultSet2 = statement2.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            while (resultSet2.next()) {
+                table = dataMapper.resultSetToTable(resultSet2, table);
+            }
+            /* obtain check constraints metadata */
+            start = System.currentTimeMillis();
+            final PreparedStatement statement3 = connection.prepareStatement(mariaDbMapper.columnsCheckConstraintSelectRawQuery());
+            statement3.setString(1, database.getInternalName());
+            statement3.setString(2, tableName);
+            log.trace("1={}, 2={}", database.getInternalName(), tableName);
+            final ResultSet resultSet3 = statement3.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            while (resultSet3.next()) {
+                final String clause = resultSet3.getString(1);
+                table.getConstraints()
+                        .getChecks()
+                        .add(clause);
+                log.trace("found check clause: {}", clause);
+            }
+            /* obtain column constraints metadata */
+            start = System.currentTimeMillis();
+            final PreparedStatement statement4 = connection.prepareStatement(mariaDbMapper.databaseTableConstraintsSelectRawQuery());
+            statement4.setString(1, database.getInternalName());
+            statement4.setString(2, tableName);
+            log.trace("1={}, 2={}", database.getInternalName(), tableName);
+            final ResultSet resultSet4 = statement4.executeQuery();
+            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            while (resultSet4.next()) {
+                table = dataMapper.resultSetToConstraint(resultSet4, table);
+                for (UniqueDto uk : table.getConstraints().getUniques()) {
+                    uk.setTable(metadataMapper.tableDtoToTableBriefDto(table));
+                    final TableDto tmpTable = table;
+                    uk.getColumns()
+                            .forEach(column -> {
+                                column.setTableId(tmpTable.getId());
+                                column.setDatabaseId(database.getId());
+                            });
+                }
+            }
+            table.setTdbid(database.getId());
+            table.setOwner(database.getOwner());
+            final TableDto tmpTable = table;
+            tmpTable.getColumns()
+                    .forEach(column -> {
+                        column.setTableId(tmpTable.getId());
+                        column.setDatabaseId(database.getId());
+                    });
+            log.debug("obtained metadata for table {}.{}", database.getInternalName(), tableName);
+            return tmpTable;
+        } finally {
+            dataSource.close();
+        }
     }
 
     @Override
-    public void update(PrivilegedDatabaseDto database, UpdateUserPasswordDto data) throws SQLException,
+    public void update(DatabaseDto database, UpdateUserPasswordDto data) throws SQLException,
             DatabaseMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* update user password */
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java
deleted file mode 100644
index 242cefd557cfd68ef95a0b06b5ac4efb91ed83f1..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package at.tuwien.service.impl;
-
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import com.mchange.v2.c3p0.ComboPooledDataSource;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.stereotype.Service;
-
-@Log4j2
-@Service
-public abstract class HibernateConnector {
-
-    public ComboPooledDataSource getPrivilegedDataSource(PrivilegedContainerDto container, String databaseName) {
-        final long start = System.currentTimeMillis();
-        final ComboPooledDataSource dataSource = new ComboPooledDataSource();
-        dataSource.setJdbcUrl(url(container, databaseName));
-        dataSource.setUser(container.getUsername());
-        dataSource.setPassword(container.getPassword());
-        dataSource.setInitialPoolSize(5);
-        dataSource.setMinPoolSize(5);
-        dataSource.setAcquireIncrement(5);
-        dataSource.setMaxPoolSize(20);
-        dataSource.setMaxStatements(100);
-        log.trace("created pooled data source {} in {} ms, user={}", url(container, databaseName), System.currentTimeMillis() - start, container.getUsername());
-        return dataSource;
-    }
-
-    public ComboPooledDataSource getPrivilegedDataSource(PrivilegedDatabaseDto database) {
-        return getPrivilegedDataSource(database.getContainer(), database.getInternalName());
-    }
-
-    public String getSparkUrl(PrivilegedContainerDto container, String databaseName) {
-        final StringBuilder sb = new StringBuilder(url(container, databaseName))
-                .append("?sessionVariables=sql_mode='ANSI_QUOTES'");
-        log.trace("mapped container to spark url: {}", sb.toString());
-        return sb.toString();
-    }
-
-    private String url(PrivilegedContainerDto container, String databaseName) {
-        final StringBuilder stringBuilder = new StringBuilder("jdbc:")
-                .append(container.getImage().getJdbcMethod())
-                .append("://")
-                .append(container.getHost())
-                .append(":")
-                .append(container.getPort());
-        if (databaseName != null) {
-            stringBuilder.append("/")
-                    .append(databaseName);
-        }
-        return stringBuilder.toString();
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java
index d5127e050e521b69e5130c4af836680ffaae013d..4db29335fbfc4cbdbb8086a2009cb588613d1969 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java
@@ -1,7 +1,7 @@
 package at.tuwien.service.impl;
 
+import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.mapper.DataMapper;
 import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.QueueService;
@@ -18,7 +18,7 @@ import java.util.Optional;
 
 @Log4j2
 @Service
-public class QueueServiceRabbitMqImpl extends HibernateConnector implements QueueService {
+public class QueueServiceRabbitMqImpl extends DataConnector implements QueueService {
 
     private final DataMapper dataMapper;
     private final MetadataMapper metadataMapper;
@@ -30,13 +30,13 @@ public class QueueServiceRabbitMqImpl extends HibernateConnector implements Queu
     }
 
     @Override
-    public void insert(PrivilegedTableDto table, Map<String, Object> data) throws SQLException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+    public void insert(TableDto table, Map<String, Object> data) throws SQLException {
+        final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         try {
             final int[] idx = new int[]{1};
             final PreparedStatement preparedStatement = connection.prepareStatement(
-                    dataMapper.rabbitMqTupleToInsertOrUpdateQuery(metadataMapper.privilegedTableDtoToTableDto(table), data));
+                    dataMapper.rabbitMqTupleToInsertOrUpdateQuery(metadataMapper.tableDtoToTableDto(table), data));
             for (Map.Entry<String, Object> entry : data.entrySet()) {
                 final Optional<ColumnDto> optional = table.getColumns().stream().filter(c -> c.getInternalName().equals(entry.getKey())).findFirst();
                 if (optional.isEmpty()) {
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java
deleted file mode 100644
index e2b0c984e0f53c68bf9d384a301ab62ad67bbff7..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package at.tuwien.service.impl;
-
-import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.constraints.unique.UniqueDto;
-import at.tuwien.exception.TableNotFoundException;
-import at.tuwien.exception.ViewNotFoundException;
-import at.tuwien.mapper.DataMapper;
-import at.tuwien.mapper.MariaDbMapper;
-import at.tuwien.mapper.MetadataMapper;
-import at.tuwien.service.SchemaService;
-import com.mchange.v2.c3p0.ComboPooledDataSource;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.LinkedList;
-
-@Log4j2
-@Service
-public class SchemaServiceMariaDbImpl extends HibernateConnector implements SchemaService {
-
-    private final DataMapper dataMapper;
-    private final MariaDbMapper mariaDbMapper;
-    private final MetadataMapper metadataMapper;
-
-    @Autowired
-    public SchemaServiceMariaDbImpl(DataMapper dataMapper, MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper) {
-        this.dataMapper = dataMapper;
-        this.mariaDbMapper = mariaDbMapper;
-        this.metadataMapper = metadataMapper;
-    }
-
-    @Override
-    public TableDto inspectTable(PrivilegedDatabaseDto database, String tableName) throws SQLException,
-            TableNotFoundException {
-        log.trace("inspecting table: {}.{}", database.getInternalName(), tableName);
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
-        final Connection connection = dataSource.getConnection();
-        try {
-            /* obtain only table metadata */
-            long start = System.currentTimeMillis();
-            final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseTableSelectRawQuery());
-            statement1.setString(1, database.getInternalName());
-            statement1.setString(2, tableName);
-            log.trace("1={}, 2={}", database.getInternalName(), tableName);
-            TableDto table = dataMapper.schemaResultSetToTable(metadataMapper.privilegedDatabaseDtoToDatabaseDto(database), statement1.executeQuery());
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            /* obtain columns metadata */
-            start = System.currentTimeMillis();
-            final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery());
-            statement2.setString(1, database.getInternalName());
-            statement2.setString(2, tableName);
-            log.trace("1={}, 2={}", database.getInternalName(), tableName);
-            final ResultSet resultSet2 = statement2.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            while (resultSet2.next()) {
-                table = dataMapper.resultSetToTable(resultSet2, table);
-            }
-            /* obtain check constraints metadata */
-            start = System.currentTimeMillis();
-            final PreparedStatement statement3 = connection.prepareStatement(mariaDbMapper.columnsCheckConstraintSelectRawQuery());
-            statement3.setString(1, database.getInternalName());
-            statement3.setString(2, tableName);
-            log.trace("1={}, 2={}", database.getInternalName(), tableName);
-            final ResultSet resultSet3 = statement3.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            while (resultSet3.next()) {
-                final String clause = resultSet3.getString(1);
-                table.getConstraints()
-                        .getChecks()
-                        .add(clause);
-                log.trace("found check clause: {}", clause);
-            }
-            /* obtain column constraints metadata */
-            start = System.currentTimeMillis();
-            final PreparedStatement statement4 = connection.prepareStatement(mariaDbMapper.databaseTableConstraintsSelectRawQuery());
-            statement4.setString(1, database.getInternalName());
-            statement4.setString(2, tableName);
-            log.trace("1={}, 2={}", database.getInternalName(), tableName);
-            final ResultSet resultSet4 = statement4.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            while (resultSet4.next()) {
-                table = dataMapper.resultSetToConstraint(resultSet4, table);
-                for (UniqueDto uk : table.getConstraints().getUniques()) {
-                    uk.setTable(metadataMapper.tableDtoToTableBriefDto(table));
-                    final TableDto tmpTable = table;
-                    uk.getColumns()
-                            .forEach(column -> {
-                                column.setTableId(tmpTable.getId());
-                                column.setDatabaseId(database.getId());
-                            });
-                }
-            }
-            table.setTdbid(database.getId());
-            table.setOwner(database.getOwner());
-            final TableDto tmpTable = table;
-            tmpTable.getColumns()
-                    .forEach(column -> {
-                        column.setTableId(tmpTable.getId());
-                        column.setDatabaseId(database.getId());
-                    });
-            log.debug("obtained metadata for table {}.{}", database.getInternalName(), tableName);
-            return tmpTable;
-        } finally {
-            dataSource.close();
-        }
-    }
-
-    @Override
-    public ViewDto inspectView(PrivilegedDatabaseDto privilegedDatabase, String viewName) throws SQLException,
-            ViewNotFoundException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(privilegedDatabase);
-        final Connection connection = dataSource.getConnection();
-        final DatabaseDto database = metadataMapper.privilegedDatabaseDtoToDatabaseDto(privilegedDatabase);
-        try {
-            /* obtain only view metadata */
-            long start = System.currentTimeMillis();
-            final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseViewSelectRawQuery());
-            statement1.setString(1, database.getInternalName());
-            statement1.setString(2, viewName);
-            log.trace("1={}, 2={}", database.getInternalName(), viewName);
-            final ResultSet resultSet1 = statement1.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            if (!resultSet1.next()) {
-                throw new ViewNotFoundException("Failed to find view in the information schema");
-            }
-            ViewDto view = dataMapper.schemaResultSetToView(database, resultSet1);
-            view.setVdbid(database.getId());
-            view.setOwner(database.getOwner());
-            /* obtain view columns */
-            start = System.currentTimeMillis();
-            final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery());
-            statement2.setString(1, database.getInternalName());
-            statement2.setString(2, viewName);
-            log.trace("1={}, 2={}", database.getInternalName(), viewName);
-            final ResultSet resultSet2 = statement2.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            TableDto tmp = TableDto.builder()
-                    .columns(new LinkedList<>())
-                    .build();
-            while (resultSet2.next()) {
-                tmp = dataMapper.resultSetToTable(resultSet2, tmp);
-            }
-            view.setColumns(tmp.getColumns()
-                    .stream()
-                    .map(metadataMapper::columnDtoToViewColumnDto)
-                    .toList());
-            view.getColumns()
-                    .forEach(column -> column.setDatabaseId(database.getId()));
-            log.debug("obtained metadata for view {}.{}", database.getInternalName(), viewName);
-            return view;
-        } finally {
-            dataSource.close();
-        }
-    }
-
-}
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 fb244bb30113ab90f4f2209bf4e80b5d11cd9185..bdfdb14838a608ce87b40a94faebe52a27546a63 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
@@ -1,7 +1,7 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
+import at.tuwien.api.SortTypeDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.identifier.IdentifierBriefDto;
 import at.tuwien.api.identifier.IdentifierTypeDto;
@@ -9,14 +9,13 @@ import at.tuwien.exception.*;
 import at.tuwien.gateway.MetadataServiceGateway;
 import at.tuwien.mapper.DataMapper;
 import at.tuwien.mapper.MariaDbMapper;
-import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.SubsetService;
-import at.tuwien.service.TableService;
-import at.tuwien.service.ViewService;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
 import org.apache.spark.sql.Dataset;
 import org.apache.spark.sql.Row;
+import org.apache.spark.sql.SparkSession;
+import org.apache.spark.sql.catalyst.ExtendedAnalysisException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -28,95 +27,63 @@ import java.util.UUID;
 
 @Log4j2
 @Service
-public class SubsetServiceMariaDbImpl extends HibernateConnector implements SubsetService {
+public class SubsetServiceMariaDbImpl extends DataConnector implements SubsetService {
 
     private final DataMapper dataMapper;
-    private final ViewService viewService;
-    private final TableService tableService;
+    private final SparkSession sparkSession;
     private final MariaDbMapper mariaDbMapper;
-    private final MetadataMapper metadataMapper;
     private final MetadataServiceGateway metadataServiceGateway;
 
     @Autowired
-    public SubsetServiceMariaDbImpl(DataMapper dataMapper, ViewService viewService, TableService tableService,
-                                    MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper,
+    public SubsetServiceMariaDbImpl(DataMapper dataMapper, MariaDbMapper mariaDbMapper, SparkSession sparkSession,
                                     MetadataServiceGateway metadataServiceGateway) {
         this.dataMapper = dataMapper;
-        this.viewService = viewService;
-        this.tableService = tableService;
+        this.sparkSession = sparkSession;
         this.mariaDbMapper = mariaDbMapper;
-        this.metadataMapper = metadataMapper;
         this.metadataServiceGateway = metadataServiceGateway;
     }
 
     @Override
-    public void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException,
-            QueryStoreCreateException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(container, databaseName);
-        final Connection connection = dataSource.getConnection();
+    public Dataset<Row> getData(DatabaseDto database, String query, Instant timestamp, Long page, Long size,
+                                SortTypeDto sortDirection, String sortColumn)
+            throws QueryMalformedException, TableNotFoundException {
         try {
-            /* create query store */
-            long start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.queryStoreCreateSequenceRawQuery())
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.queryStoreCreateTableRawQuery())
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.queryStoreCreateHashTableProcedureRawQuery())
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.queryStoreCreateStoreQueryProcedureRawQuery())
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.queryStoreCreateInternalStoreQueryProcedureRawQuery())
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            connection.commit();
-        } catch (SQLException e) {
-            connection.rollback();
-            log.error("Failed to create query store: {}", e.getMessage());
-            throw new QueryStoreCreateException("Failed to create query store: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-        log.info("Created query store in database with name {}", databaseName);
-    }
-
-    @Override
-    public Dataset<Row> getData(PrivilegedDatabaseDto database, QueryDto subset, Long page, Long size)
-            throws ViewMalformedException, SQLException, QueryMalformedException, TableNotFoundException {
-        final String viewName = metadataMapper.queryDtoToViewName(subset);
-        if (!viewService.existsByName(database, viewName)) {
-            log.warn("Missing internal view {} for subset with id {}: create it from subset query", viewName, subset.getId());
-            viewService.create(database, subset);
-        } else {
-            log.debug("internal view {}.{} for subset with id {} exists", database.getInternalName(), viewName, subset.getId());
+            return sparkSession.read()
+                    .format("jdbc")
+                    .option("user", database.getContainer().getUsername())
+                    .option("password", database.getContainer().getPassword())
+                    .option("url", getSparkUrl(database))
+                    .option("query", query)
+                    .load();
+        } catch (Exception e) {
+            if (e instanceof ExtendedAnalysisException exception) {
+                if (exception.getSimpleMessage().contains("TABLE_OR_VIEW_NOT_FOUND")) {
+                    log.error("Failed to find named reference: {}", exception.getSimpleMessage());
+                    throw new TableNotFoundException("Failed to find named reference: " + exception.getSimpleMessage()) /* remove throwable on purpose, clutters the output */;
+                }
+            }
+            log.error("Malformed query: {}", e.getMessage());
+            throw new QueryMalformedException("Malformed query: " + e.getMessage(), e);
         }
-        return tableService.getData(database, viewName, subset.getExecution(), page, size, null, null);
     }
 
     @Override
-    public Long create(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId)
+    public Long create(DatabaseDto database, String statement, Instant timestamp, UUID userId)
             throws QueryStoreInsertException, SQLException {
         return storeQuery(database, statement, timestamp, userId);
     }
 
     @Override
-    public Long reExecuteCount(PrivilegedDatabaseDto database, QueryDto query) throws TableMalformedException,
+    public Long reExecuteCount(DatabaseDto database, QueryDto query) throws TableMalformedException,
             SQLException, QueryMalformedException {
         return executeCountNonPersistent(database, query.getQuery(), query.getExecution());
     }
 
     @Override
-    public List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException,
+    public List<QueryDto> findAll(DatabaseDto database, Boolean filterPersisted) throws SQLException,
             QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
         final List<IdentifierBriefDto> identifiers = metadataServiceGateway.getIdentifiers(database.getId(), null);
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             final long start = System.currentTimeMillis();
@@ -147,9 +114,9 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     }
 
     @Override
-    public Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp)
+    public Long executeCountNonPersistent(DatabaseDto database, String statement, Instant timestamp)
             throws SQLException, QueryMalformedException, TableMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             final long start = System.currentTimeMillis();
@@ -166,9 +133,9 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     }
 
     @Override
-    public QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException,
+    public QueryDto findById(DatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException,
             RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             final long start = System.currentTimeMillis();
@@ -193,11 +160,11 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     }
 
     @Override
-    public Long storeQuery(PrivilegedDatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException,
+    public Long storeQuery(DatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException,
             QueryStoreInsertException {
         /* save */
         final Long queryId;
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* insert query into query store */
@@ -228,9 +195,9 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     }
 
     @Override
-    public void persist(PrivilegedDatabaseDto database, Long queryId, Boolean persist) throws SQLException,
+    public void persist(DatabaseDto database, Long queryId, Boolean persist) throws SQLException,
             QueryStorePersistException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             /* update query */
@@ -250,8 +217,8 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs
     }
 
     @Override
-    public void deleteStaleQueries(PrivilegedDatabaseDto database) throws SQLException, QueryStoreGCException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+    public void deleteStaleQueries(DatabaseDto database) throws SQLException, QueryStoreGCException {
+        final ComboPooledDataSource dataSource = getDataSource(database);
         final Connection connection = dataSource.getConnection();
         try {
             final long start = System.currentTimeMillis();
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
index c34f057e0129bd1c65277648adf3b5985952235c..466f7539fd250666962d08a75ffffd5aa61480fa 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
@@ -1,25 +1,23 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.SortTypeDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.database.query.ImportDto;
 import at.tuwien.api.database.table.*;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.columns.ColumnStatisticDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
-import at.tuwien.api.database.table.internal.TableCreateDto;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.DataMapper;
 import at.tuwien.mapper.MariaDbMapper;
-import at.tuwien.service.SchemaService;
+import at.tuwien.service.DatabaseService;
 import at.tuwien.service.StorageService;
 import at.tuwien.service.TableService;
 import at.tuwien.utils.MariaDbUtil;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
-import org.apache.spark.sql.*;
-import org.apache.spark.sql.catalyst.ExtendedAnalysisException;
+import org.apache.spark.sql.AnalysisException;
+import org.apache.spark.sql.Dataset;
+import org.apache.spark.sql.Row;
+import org.apache.spark.sql.SaveMode;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -28,66 +26,33 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.time.Instant;
-import java.util.*;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
 
 @Log4j2
 @Service
-public class TableServiceMariaDbImpl extends HibernateConnector implements TableService {
+public class TableServiceMariaDbImpl extends DataConnector implements TableService {
 
     private final DataMapper dataMapper;
-    private final SparkSession sparkSession;
     private final MariaDbMapper mariaDbMapper;
-    private final SchemaService schemaService;
     private final StorageService storageService;
+    private final DatabaseService databaseService;
 
     @Autowired
-    public TableServiceMariaDbImpl(DataMapper dataMapper, SparkSession sparkSession, MariaDbMapper mariaDbMapper,
-                                   SchemaService schemaService, StorageService storageService) {
+    public TableServiceMariaDbImpl(DataMapper dataMapper, MariaDbMapper mariaDbMapper, StorageService storageService,
+                                   DatabaseService databaseService) {
         this.dataMapper = dataMapper;
-        this.sparkSession = sparkSession;
         this.mariaDbMapper = mariaDbMapper;
-        this.schemaService = schemaService;
         this.storageService = storageService;
+        this.databaseService = databaseService;
     }
 
     @Override
-    public List<TableDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, TableNotFoundException,
-            DatabaseMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
-        final Connection connection = dataSource.getConnection();
-        final List<TableDto> tables = new LinkedList<>();
-        try {
-            /* inspect tables before views */
-            final long start = System.currentTimeMillis();
-            final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseTablesSelectRawQuery());
-            statement.setString(1, database.getInternalName());
-            final ResultSet resultSet1 = statement.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            while (resultSet1.next()) {
-                final String tableName = resultSet1.getString(1);
-                if (database.getTables().stream().anyMatch(t -> t.getInternalName().equals(tableName))) {
-                    log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), tableName);
-                    continue;
-                }
-                final TableDto table = schemaService.inspectTable(database, tableName);
-                if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(table.getInternalName()))) {
-                    tables.add(table);
-                }
-            }
-        } catch (SQLException e) {
-            log.error("Failed to get table schemas: {}", e.getMessage());
-            throw new DatabaseMalformedException("Failed to get table schemas: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-        log.info("Found {} table schema(s)", tables.size());
-        return tables;
-    }
-
-    @Override
-    public TableStatisticDto getStatistics(PrivilegedTableDto table) throws SQLException, TableMalformedException,
+    public TableStatisticDto getStatistics(TableDto table) throws SQLException, TableMalformedException,
             TableNotFoundException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         final TableStatisticDto statistic;
         try {
@@ -102,7 +67,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
                         .executeQuery();
                 log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
                 statistic = dataMapper.resultSetToTableStatistic(resultSet);
-                final TableDto tmpTable = schemaService.inspectTable(table.getDatabase(), table.getInternalName());
+                final TableDto tmpTable = databaseService.inspectTable(table.getDatabase(), table.getInternalName());
                 statistic.setAvgRowLength(tmpTable.getAvgRowLength());
                 statistic.setDataLength(tmpTable.getDataLength());
                 statistic.setMaxDataLength(tmpTable.getMaxDataLength());
@@ -126,44 +91,9 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
     }
 
     @Override
-    public TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException {
-        return schemaService.inspectTable(database, tableName);
-    }
-
-    @Override
-    public TableDto createTable(PrivilegedDatabaseDto database, TableCreateDto data) throws SQLException,
-            TableMalformedException, TableExistsException, TableNotFoundException {
-        final String tableName = mariaDbMapper.nameToInternalName(data.getName());
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
-        final Connection connection = dataSource.getConnection();
-        try {
-            /* create table if not exists */
-            final long start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.tableCreateDtoToCreateTableRawQuery(data))
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            connection.commit();
-        } catch (SQLException e) {
-            connection.rollback();
-            if (e.getMessage().contains("already exists")) {
-                log.error("Failed to create table: already exists");
-                throw new TableExistsException("Failed to create table: already exists", e);
-            }
-            log.error("Failed to create table: {}", e.getMessage());
-            throw new TableMalformedException("Failed to create table: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-        log.info("Created table with name {}", tableName);
-        final TableDto table = find(database, tableName);
-        table.setName(data.getName());
-        return table;
-    }
-
-    @Override
-    public void updateTable(PrivilegedTableDto table, TableUpdateDto data) throws SQLException,
+    public void updateTable(TableDto table, TableUpdateDto data) throws SQLException,
             TableMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table.getDatabase());
         final Connection connection = dataSource.getConnection();
         try {
             /* create table if not exists */
@@ -189,14 +119,13 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
     }
 
     @Override
-    public void delete(PrivilegedTableDto table) throws SQLException, QueryMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
-        final String tableName = mariaDbMapper.nameToInternalName(table.getInternalName());
+    public void delete(TableDto table) throws SQLException, QueryMalformedException {
+        final ComboPooledDataSource dataSource = getDataSource(table.getDatabase());
         final Connection connection = dataSource.getConnection();
         try {
             /* create table if not exists */
             final long start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.dropTableRawQuery(tableName))
+            connection.prepareStatement(mariaDbMapper.dropTableRawQuery(table.getInternalName()))
                     .execute();
             log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
             connection.commit();
@@ -207,13 +136,13 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
         } finally {
             dataSource.close();
         }
-        log.info("Deleted table with name {}", tableName);
+        log.info("Deleted table with name {}", table.getInternalName());
     }
 
     @Override
-    public List<TableHistoryDto> history(PrivilegedTableDto table, Long size) throws SQLException,
+    public List<TableHistoryDto> history(TableDto table, Long size) throws SQLException,
             TableNotFoundException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table.getDatabase());
         final Connection connection = dataSource.getConnection();
         final List<TableHistoryDto> history;
         try {
@@ -227,19 +156,19 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
             connection.commit();
         } catch (SQLException e) {
             connection.rollback();
-            log.error("Failed to find history for table {}.{}: {}", table.getDatabase().getInternalName(), table.getInternalName(), e.getMessage());
-            throw new TableNotFoundException("Failed to find history for table " + table.getDatabase().getInternalName() + "." + table.getInternalName() + ": " + e.getMessage(), e);
+            log.error("Failed to find history for table {}.{}: {}", table.getDatabase(), table.getInternalName(), e.getMessage());
+            throw new TableNotFoundException("Failed to find history for table " + table.getDatabase() + "." + table.getInternalName() + ": " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        log.info("Find history for table {}.{}", table.getDatabase().getInternalName(), table.getInternalName());
+        log.info("Find history for table {}.{}", table.getDatabase(), table.getInternalName());
         return history;
     }
 
     @Override
-    public Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException,
+    public Long getCount(TableDto table, Instant timestamp) throws SQLException,
             QueryMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table.getDatabase());
         final Connection connection = dataSource.getConnection();
         final Long queryResult;
         try {
@@ -253,17 +182,17 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
             connection.commit();
         } catch (SQLException e) {
             connection.rollback();
-            log.error("Failed to find row count from table {}.{}: {}", table.getDatabase().getInternalName(), table.getInternalName(), e.getMessage());
-            throw new QueryMalformedException("Failed to find row count from table " + table.getDatabase().getInternalName() + "." + table.getInternalName() + ": " + e.getMessage(), e);
+            log.error("Failed to find row count from table {}.{}: {}", table.getDatabase(), table.getInternalName(), e.getMessage());
+            throw new QueryMalformedException("Failed to find row count from table " + table.getDatabase() + "." + table.getInternalName() + ": " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        log.info("Find row count from table {}.{}", table.getDatabase().getInternalName(), table.getInternalName());
+        log.info("Find row count from table {}.{}", table.getDatabase(), table.getInternalName());
         return queryResult;
     }
 
     @Override
-    public void importDataset(PrivilegedTableDto table, ImportDto data) throws MalformedException,
+    public void importDataset(TableDto table, ImportDto data) throws MalformedException,
             StorageNotFoundException, StorageUnavailableException, SQLException, QueryMalformedException,
             TableMalformedException {
         final List<String> columns = table.getColumns()
@@ -282,8 +211,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
                     .mode(SaveMode.Overwrite)
                     .option("header", data.getHeader())
                     .option("inferSchema", "true")
-                    .jdbc(getSparkUrl(table.getDatabase().getContainer(), table.getDatabase().getInternalName()),
-                            temporaryTable, properties);
+                    .jdbc(getSparkUrl(table), temporaryTable, properties);
         } catch (Exception e) {
             if (e instanceof AnalysisException exception) {
                 final String message = exception.getSimpleMessage()
@@ -295,7 +223,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
             throw new MalformedException("Failed to write dataset: " + e.getMessage()) /* remove throwable on purpose, clutters the output */;
         }
         /* import .csv from sidecar to database */
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         try {
             /* import tuple */
@@ -314,15 +242,15 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
             connection.commit();
             dataSource.close();
         }
-        log.info("Imported dataset into table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName());
+        log.info("Imported dataset into table: {}.{}", table.getDatabase(), table.getInternalName());
     }
 
     @Override
-    public void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException,
+    public void deleteTuple(TableDto table, TupleDeleteDto data) throws SQLException,
             TableMalformedException, QueryMalformedException {
         log.trace("delete tuple: {}", data);
         /* prepare the statement */
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         try {
             /* import tuple */
@@ -344,11 +272,11 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
         } finally {
             dataSource.close();
         }
-        log.info("Deleted tuple(s) from table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName());
+        log.info("Deleted tuple(s) from table: {}.{}", table.getDatabase(), table.getInternalName());
     }
 
     @Override
-    public void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, QueryMalformedException,
+    public void createTuple(TableDto table, TupleDto data) throws SQLException, QueryMalformedException,
             TableMalformedException, StorageUnavailableException, StorageNotFoundException {
         log.trace("create tuple: {}", data);
         /* for each LOB-like data-column, retrieve the bytes and replace the value */
@@ -366,7 +294,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
                     .replace(key, blob);
         }
         /* prepare the statement */
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         try {
             /* create tuple */
@@ -388,15 +316,15 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
         } finally {
             dataSource.close();
         }
-        log.info("Created tuple(s) in table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName());
+        log.info("Created tuple(s) in table: {}.{}", table.getDatabase(), table.getInternalName());
     }
 
     @Override
-    public void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException,
+    public void updateTuple(TableDto table, TupleUpdateDto data) throws SQLException,
             QueryMalformedException, TableMalformedException {
         log.trace("update tuple: {}", data);
         /* prepare the statement */
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         try {
             final int[] idx = new int[]{1};
@@ -424,7 +352,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
         } finally {
             dataSource.close();
         }
-        log.info("Updated tuple(s) from table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName());
+        log.info("Updated tuple(s) from table: {}.{}", table.getDatabase(), table.getInternalName());
     }
 
     public ColumnTypeDto getColumnType(List<ColumnDto> columns, String name) throws QueryMalformedException {
@@ -438,26 +366,4 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table
                 .getColumnType();
     }
 
-    @Override
-    public Dataset<Row> getData(PrivilegedDatabaseDto database, String tableOrView, Instant timestamp,
-                                Long page, Long size, SortTypeDto sortDirection, String sortColumn)
-            throws QueryMalformedException, TableNotFoundException {
-        try {
-            final Properties properties = new Properties();
-            properties.setProperty("user", database.getContainer().getUsername());
-            properties.setProperty("password", database.getContainer().getPassword());
-            return sparkSession.read()
-                    .jdbc(getSparkUrl(database.getContainer(), database.getInternalName()), tableOrView, properties);
-        } catch (Exception e) {
-            if (e instanceof ExtendedAnalysisException exception) {
-                if (exception.getSimpleMessage().contains("TABLE_OR_VIEW_NOT_FOUND")) {
-                    log.error("Failed to find named reference: {}", exception.getSimpleMessage());
-                    throw new TableNotFoundException("Failed to find named reference: " + exception.getSimpleMessage()) /* remove throwable on purpose, clutters the output */;
-                }
-            }
-            log.error("Failed to find get data from query statement: {}", e.getMessage());
-            throw new QueryMalformedException("Failed to find get data from query statement: " + e.getMessage(), e);
-        }
-    }
-
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java
index d85bdc53ac235a3a95bb8b3543bddcfdd143dc6d..fff524047e10b575f773fe23656f86944514843a 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java
@@ -1,182 +1,39 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
-import at.tuwien.api.database.query.QueryDto;
-import at.tuwien.config.QueryConfig;
-import at.tuwien.exception.DatabaseMalformedException;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.ViewMalformedException;
-import at.tuwien.exception.ViewNotFoundException;
-import at.tuwien.mapper.DataMapper;
 import at.tuwien.mapper.MariaDbMapper;
-import at.tuwien.mapper.MetadataMapper;
-import at.tuwien.service.SchemaService;
 import at.tuwien.service.ViewService;
-import com.google.common.hash.Hashing;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.nio.charset.StandardCharsets;
 import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.time.Instant;
-import java.util.LinkedList;
-import java.util.List;
 
 @Log4j2
 @Service
-public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewService {
+public class ViewServiceMariaDbImpl extends DataConnector implements ViewService {
 
-    private final DataMapper dataMapper;
-    private final QueryConfig queryConfig;
-    private final SchemaService schemaService;
     private final MariaDbMapper mariaDbMapper;
-    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public ViewServiceMariaDbImpl(DataMapper dataMapper, QueryConfig queryConfig, SchemaService schemaService,
-                                  MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper) {
-        this.dataMapper = dataMapper;
-        this.queryConfig = queryConfig;
-        this.schemaService = schemaService;
+    public ViewServiceMariaDbImpl(MariaDbMapper mariaDbMapper) {
         this.mariaDbMapper = mariaDbMapper;
-        this.metadataMapper = metadataMapper;
     }
 
     @Override
-    public Boolean existsByName(PrivilegedDatabaseDto database, String name) throws SQLException,
-            QueryMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
-        final Connection connection = dataSource.getConnection();
-        final Boolean queryResult;
-        try {
-            /* find view data */
-            final long start = System.currentTimeMillis();
-            final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.selectExistsTableOrViewRawQuery());
-            statement.setString(1, database.getInternalName());
-            statement.setString(2, name);
-            final ResultSet resultSet = statement.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            queryResult = mariaDbMapper.resultSetToBoolean(resultSet);
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}", e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-        return queryResult;
-    }
-
-    @Override
-    public List<ViewDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, DatabaseMalformedException,
-            ViewNotFoundException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
-        final Connection connection = dataSource.getConnection();
-        final List<ViewDto> views = new LinkedList<>();
-        try {
-            /* inspect tables before views */
-            final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseViewsSelectRawQuery());
-            statement.setString(1, database.getInternalName());
-            final long start = System.currentTimeMillis();
-            final ResultSet resultSet1 = statement.executeQuery();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            while (resultSet1.next()) {
-                final String viewName = resultSet1.getString(1);
-                if (viewName.length() == 64) {
-                    log.trace("view {}.{} seems to be a subset view (name length = 64), skip.", database.getInternalName(), viewName);
-                    continue;
-                }
-                if (database.getViews().stream().anyMatch(v -> v.getInternalName().equals(viewName))) {
-                    log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), viewName);
-                    continue;
-                }
-                final ViewDto view;
-                view = schemaService.inspectView(database, viewName);
-                if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(view.getInternalName()))) {
-                    views.add(view);
-                }
-            }
-        } catch (SQLException e) {
-            log.error("Failed to get view schemas: {}", e.getMessage());
-            throw new DatabaseMalformedException("Failed to get view schemas: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-        log.info("Found {} view schema(s)", views.size());
-        return views;
-    }
-
-    @Override
-    public ViewDto create(PrivilegedDatabaseDto database, QueryDto subset) throws ViewMalformedException,
-            SQLException {
-        final ViewCreateDto data = ViewCreateDto.builder()
-                .name(metadataMapper.queryDtoToViewName(subset))
-                .query(subset.getQuery())
-                .isPublic(false)
-                .build();
-        return create(database, data);
-    }
-
-    @Override
-    public ViewDto create(PrivilegedDatabaseDto database, ViewCreateDto data) throws SQLException,
-            ViewMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
-        final Connection connection = dataSource.getConnection();
-        ViewDto view = ViewDto.builder()
-                .name(data.getName())
-                .internalName(mariaDbMapper.nameToInternalName(data.getName()))
-                .query(data.getQuery())
-                .queryHash(Hashing.sha256()
-                        .hashString(data.getQuery(), StandardCharsets.UTF_8)
-                        .toString())
-                .isPublic(database.getIsPublic())
-                .owner(database.getOwner())
-                .identifiers(new LinkedList<>())
-                .isInitialView(false)
-                .vdbid(database.getId())
-                .columns(new LinkedList<>())
-                .build();
-        try {
-            /* create view if not exists */
-            final long start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.viewCreateRawQuery(view.getInternalName(), data.getQuery()))
-                    .execute();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
-            /* select view columns */
-            final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery());
-            statement2.setString(1, database.getInternalName());
-            statement2.setString(2, view.getInternalName());
-            final ResultSet resultSet2 = statement2.executeQuery();
-            while (resultSet2.next()) {
-                view = dataMapper.resultSetToTable(resultSet2, view, queryConfig);
-            }
-            connection.commit();
-        } catch (SQLException e) {
-            connection.rollback();
-            log.error("Failed to create view: {}", e.getMessage());
-            throw new ViewMalformedException("Failed to create view: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-        log.info("Created view with name {}", view.getName());
-        return view;
-    }
-
-    @Override
-    public void delete(PrivilegedDatabaseDto database, String viewName) throws SQLException, ViewMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database);
+    public void delete(ViewDto view) throws SQLException, ViewMalformedException {
+        final ComboPooledDataSource dataSource = getDataSource(view);
         final Connection connection = dataSource.getConnection();
         try {
             /* drop view if exists */
             final long start = System.currentTimeMillis();
-            connection.prepareStatement(mariaDbMapper.dropViewRawQuery(viewName))
+            connection.prepareStatement(mariaDbMapper.dropViewRawQuery(view.getInternalName()))
                     .execute();
             log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
             connection.commit();
@@ -187,14 +44,13 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe
         } finally {
             dataSource.close();
         }
-        log.info("Deleted view {}.{}", database.getInternalName(), viewName);
+        log.info("Deleted view {}.{}", view.getDatabase(), view.getInternalName());
     }
 
-
     @Override
-    public Long count(PrivilegedViewDto view, Instant timestamp) throws SQLException,
+    public Long count(ViewDto view, Instant timestamp) throws SQLException,
             QueryMalformedException {
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(view.getDatabase());
+        final ComboPooledDataSource dataSource = getDataSource(view);
         final Connection connection = dataSource.getConnection();
         final Long queryResult;
         try {
@@ -208,12 +64,12 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe
             connection.commit();
         } catch (SQLException e) {
             connection.rollback();
-            log.error("Failed to find row count from view {}.{}: {}", view.getDatabase().getInternalName(), view.getInternalName(), e.getMessage());
-            throw new QueryMalformedException("Failed to find row count from view " + view.getDatabase().getInternalName() + "." + view.getInternalName() + ": " + e.getMessage(), e);
+            log.error("Failed to find row count from view {}.{}: {}", view.getDatabase(), view.getInternalName(), e.getMessage());
+            throw new QueryMalformedException("Failed to find row count from view " + view.getDatabase() + "." + view.getInternalName() + ": " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        log.info("Find row count from view {}.{}", view.getDatabase().getInternalName(), view.getInternalName());
+        log.info("Find row count from view {}.{}", view.getDatabase(), view.getInternalName());
         return queryResult;
     }
 
diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf
index fd66cf805ef4bc7d5e7bb5e93ee54381015e88f6..68778de757bf331e183e7258755c6f3ef210d6ec 100644
--- a/dbrepo-gateway-service/dbrepo.conf
+++ b/dbrepo-gateway-service/dbrepo.conf
@@ -40,6 +40,10 @@ upstream dashboard-service {
     server dashboard-service:3000;
 }
 
+upstream auth-service {
+    server auth-service:8080;
+}
+
 server {
     listen 8080 default_server;
     server_name _;
@@ -67,6 +71,26 @@ server {
         proxy_read_timeout      90;
     }
 
+    # Proxy Keycloak OIDC connections, c.f. https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations
+    location /realms {
+        proxy_set_header        Host $host;
+        proxy_set_header        X-Real-IP $remote_addr;
+        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header        X-Forwarded-Proto $scheme;
+        proxy_pass              http://auth-service;
+        proxy_read_timeout      90;
+    }
+
+    # Proxy Keycloak assets, c.f. https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations
+    location /resources {
+        proxy_set_header        Host $host;
+        proxy_set_header        X-Real-IP $remote_addr;
+        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header        X-Forwarded-Proto $scheme;
+        proxy_pass              http://auth-service;
+        proxy_read_timeout      90;
+    }
+
     location /api/search {
         proxy_set_header        Host $host;
         proxy_set_header        X-Real-IP $remote_addr;
diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql
index c9ce89d1be71f4791c5e55dbb7c24f46e979355a..e2bde25ed6d64f69c4f8d6e897a49a672e3f9a71 100644
--- a/dbrepo-metadata-db/1_setup-schema.sql
+++ b/dbrepo-metadata-db/1_setup-schema.sql
@@ -3,10 +3,10 @@ BEGIN;
 CREATE TABLE IF NOT EXISTS `mdb_users`
 (
     id               character varying(36)  NOT NULL,
+    keycloak_id      character varying(36)  NOT NULL,
     username         character varying(255) NOT NULL,
     firstname        character varying(255),
     lastname         character varying(255),
-    email            character varying(255) NOT NULL,
     orcid            character varying(255),
     affiliation      character varying(255),
     is_internal      BOOLEAN                NOT NULL DEFAULT FALSE,
@@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS `mdb_users`
     theme            character varying(255) NOT NULL default ('light'),
     language         character varying(3)   NOT NULL default ('en'),
     PRIMARY KEY (id),
-    UNIQUE (username),
-    UNIQUE (email)
+    UNIQUE (keycloak_id),
+    UNIQUE (username)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS `mdb_images`
diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile
index 843c334a9acb3d24e061c42c72cb75c6068ef954..fa92b799eeaac75f9daea7b5a1eec11560b04647 100644
--- a/dbrepo-metadata-service/Dockerfile
+++ b/dbrepo-metadata-service/Dockerfile
@@ -12,7 +12,7 @@ COPY ./rest-service/pom.xml ./rest-service/
 COPY ./services/pom.xml ./services/
 COPY ./test/pom.xml ./test/
 
-RUN mvn verify -B -fn
+RUN mvn dependency:go-offline
 
 COPY ./api ./api
 COPY ./entities ./entities
diff --git a/dbrepo-metadata-service/api/pom.xml b/dbrepo-metadata-service/api/pom.xml
index 9baf18ff69870ee00658f67dc5fa5e43bab49581..0d534105f8a12d52201e2437d31360903292f657 100644
--- a/dbrepo-metadata-service/api/pom.xml
+++ b/dbrepo-metadata-service/api/pom.xml
@@ -6,18 +6,18 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-api</artifactId>
     <name>dbrepo-metadata-service-api</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
             <groupId>at.tuwien</groupId>
             <artifactId>dbrepo-metadata-service-entities</artifactId>
-            <version>1.6.1</version>
+            <version>1.6.3</version>
             <scope>compile</scope>
         </dependency>
     </dependencies>
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/PrivilegedObjectDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java
similarity index 59%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/PrivilegedObjectDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java
index c88fcabccfba67130fbc4a230d98fb749d5857dd..e947ece6320820e926a3674834310c785042603d 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/PrivilegedObjectDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java
@@ -1,6 +1,8 @@
 package at.tuwien.api;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.ToString;
@@ -9,10 +11,12 @@ import java.time.Instant;
 
 @Getter
 @Setter
+@EqualsAndHashCode
 @ToString
-public abstract class PrivilegedObjectDto {
+public abstract class CacheableDto {
 
     @JsonProperty("last_retrieved")
+    @Schema(example = "2025-01-23T12:09:01")
     private Instant lastRetrieved;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
index 0beb8a379491869edef613a594616beb21d1da83..16f45aec4d625639f1188e0e853b3a81bd71811f 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
@@ -1,13 +1,13 @@
 package at.tuwien.api.auth;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Email;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
-import java.util.List;
+import java.util.UUID;
 
 @Getter
 @Setter
@@ -20,23 +20,27 @@ import java.util.List;
 public class CreateUserDto {
 
     @NotNull
-    @Schema(example = "true")
-    private Boolean enabled;
+    @Schema(example = "3b91bc36-3eae-4662-a4be-8993624ab0cb", description = "The user id generated by Keycloak")
+    private UUID id;
+
+    @NotNull
+    @JsonProperty("ldap_id")
+    @Schema(example = "ea022d6d-b4a4-42f3-836f-ff4e596a527a", description = "The user id generated by OpenLDAP")
+    private UUID ldapId;
 
     @NotBlank
     @Schema(example = "user")
     private String username;
 
-    @NotBlank
-    @Email
-    @Schema(example = "user@example.com")
-    private String email;
+    @JsonProperty("given_name")
+    @Schema(example = "foo")
+    private String givenName;
 
-    private String firstName;
+    @JsonProperty("family_name")
+    @Schema(example = "bar")
+    private String familyName;
 
-    private String lastName;
-
-    @NotNull
-    private List<CredentialDto> credentials;
+    @Schema(example = "foo.bar@example.com")
+    private String email;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
deleted file mode 100644
index c9110e041aaf1187675c58d2365cf63e1f1f2003..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package at.tuwien.api.auth;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Email;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-@Getter
-@Setter
-@Builder
-@EqualsAndHashCode
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class SignupRequestDto {
-
-    @NotBlank
-    @Pattern(regexp = "^[a-z0-9]{3,}$")
-    @Schema(example = "user")
-    private String username;
-
-    @NotBlank
-    @Email
-    @Schema(example = "user@example.com")
-    private String email;
-
-    @NotNull
-    @ToString.Exclude
-    private String password;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
index 9b1f8fcd4791d018970cb8559b5a7dcd1b1d7210..71e7601b164bbda3a1efd21557d9695322ad0715 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
@@ -22,6 +22,7 @@ import java.time.Instant;
 public class ContainerBriefDto {
 
     @NotNull
+    @Schema(example = "4")
     private Long id;
 
     @NotNull
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java
index 9928c8e54d39287fc7a19bf84b6a99c7429f69bd..913ab26d9d4469fb3335d5dc1da8463c9afc0bd6 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java
@@ -1,7 +1,7 @@
 package at.tuwien.api.container;
 
+import at.tuwien.api.CacheableDto;
 import at.tuwien.api.container.image.ImageDto;
-import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
@@ -14,13 +14,15 @@ import java.time.Instant;
 @Getter
 @Setter
 @Builder
+@EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ContainerDto {
+public class ContainerDto extends CacheableDto {
 
     @NotNull
+    @Schema(example = "4")
     private Long id;
 
     @NotBlank
@@ -29,19 +31,21 @@ public class ContainerDto {
 
     @NotBlank
     @JsonProperty("internal_name")
-    @Schema(example = "data-db")
+    @Schema(example = "air_quality")
     private String internalName;
 
-    @NotBlank
+    @Schema(example = "data-db")
     private String host;
 
-    @NotNull
+    @Schema(example = "3306")
     private Integer port;
 
     @JsonProperty("ui_host")
+    @Schema(example = "example.com")
     private String uiHost;
 
     @JsonProperty("ui_port")
+    @Schema(example = "3306")
     private Integer uiPort;
 
     @NotNull
@@ -55,4 +59,18 @@ public class ContainerDto {
     @Schema(example = "10")
     private Long count;
 
+    @ToString.Exclude
+    @Schema(example = "username")
+    private String username;
+
+    @ToString.Exclude
+    @Schema(example = "p4ssw0rd")
+    private String password;
+
+    /* lombok limitations prevent from convenient builder functions */
+
+    @JsonProperty("last_retrieved")
+    @Schema(example = "2025-01-23T12:09:01")
+    private Instant lastRetrieved;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java
similarity index 68%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java
index 86b50bea70209334a41458c47610c07f44f1799f..23062ffd9082098f13524ddd283b39310ecf39d5 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java
@@ -14,7 +14,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ContainerCreateDto {
+public class CreateContainerDto {
 
     @NotBlank
     @Schema(example = "Air Quality")
@@ -22,20 +22,22 @@ public class ContainerCreateDto {
 
     @NotNull
     @JsonProperty("image_id")
-    @Schema(description = "Image ID")
+    @Schema(example = "1", description = "Image ID")
     private Long imageId;
 
     @NotBlank
-    @Schema(description = "Hostname of container")
+    @Schema(example = "data-db2", description = "Hostname of container")
     private String host;
 
-    @Schema(description = "Port of container")
+    @Schema(example = "3306", description = "Port of container")
     private Integer port;
 
     @JsonProperty("ui_host")
+    @Schema(example = "example.com")
     private String uiHost;
 
     @JsonProperty("ui_port")
+    @Schema(example = "3306")
     private Integer uiPort;
 
     @NotNull
@@ -44,11 +46,11 @@ public class ContainerCreateDto {
 
     @NotBlank
     @JsonProperty("privileged_username")
-    @Schema(description = "Username of privileged user", example = "root")
+    @Schema(example = "root", description = "Username of privileged user")
     private String privilegedUsername;
 
     @NotBlank
     @JsonProperty("privileged_password")
-    @Schema(description = "Password of privileged user")
+    @Schema(example = "dbrepo", description = "Password of privileged user")
     private String privilegedPassword;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java
index 880db11fbd9818ed432f8dab7a910c48a51bf72e..6a9a970c0f5b3931bbcab7f53be099138d568c12 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java
@@ -18,6 +18,7 @@ import lombok.extern.jackson.Jacksonized;
 public class ImageBriefDto {
 
     @NotNull
+    @Schema(example = "5")
     private Long id;
 
     @NotBlank
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java
index 3baa76171b1ad00ab575a0fafa403c675e16f640..a9c37fb8485db0e90b4b5d56b91b53ad4ec47940 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java
@@ -20,6 +20,7 @@ import java.util.List;
 public class ImageDto {
 
     @NotNull
+    @Schema(example = "1")
     private Long id;
 
     @NotBlank
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java
deleted file mode 100644
index 9c414e5ef1f0201da252e58494048d537996bb56..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package at.tuwien.api.container.internal;
-
-import at.tuwien.api.PrivilegedObjectDto;
-import at.tuwien.api.container.image.ImageDto;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.time.Instant;
-
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class PrivilegedContainerDto extends PrivilegedObjectDto {
-
-    @NotNull
-    private Long id;
-
-    @NotBlank
-    @Schema(example = "Air Quality")
-    private String name;
-
-    @NotBlank
-    @JsonProperty("internal_name")
-    @Schema(example = "data-db")
-    private String internalName;
-
-    @NotBlank
-    private String host;
-
-    @NotNull
-    private Integer port;
-
-    @JsonProperty("ui_host")
-    private String uiHost;
-
-    @JsonProperty("ui_port")
-    private Integer uiPort;
-
-    @NotNull
-    private ImageDto image;
-
-    @ToString.Exclude
-    private String username;
-
-    @ToString.Exclude
-    private String password;
-
-    @JsonProperty("last_retrieved")
-    private Instant lastRetrieved;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java
index a93e89ec96fd19a78767f135366422301d42d959..fa0f6fea49e0aaf1823ba26f70aa918ecd96d98d 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java
@@ -1,9 +1,11 @@
 package at.tuwien.api.database;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 
 @Getter
+@Schema
 public enum AccessTypeDto {
 
     @JsonProperty("read")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/UpdateDatabaseAccessDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java
similarity index 72%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/UpdateDatabaseAccessDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java
index 32084c865feafc27fd1ae0a1a534229b347d3538..965e10afd50884605ca8788a4653b2b2dc3b9f09 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/UpdateDatabaseAccessDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -12,9 +13,10 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class UpdateDatabaseAccessDto {
+public class CreateAccessDto {
 
     @NotNull
+    @Schema(example = "read")
     private AccessTypeDto type;
 
 
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java
similarity index 96%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java
index f87673764ea55479e86ede7e3f2b70c94cd16b9a..c10d6b0b5e2618a6c3854e591d99e477be952035 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java
@@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class DatabaseCreateDto {
+public class CreateDatabaseDto {
 
     @NotNull
     @JsonProperty("container_id")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java
similarity index 96%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java
index 142a751ec4cc8eaceee7a9402af2c711d1acaa19..366845d08304881519c80f4984106626bf52a01a 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java
@@ -16,7 +16,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ViewCreateDto {
+public class CreateViewDto {
 
     @NotBlank
     @Size(min = 1, max = 63)
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java
index 7e929eb74843d7ad5589652c269f59d8bd7db498..d065a5892afb0cb342c12975f562820d1eeb6b10 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java
@@ -3,6 +3,7 @@ package at.tuwien.api.database;
 
 import at.tuwien.api.user.UserBriefDto;
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -31,6 +32,7 @@ public class DatabaseAccessDto {
     private UserBriefDto user;
 
     @NotNull
+    @Schema(example = "read")
     private AccessTypeDto type;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java
index 46072e83dc14af22d09923d3e9462a53506aa4f8..4cff48db18b1b337de7ae9d3a50c986e4c329028 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java
@@ -23,6 +23,7 @@ import java.util.UUID;
 public class DatabaseBriefDto {
 
     @NotNull
+    @Schema(example = "3")
     private Long id;
 
     @NotBlank
@@ -47,6 +48,7 @@ public class DatabaseBriefDto {
     @Schema(example = "true")
     private Boolean isSchemaPublic;
 
+    @NotNull
     private List<IdentifierBriefDto> identifiers;
 
     @NotNull
@@ -54,6 +56,10 @@ public class DatabaseBriefDto {
 
     @NotNull
     @JsonProperty("owner_id")
+    @Schema(example = "2f45ef7a-7f9b-4667-9156-152c87fe1ca5")
     private UUID ownerId;
 
+    @JsonProperty("preview_image")
+    private String previewImage;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java
index 5fc253c4335044a1eaabbb43d02f7ae07510178b..d6ea2bff9e2203439891e3a1a6aec6f17afc86a6 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java
@@ -1,8 +1,9 @@
 package at.tuwien.api.database;
 
-import at.tuwien.api.container.ContainerBriefDto;
-import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.identifier.IdentifierBriefDto;
+import at.tuwien.api.CacheableDto;
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.database.table.TableDto;
+import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.UserBriefDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -11,19 +12,21 @@ import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
+import java.time.Instant;
 import java.util.List;
 
 @Getter
 @Setter
 @Builder
-@EqualsAndHashCode
+@EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class DatabaseDto {
+public class DatabaseDto extends CacheableDto {
 
     @NotNull
+    @Schema(example = "3")
     private Long id;
 
     @NotBlank
@@ -47,9 +50,11 @@ public class DatabaseDto {
     @Schema(example = "Air Quality")
     private String description;
 
-    private List<TableBriefDto> tables;
+    @NotNull
+    private List<TableDto> tables;
 
-    private List<ViewBriefDto> views;
+    @NotNull
+    private List<ViewDto> views;
 
     @NotNull
     @JsonProperty("is_public")
@@ -61,14 +66,16 @@ public class DatabaseDto {
     @Schema(example = "true")
     private Boolean isSchemaPublic;
 
-    @NotNull
-    private ContainerBriefDto container;
+    private ContainerDto container;
 
+    @NotNull
     private List<DatabaseAccessDto> accesses;
 
-    private List<IdentifierBriefDto> identifiers;
+    @NotNull
+    private List<IdentifierDto> identifiers;
 
-    private List<IdentifierBriefDto> subsets;
+    @NotNull
+    private List<IdentifierDto> subsets;
 
     @NotNull
     private UserBriefDto contact;
@@ -79,4 +86,10 @@ public class DatabaseDto {
     @JsonProperty("preview_image")
     private String previewImage;
 
+    /* lombok limitations prevent from convenient builder functions */
+
+    @JsonProperty("last_retrieved")
+    @Schema(example = "2025-01-23T12:09:01")
+    private Instant lastRetrieved;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java
index 9b7c9fca89472a956b5d142e69c498c616fce81a..f68067e8a870f01b402b23a3b27bd0a065e186fd 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java
@@ -20,10 +20,12 @@ import java.util.UUID;
 public class ViewBriefDto {
 
     @NotNull
+    @Schema(example = "4")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "1")
     private Long vdbid;
 
     @NotBlank
@@ -31,8 +33,8 @@ public class ViewBriefDto {
     private String name;
 
     @NotBlank
-    @JsonProperty("internal_name")
     @Schema(example = "air_quality")
+    @JsonProperty("internal_name")
     private String internalName;
 
     @JsonProperty("is_public")
@@ -57,6 +59,7 @@ public class ViewBriefDto {
     private String queryHash;
 
     @JsonProperty("owned_by")
+    @Schema(example = "ac750fcf-ea02-4fce-85ac-d73857e18b35")
     private UUID ownedBy;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java
index 4005433afedbd5440b939d97bcd874f570a56c29..24cca8e4cc7325904c83845d42d060814753d171 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java
@@ -20,42 +20,41 @@ import lombok.extern.jackson.Jacksonized;
 public class ViewColumnDto {
 
     @NotNull
+    @Schema(example = "12")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "1")
     private Long databaseId;
 
     @NotNull
-    @Schema(example = "0")
     @JsonProperty("ord")
+    @Schema(example = "0")
     private Integer ordinalPosition;
 
     @NotBlank
     @Size(max = 64)
-    @Schema(example = "Date")
+    @Schema(example = "Given Name")
     private String name;
 
     @NotBlank
     @Size(max = 64)
     @JsonProperty("internal_name")
-    @Schema(example = "mdb_date")
+    @Schema(example = "given_name")
     private String internalName;
 
-    @NotNull
-    @JsonProperty("auto_generated")
-    @Schema(example = "false")
-    private Boolean autoGenerated;
-
     @JsonProperty("index_length")
+    @Schema(example = "255")
     private Long indexLength;
 
     @JsonProperty("length")
+    @Schema(example = "255")
     private Long length;
 
     @NotNull
     @JsonProperty("type")
-    @Schema(example = "string")
+    @Schema(example = "varchar")
     private ColumnTypeDto columnType;
 
     @Schema(example = "255")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java
index d1ee156e9b95c09a9dd31c1ddf01926818f75879..82a7081e16f08a2cc2c3a7c02a28760adc7ef9d1 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database;
 
+import at.tuwien.api.CacheableDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.UserBriefDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -9,29 +10,33 @@ import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
+import java.time.Instant;
 import java.util.List;
 
 @Getter
 @Setter
 @Builder
-@EqualsAndHashCode
+@EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ViewDto {
+public class ViewDto extends CacheableDto {
 
     @NotNull
+    @Schema(example = "4")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "1")
     private Long vdbid;
 
     @NotBlank
     @Schema(example = "Air Quality")
     private String name;
 
+    @NotNull
     private List<IdentifierDto> identifiers;
 
     @NotBlank
@@ -60,10 +65,20 @@ public class ViewDto {
     @Schema(example = "7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916")
     private String queryHash;
 
+    @ToString.Exclude
+    @EqualsAndHashCode.Exclude
+    private DatabaseDto database;
+
     @NotNull
     private UserBriefDto owner;
 
     @NotNull
     private List<ViewColumnDto> columns;
 
+    /* lombok limitations prevent from convenient builder functions */
+
+    @JsonProperty("last_retrieved")
+    @Schema(example = "2025-01-23T12:09:01")
+    private Instant lastRetrieved;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedDatabaseDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedDatabaseDto.java
deleted file mode 100644
index 2335ea39baf1a2e8f1461b56c844409f8e21b207..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedDatabaseDto.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package at.tuwien.api.database.internal;
-
-import at.tuwien.api.PrivilegedObjectDto;
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
-import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.identifier.IdentifierDto;
-import at.tuwien.api.user.UserBriefDto;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.time.Instant;
-import java.util.List;
-
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class PrivilegedDatabaseDto extends PrivilegedObjectDto {
-
-    @NotNull
-    private Long id;
-
-    @NotBlank
-    @Schema(example = "Air Quality")
-    private String name;
-
-    @NotBlank
-    @JsonProperty("exchange_name")
-    @Schema(example = "dbrepo")
-    private String exchangeName;
-
-    @JsonProperty("exchange_type")
-    @Schema(example = "topic")
-    private String exchangeType;
-
-    @NotBlank
-    @JsonProperty("internal_name")
-    @Schema(example = "air_quality")
-    private String internalName;
-
-    @Schema(example = "Air Quality")
-    private String description;
-
-    private List<TableDto> tables;
-
-    private List<ViewDto> views;
-
-    @NotNull
-    @JsonProperty("is_public")
-    @Schema(example = "true")
-    private Boolean isPublic;
-
-    @NotNull
-    @JsonProperty("is_schema_public")
-    @Schema(example = "true")
-    private Boolean isSchemaPublic;
-
-    @NotNull
-    private PrivilegedContainerDto container;
-
-    private List<DatabaseAccessDto> accesses;
-
-    private List<IdentifierDto> identifiers;
-
-    private List<IdentifierDto> subsets;
-
-    @NotNull
-    private UserBriefDto contact;
-
-    @NotNull
-    private UserBriefDto owner;
-
-    @JsonProperty("preview_image")
-    private String previewImage;
-
-    @JsonProperty("last_retrieved")
-    private Instant lastRetrieved;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedViewDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedViewDto.java
deleted file mode 100644
index bda575f45d05f21a29a7be3d9da6cdfe1511d855..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedViewDto.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package at.tuwien.api.database.internal;
-
-import at.tuwien.api.PrivilegedObjectDto;
-import at.tuwien.api.database.ViewColumnDto;
-import at.tuwien.api.identifier.IdentifierDto;
-import at.tuwien.api.user.UserBriefDto;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.time.Instant;
-import java.util.List;
-
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class PrivilegedViewDto extends PrivilegedObjectDto {
-
-    @NotNull
-    private Long id;
-
-    @NotNull
-    @JsonProperty("database_id")
-    private Long vdbid;
-
-    @NotNull
-    private PrivilegedDatabaseDto database;
-
-    @NotBlank
-    @Schema(example = "Air Quality")
-    private String name;
-
-    private List<IdentifierDto> identifiers;
-
-    @NotBlank
-    @Schema(example = "air_quality")
-    @JsonProperty("internal_name")
-    private String internalName;
-
-    @JsonProperty("is_public")
-    @Schema(example = "true")
-    private Boolean isPublic;
-
-    @JsonProperty("is_schema_public")
-    @Schema(example = "true")
-    private Boolean isSchemaPublic;
-
-    @JsonProperty("initial_view")
-    @Schema(example = "true", description = "True if it is the default view for the database")
-    private Boolean isInitialView;
-
-    @NotNull
-    @Schema(example = "SELECT `id` FROM `air_quality` ORDER BY `value` DESC")
-    private String query;
-
-    @NotNull
-    @JsonProperty("query_hash")
-    @Schema(example = "7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916")
-    private String queryHash;
-
-    @NotNull
-    private UserBriefDto owner;
-
-    @NotNull
-    private List<ViewColumnDto> columns;
-
-    @JsonProperty("last_retrieved")
-    private Instant lastRetrieved;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java
index 39cb6683a1cb2d5250054b8dd555bffbad929fad..20817e017622ff5619cf1eaf284f238ba02dff4b 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java
@@ -22,7 +22,7 @@ public class ImportDto {
     private String location;
 
     @NotNull
-    @Schema(description = "If true, the first line contains the column names, otherwise it contains only data")
+    @Schema(example = "true", description = "If true, the first line contains the column names, otherwise it contains only data")
     private Boolean header;
 
     @NotNull
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java
index cd1659e73c6a1e0a13e220e4a83aaaf5b5aacc2f..41cb641a5d8cdf8ccc6187c2f083447e4cdb4714 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java
@@ -24,10 +24,12 @@ import java.util.List;
 public class QueryDto {
 
     @NotNull
+    @Schema(example = "4")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "1")
     private Long databaseId;
 
     @NotNull
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java
index afc03ab97f9742d5d4d639b546ae983fa7525f35..4df28733cdba0830b0e1579805284a92581c42bb 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java
@@ -1,7 +1,9 @@
 package at.tuwien.api.database.query;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
 
+@Schema
 public enum QueryTypeDto {
 
     @JsonProperty("query")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java
similarity index 77%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java
index 7c3defcc0b69dc47e20c4e9aa9931fdfad1143b0..15a798ee2d6bd237a6f578678d8885ca3b0f87dd 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java
@@ -1,7 +1,7 @@
 package at.tuwien.api.database.table;
 
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
@@ -20,7 +20,7 @@ import java.util.List;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class TableCreateDto {
+public class CreateTableDto {
 
     @NotBlank
     @Size(min = 1, max = 64)
@@ -42,8 +42,8 @@ public class TableCreateDto {
     private Boolean isSchemaPublic;
 
     @NotNull
-    private List<ColumnCreateDto> columns;
+    private List<CreateTableColumnDto> columns;
 
     @NotNull
-    private ConstraintsCreateDto constraints;
+    private CreateTableConstraintsDto constraints;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java
index 29531012f1f2912cc7d7f0c326661cee868ec72d..98932f30a294febdc3df41290888c0d6d3ae7e5d 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java
@@ -20,10 +20,12 @@ import java.util.UUID;
 public class TableBriefDto {
 
     @NotNull
+    @Schema(example = "3")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "2")
     private Long databaseId;
 
     @NotBlank
@@ -55,5 +57,6 @@ public class TableBriefDto {
 
     @NotNull
     @JsonProperty("owned_by")
+    @Schema(example = "78337b80-5699-45db-8111-cec86439ab6b")
     private UUID ownedBy;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java
index 67087d438daedf60cd0236a8f5427310b06464e4..1021d167ca1364eb63b06d321040e708c4f7d6e2 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java
@@ -1,9 +1,13 @@
 package at.tuwien.api.database.table;
 
+import at.tuwien.api.CacheableDto;
+import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.constraints.ConstraintsDto;
 import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.user.UserBriefDto;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
@@ -12,23 +16,26 @@ import jakarta.validation.constraints.Size;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
+import java.time.Instant;
 import java.util.List;
 
 @Getter
 @Setter
 @Builder
-@EqualsAndHashCode
+@EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class TableDto {
+public class TableDto extends CacheableDto {
 
     @NotNull
+    @Schema(example = "3")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "2")
     private Long tdbid;
 
     @NotBlank
@@ -40,7 +47,7 @@ public class TableDto {
     @Schema(example = "air_quality")
     private String internalName;
 
-    @Schema
+    @Schema(example = "a")
     private String alias;
 
     private List<IdentifierDto> identifiers;
@@ -100,7 +107,17 @@ public class TableDto {
     @NotNull
     private List<ColumnDto> columns;
 
+    @ToString.Exclude
+    @EqualsAndHashCode.Exclude
+    private DatabaseDto database;
+
     @NotNull
     private ConstraintsDto constraints;
 
+    /* lombok limitations prevent from convenient builder functions */
+
+    @JsonProperty("last_retrieved")
+    @Schema(example = "2025-01-23T12:09:01")
+    private Instant lastRetrieved;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java
index 6c3a946e1257dd2a9a90175a1904d88cf2f1a339..f74ffb3d89a1cfc5582be30e89ff0cb6a573f8c5 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database.table;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -17,6 +18,7 @@ import java.util.Map;
 public class TupleDeleteDto {
 
     @NotNull
+    @Schema(example = "{\"id\": 1}")
     private Map<String, Object> keys;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java
index 62f57434b67dfe69e95bd212afb795f004da87d7..13dc2b9723e763a5b255c762f1d94974ef90d074 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database.table;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -17,6 +18,7 @@ import java.util.Map;
 public class TupleDto {
 
     @NotNull
+    @Schema(example = "{\"key\": \"value\"}")
     private Map<String, Object> data;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java
index be50791b944db8eada4316ca6ee975dedf95a113..ab3f1ae8758c69a9bfa0958e9a53e5326d8c91a9 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database.table;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -17,9 +18,11 @@ import java.util.Map;
 public class TupleUpdateDto {
 
     @NotNull
+    @Schema(example = "{\"key\": \"value\"}")
     private Map<String, Object> data;
 
     @NotNull
+    @Schema(example = "{\"id\": 1}")
     private Map<String, Object> keys;
 
 }
\ No newline at end of file
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java
index 4dee5f0837148f9c2d1095fdbe12d6ab664672ef..bc13700bdd83dfac5fe23c133509c0184834b7a9 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
@@ -18,31 +19,36 @@ import lombok.extern.jackson.Jacksonized;
 public class ColumnBriefDto {
 
     @NotNull
+    @Schema(example = "1")
     private Long id;
 
-    @JsonProperty("database_id")
     @NotNull
+    @Schema(example = "2")
+    @JsonProperty("database_id")
     private Long databaseId;
 
-    @JsonProperty("table_id")
     @NotNull
+    @Schema(example = "3")
+    @JsonProperty("table_id")
     private Long tableId;
 
     @NotBlank
-    @Schema(example = "date")
+    @Size(max = 64)
+    @Schema(example = "Given Name")
     private String name;
 
     @NotBlank
+    @Size(max = 64)
     @JsonProperty("internal_name")
-    @Schema(example = "mdb_date")
+    @Schema(example = "given_name")
     private String internalName;
 
-    @Schema
+    @Schema(example = "firstname")
     private String alias;
 
     @NotNull
-    @JsonProperty("column_type")
-    @Schema(example = "date")
+    @JsonProperty("type")
+    @Schema(example = "varchar")
     private ColumnTypeDto columnType;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java
index 1f8d3b046e7c6fc6512fc68e53095822a3513061..462821b53c0a8a01a7acb36f15a25641ac895cd8 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java
@@ -25,44 +25,49 @@ import java.util.List;
 public class ColumnDto {
 
     @NotNull
+    @Schema(example = "1")
     private Long id;
 
     @NotNull
     @JsonProperty("database_id")
+    @Schema(example = "2")
     private Long databaseId;
 
     @NotNull
     @JsonProperty("table_id")
+    @Schema(example = "3")
     private Long tableId;
 
     @NotNull
-    @Schema(example = "0")
     @JsonProperty("ord")
+    @Schema(example = "0")
     private Integer ordinalPosition;
 
     @NotBlank
     @Size(max = 64)
-    @Schema(example = "Date")
+    @Schema(example = "Given Name")
     private String name;
 
     @NotBlank
     @Size(max = 64)
     @JsonProperty("internal_name")
-    @Schema(example = "mdb_date")
+    @Schema(example = "given_name")
     private String internalName;
 
-    @Schema
+    @Schema(example = "firstname")
     private String alias;
 
     @JsonProperty("index_length")
+    @Schema(example = "255")
     private Long indexLength;
 
     @JsonProperty("length")
+    @Schema(example = "255")
     private Long length;
 
     @NotNull
     @JsonProperty("type")
-    @Schema(example = "string")
+    @Schema(example = "varchar")
     private ColumnTypeDto columnType;
 
     @Schema(example = "255")
@@ -114,9 +119,11 @@ public class ColumnDto {
     @Schema(example = "false")
     private Boolean isNullAllowed;
 
+    @Schema(example = "[\"val1\"]")
     @Parameter(description = "enum values, only considered when type = ENUM")
     private List<String> enums;
 
+    @Schema(example = "[\"val1\"]")
     @Parameter(description = "enum values, only considered when type = ENUM")
     private List<String> sets;
 
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java
index d44b25b84ed4c51075ab4c075433750c4aafca42..a96337082937c085e28957b7768a354dc5ed8dd6 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java
@@ -1,10 +1,12 @@
 package at.tuwien.api.database.table.columns;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 
 /* MYSQL 8 */
 @Getter
+@Schema
 public enum ColumnTypeDto {
 
     @JsonProperty("char")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java
similarity index 97%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java
index ca9bb10569e7bbeb30dd4b8080d0adbbcd2fab75..ca7f3b8d58a3ee08a342b6df0452719c786b863b 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java
@@ -18,7 +18,7 @@ import java.util.List;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ColumnCreateDto {
+public class CreateTableColumnDto {
 
     @NotBlank
     @Schema(example = "Date")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java
index 1e2b36dc66a2f75a846e0ee66cef2037bb8cfd8b..3cc1231c7452aa809ef7ecf4d85244d0c9f400e0 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database.table.columns.concepts;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
@@ -16,13 +17,17 @@ import lombok.extern.jackson.Jacksonized;
 public class ConceptBriefDto {
 
     @NotNull
+    @Schema(example = "23")
     private Long id;
 
     @NotBlank
+    @Schema(example = "http://www.wikidata.org/entity/Q202444")
     private String uri;
 
+    @Schema(example = "given name")
     private String name;
 
+    @Schema(example = "name typically used to differentiate people from the same family, clan, or other social group who have a common last name")
     private String description;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java
index 407f3708eb7a7fbe2b9746122b1f712858b8cf5e..15d9ae90823e05491b692932af518a768cfc1305 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database.table.columns.concepts;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
@@ -16,12 +17,16 @@ import lombok.extern.jackson.Jacksonized;
 public class UnitBriefDto {
 
     @NotNull
+    @Schema(example = "34")
     private Long id;
 
     @NotBlank
+    @Schema(example = "http://www.wikidata.org/entity/Q1422583")
     private String uri;
 
+    @Schema(example = "importance")
     private String name;
 
+    @Schema(example = "subjective magnitude of value, meaning, or purpose")
     private String description;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java
index 3cd36f6d687892224e668100e6171552c090b449..b9288b659bb7e2accb18c14e8258f631327d10f3 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java
@@ -4,6 +4,7 @@ import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
 import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
 import at.tuwien.api.database.table.constraints.unique.UniqueDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
@@ -24,6 +25,7 @@ public class ConstraintsDto {
     @JsonProperty("foreign_keys")
     private List<ForeignKeyDto> foreignKeys;
 
+    @Schema(example = "[\"value > 1\"]")
     private Set<String> checks;
 
     @JsonProperty("primary_key")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java
similarity index 77%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java
index 3d35a20b0c57ae76f2d5fb6c4843e4d46d43ffab..7b223372d2ae0057149e3b9ed95824c7a5baa05d 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java
@@ -1,6 +1,6 @@
 package at.tuwien.api.database.table.constraints;
 
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto;
+import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
@@ -17,14 +17,14 @@ import java.util.Set;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ConstraintsCreateDto {
+public class CreateTableConstraintsDto {
 
     @NotNull
     private List<List<String>> uniques;
 
     @NotNull
     @JsonProperty("foreign_keys")
-    private List<ForeignKeyCreateDto> foreignKeys;
+    private List<CreateForeignKeyDto> foreignKeys;
 
     @NotNull
     private Set<String> checks;
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java
similarity index 95%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java
index 8e2a110997bb257b9414a9780fb29751265cce76..31e43b0c6a4377b59d096f5acf5b6bf43067a295 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java
@@ -14,7 +14,7 @@ import java.util.List;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class ForeignKeyCreateDto {
+public class CreateForeignKeyDto {
 
     @NotNull
     private List<String> columns;
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java
index 58a4d5b2453f617297673891f4a879fb02409f10..56dd9863245a51219c1604c43636dd27adea2bd8 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.database.table.constraints.foreign;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
@@ -12,5 +13,6 @@ import lombok.extern.jackson.Jacksonized;
 @ToString
 public class ForeignKeyBriefDto {
 
+    @Schema(example = "8")
     private Long id;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java
index 8016de91316bb0a5cbac30fc4148ecc39acdc33b..254666f9eb6b056501bc08ecebb745c5eac61345 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java
@@ -4,6 +4,7 @@ import at.tuwien.api.database.table.TableBriefDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -19,9 +20,11 @@ import java.util.List;
 @ToString
 public class ForeignKeyDto {
 
+    @Schema(example = "4")
     private Long id;
 
     @NotNull
+    @Schema(example = "fk_name")
     private String name;
 
     @NotNull
@@ -35,8 +38,10 @@ public class ForeignKeyDto {
     private TableBriefDto referencedTable;
 
     @JsonProperty("on_update")
+    @Schema(example = "restrict")
     private ReferenceTypeDto onUpdate;
 
     @JsonProperty("on_delete")
+    @Schema(example = "restrict")
     private ReferenceTypeDto onDelete;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java
index 55fcc46ecf85fc097eeef7677b9d0c897c612aa3..f0d5b249cdbc41222a5c71c6d41855f1aa5cc5df 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java
@@ -2,6 +2,7 @@ package at.tuwien.api.database.table.constraints.foreign;
 
 import at.tuwien.api.database.table.columns.ColumnBriefDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -15,6 +16,7 @@ import lombok.extern.jackson.Jacksonized;
 @ToString
 public class ForeignKeyReferenceDto {
 
+    @Schema(example = "8")
     private Long id;
 
     @NotNull
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java
index 80df5d443b70146c2ce2cda6e96bbf75c1816e28..86d1d49960d2c9496ce5d23e26fa99edadec344e 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java
@@ -2,6 +2,7 @@ package at.tuwien.api.database.table.constraints.primary;
 
 import at.tuwien.api.database.table.TableBriefDto;
 import at.tuwien.api.database.table.columns.ColumnBriefDto;
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -15,6 +16,7 @@ import lombok.extern.jackson.Jacksonized;
 @ToString
 public class PrimaryKeyDto {
 
+    @Schema(example = "8")
     private Long id;
 
     @NotNull
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java
index 2bcc9d6cf4fb4d130c398dc2ed0341af46f61df9..755f3a31b7a9634bff74c8992bb384719297c256 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java
@@ -1,13 +1,11 @@
-
 package at.tuwien.api.database.table.constraints.unique;
 
 import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
+import at.tuwien.api.database.table.columns.ColumnBriefDto;
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
-import org.springframework.data.annotation.Id;
 
 import java.util.List;
 
@@ -21,14 +19,16 @@ import java.util.List;
 public class UniqueDto {
 
     @NotNull
+    @Schema(example = "5")
     private Long id;
 
     @NotNull
+    @Schema(example = "uk_name")
     private String name;
 
     @NotNull
     private TableBriefDto table;
 
     @NotNull
-    private List<ColumnDto> columns;
+    private List<ColumnBriefDto> columns;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/PrivilegedTableDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/PrivilegedTableDto.java
deleted file mode 100644
index 64b23f17c412c1042c0a1db9a040a67fcc612b39..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/PrivilegedTableDto.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package at.tuwien.api.database.table.internal;
-
-import at.tuwien.api.PrivilegedObjectDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.constraints.ConstraintsDto;
-import at.tuwien.api.identifier.IdentifierDto;
-import at.tuwien.api.user.UserBriefDto;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Size;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.time.Instant;
-import java.util.List;
-
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-@EqualsAndHashCode
-public class PrivilegedTableDto extends PrivilegedObjectDto {
-
-    @NotNull
-    private Long id;
-
-    @NotNull
-    @JsonProperty("database_id")
-    private Long tdbid;
-
-    @NotBlank
-    @Schema(example = "Air Quality")
-    private String name;
-
-    @NotBlank
-    @JsonProperty("internal_name")
-    @Schema(example = "air_quality")
-    private String internalName;
-
-    @Schema
-    private String alias;
-
-    private List<IdentifierDto> identifiers;
-
-    @NotNull
-    @JsonProperty("is_versioned")
-    @Schema(example = "true")
-    private Boolean isVersioned;
-
-    @NotNull
-    @JsonProperty("is_schema_public")
-    @Schema(example = "true")
-    private Boolean isSchemaPublic;
-
-    @NotNull
-    private UserBriefDto owner;
-
-    @NotBlank
-    @JsonProperty("queue_name")
-    @Schema(example = "air_quality")
-    private String queueName;
-
-    @JsonProperty("queue_type")
-    @Schema(example = "quorum")
-    private String queueType;
-
-    @NotBlank
-    @JsonProperty("routing_key")
-    @Schema(example = "dbrepo.1.2")
-    private String routingKey;
-
-    @Size(max = 2048)
-    @Schema(example = "Air Quality in Austria")
-    private String description;
-
-    @NotNull
-    @JsonProperty("is_public")
-    @Schema(example = "true")
-    private Boolean isPublic;
-
-    @JsonProperty("num_rows")
-    @Schema(example = "5")
-    private Long numRows;
-
-    @JsonProperty("data_length")
-    @Schema(example = "16384", description = "in bytes")
-    private Long dataLength;
-
-    @JsonProperty("max_data_length")
-    @Schema(example = "0", description = "in bytes")
-    private Long maxDataLength;
-
-    @JsonProperty("avg_row_length")
-    @Schema(example = "3276", description = "in bytes")
-    private Long avgRowLength;
-
-    @NotNull
-    private List<ColumnDto> columns;
-
-    @NotNull
-    private ConstraintsDto constraints;
-
-    @NotNull
-    private PrivilegedDatabaseDto database;
-
-    @JsonProperty("last_retrieved")
-    private Instant lastRetrieved;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java
index 777a870bb9650f0e06b732f0a5776a6768902945..f8db928e8e9bb3d7491e67ea36756b95749a4482 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java
@@ -1,7 +1,7 @@
 package at.tuwien.api.database.table.internal;
 
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
@@ -41,8 +41,8 @@ public class TableCreateDto {
     private Boolean isSchemaPublic;
 
     @NotNull
-    private List<ColumnCreateDto> columns;
+    private List<CreateTableColumnDto> columns;
 
     @NotNull
-    private ConstraintsCreateDto constraints;
+    private CreateTableConstraintsDto constraints;
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java
similarity index 84%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierCreateDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java
index 46eb1bbc7db597e788918745d526ba7dace1ed1b..db55272383828e1bfc0c870f086ecc2c27ecba03 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierCreateDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java
@@ -19,7 +19,7 @@ import java.util.List;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class IdentifierCreateDto {
+public class CreateIdentifierDto {
 
     @NotNull
     @JsonProperty("database_id")
@@ -47,11 +47,11 @@ public class IdentifierCreateDto {
 
     @NotNull
     @NotEmpty
-    private List<IdentifierSaveTitleDto> titles;
+    private List<SaveIdentifierTitleDto> titles;
 
-    private List<IdentifierSaveDescriptionDto> descriptions;
+    private List<SaveIdentifierDescriptionDto> descriptions;
 
-    private List<IdentifierFunderSaveDto> funders;
+    private List<SaveIdentifierFunderDto> funders;
 
     private List<LicenseDto> licenses;
 
@@ -76,9 +76,9 @@ public class IdentifierCreateDto {
 
     @NotNull
     @NotEmpty
-    private List<CreatorSaveDto> creators;
+    private List<SaveIdentifierCreatorDto> creators;
 
     @JsonProperty("related_identifiers")
-    private List<RelatedIdentifierSaveDto> relatedIdentifiers;
+    private List<SaveRelatedIdentifierDto> relatedIdentifiers;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..8265a1106bc8daef632f887e9c38c148d765fb01
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java
@@ -0,0 +1,53 @@
+package at.tuwien.api.identifier;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class CreatorBriefDto {
+
+    @NotNull
+    @Schema(example = "11")
+    private Long id;
+
+    @NotBlank
+    @JsonProperty("creator_name")
+    @Schema(example = "Carberry, Josiah")
+    private String creatorName;
+
+    @JsonProperty("name_type")
+    @Schema(example = "Personal")
+    private NameTypeDto nameType;
+
+    @JsonProperty("name_identifier")
+    @Schema(example = "0000-0002-1825-0097")
+    private String nameIdentifier;
+
+    @JsonProperty("name_identifier_scheme")
+    @Schema(example = "ORCID")
+    private NameIdentifierSchemeTypeDto nameIdentifierScheme;
+
+    @Schema(example = "Brown University")
+    private String affiliation;
+
+    @JsonProperty("affiliation_identifier")
+    @Schema(example = "https://ror.org/05gq02987")
+    private String affiliationIdentifier;
+
+    @JsonProperty("affiliation_identifier_scheme")
+    @Schema(example = "ROR")
+    private AffiliationIdentifierSchemeTypeDto affiliationIdentifierScheme;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java
index 9c166f869c5bcec81c1e67212616e03833fe64c7..a3a2976901aee60e60162788dd10df239206e826 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java
@@ -21,6 +21,7 @@ import org.springframework.data.annotation.Id;
 public class CreatorDto {
 
     @NotNull
+    @Schema(example = "11")
     private Long id;
 
     @Schema(example = "Josiah")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
index 0a36c561a30a480f14251e1ddab396b8a3fcc9ae..f94edc2cf75421855a8bcd761252e6aba249bb27 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
@@ -1,6 +1,5 @@
 package at.tuwien.api.identifier;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
@@ -8,7 +7,6 @@ import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
-import java.time.Instant;
 import java.util.List;
 import java.util.UUID;
 
@@ -22,6 +20,7 @@ import java.util.UUID;
 public class IdentifierBriefDto {
 
     @NotNull
+    @Schema(example = "2")
     private Long id;
 
     @NotNull
@@ -42,11 +41,18 @@ public class IdentifierBriefDto {
     private Long viewId;
 
     @NotNull
+    @Schema(example = "database")
     private IdentifierTypeDto type;
 
+    @NotNull
+    private List<CreatorBriefDto> creators;
+
     @NotNull
     private List<IdentifierTitleDto> titles;
 
+    @NotNull
+    private List<IdentifierDescriptionDto> descriptions;
+
     @Schema(example = "10.1038/nphys1170")
     private String doi;
 
@@ -59,10 +65,13 @@ public class IdentifierBriefDto {
     @Schema(example = "2022")
     private Integer publicationYear;
 
+    @NotNull
+    @Schema(example = "draft")
     private IdentifierStatusTypeDto status;
 
     @NotNull
-    @JsonProperty("created_by")
-    private UUID createdBy;
+    @JsonProperty("owned_by")
+    @Schema(example = "2f45ef7a-7f9b-4667-9156-152c87fe1ca5")
+    private UUID ownedBy;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java
index 55e6ff76214a8af82ec32991c62aa265909d75f6..fbcbb3afe7b6cb9ca27aee16b2875c5ed5d03c1b 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java
@@ -19,6 +19,7 @@ import org.springframework.data.annotation.Id;
 public class IdentifierDescriptionDto {
 
     @NotNull
+    @Schema(example = "3")
     private Long id;
 
     @Schema(example = "Air quality reports at Stephansplatz, Vienna")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java
index 87baf4870661e292dbb69d180cfb1be43ac15f16..53d40ecd781169f531a6cf215d370fd69be9d2b0 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java
@@ -25,6 +25,7 @@ import java.util.List;
 public class IdentifierDto {
 
     @NotNull
+    @Schema(example = "2")
     private Long id;
 
     @NotNull
@@ -45,13 +46,16 @@ public class IdentifierDto {
     private Long viewId;
 
     @NotNull
+    @Schema(example = "database")
     private IdentifierTypeDto type;
 
     @NotNull
     private List<IdentifierTitleDto> titles;
 
+    @NotNull
     private List<IdentifierDescriptionDto> descriptions;
 
+    @NotNull
     private List<IdentifierFunderDto> funders;
 
     @NotBlank
@@ -106,13 +110,17 @@ public class IdentifierDto {
     @Schema(example = "2022")
     private Integer publicationYear;
 
+    @NotNull
     private LanguageTypeDto language;
 
+    @NotNull
     private List<LicenseDto> licenses;
 
     @NotNull
     private List<CreatorDto> creators;
 
+    @NotNull
+    @Schema(example = "draft")
     private IdentifierStatusTypeDto status;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java
index 921ba3eb983840dee342071bfde0a75f478946b4..93084d2d17679b94d825600761c1aa03c3b1bdde 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java
@@ -19,6 +19,7 @@ import org.springframework.data.annotation.Id;
 public class IdentifierFunderDto {
 
     @NotNull
+    @Schema(example = "2")
     private Long id;
 
     @NotBlank
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java
index 8591cdc8c2b6b6c35672c8bf7451652b5a523e61..ed4d445de0ffd2686a84331981d3d5899a4a9b65 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java
@@ -51,11 +51,11 @@ public class IdentifierSaveDto {
 
     @NotNull
     @NotEmpty
-    private List<IdentifierSaveTitleDto> titles;
+    private List<SaveIdentifierTitleDto> titles;
 
-    private List<IdentifierSaveDescriptionDto> descriptions;
+    private List<SaveIdentifierDescriptionDto> descriptions;
 
-    private List<IdentifierFunderSaveDto> funders;
+    private List<SaveIdentifierFunderDto> funders;
 
     private List<LicenseDto> licenses;
 
@@ -80,9 +80,9 @@ public class IdentifierSaveDto {
 
     @NotNull
     @NotEmpty
-    private List<CreatorSaveDto> creators;
+    private List<SaveIdentifierCreatorDto> creators;
 
     @JsonProperty("related_identifiers")
-    private List<RelatedIdentifierSaveDto> relatedIdentifiers;
+    private List<SaveRelatedIdentifierDto> relatedIdentifiers;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java
index 9333a05ce961a403b84463a10abc86ddb2a2e86c..27e3b323eaca7d9ab481af61059a05fbe576c42d 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java
@@ -19,6 +19,7 @@ import org.springframework.data.annotation.Id;
 public class IdentifierTitleDto {
 
     @NotNull
+    @Schema(example = "4")
     private Long id;
 
     @Schema(example = "Airquality Demonstrator")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java
index 74525bf711988a0690aeba9c403a44156885b0f3..6ff5d9aed1297f5a12755d76d03cc668a273e0e5 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java
@@ -24,6 +24,7 @@ import java.time.Instant;
 public class RelatedIdentifierDto {
 
     @NotNull
+    @Schema(example = "8")
     private Long id;
 
     @NotNull
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java
similarity index 97%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorSaveDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java
index 86d51e7b4cc3d132959f60731acd1352765df20f..c87ff81d3c058edd475d89102c8e29468dae211e 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorSaveDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java
@@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class CreatorSaveDto {
+public class SaveIdentifierCreatorDto {
 
     @NotNull
     @Schema(example = "1")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDescriptionDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java
similarity index 94%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDescriptionDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java
index 76f4f4b7bc1ff6e4763ec0e57f3de9ca1a1e125c..1d251db634d4f1a6cb0b369013c113aae69f1968 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDescriptionDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java
@@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class IdentifierSaveDescriptionDto {
+public class SaveIdentifierDescriptionDto {
 
     @NotNull
     @Schema(example = "1")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java
similarity index 96%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderSaveDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java
index 81fd7c91ab44c0f1b89d18656c214fdc50958e38..89bea57a1cf5c69a4184fae5edc3d77f8062bb39 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderSaveDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java
@@ -14,7 +14,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class IdentifierFunderSaveDto {
+public class SaveIdentifierFunderDto {
 
     @NotNull
     @Schema(example = "1")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveTitleDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java
similarity index 95%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveTitleDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java
index 9da7e7ec8b7d61f35fe963b2e651c2662e7353e9..0832a77cee0323db7220cf88ff295982fee2c0a1 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveTitleDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java
@@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class IdentifierSaveTitleDto {
+public class SaveIdentifierTitleDto {
 
     @NotNull
     @Schema(example = "1")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java
similarity index 93%
rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierSaveDto.java
rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java
index f72d5b02d29d038233031365b7172c93da567b5d..b3a95eee06fe4cc0cb91fb8df822e52c3f507221 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierSaveDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java
@@ -13,7 +13,7 @@ import jakarta.validation.constraints.NotNull;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class RelatedIdentifierSaveDto {
+public class SaveRelatedIdentifierDto {
 
     @NotNull
     @Schema(example = "1")
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..26d700e798e1517ae484dc60e9359bd8b5646965
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java
@@ -0,0 +1,26 @@
+package at.tuwien.api.keycloak;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class ModifyUserDto {
+
+    @JsonProperty("firstName")
+    private String firstname;
+
+    @JsonProperty("lastName")
+    private String lastname;
+
+    @NotNull
+    private UserAttributesDto attributes;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java
index 027955ba77b69fd708c1c18463c1a92d09c93c95..50718bc8034d500c2d707abacac58acf2bb95012 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java
@@ -16,12 +16,20 @@ import java.util.UUID;
 @ToString
 public class UserAttributesDto {
 
-    @Schema(example = "s3cr3t")
-    @JsonProperty("LDAP_ENTRY_DN")
-    private String[] ldapEntryDn;
+    @Schema(example = "dark")
+    @JsonProperty("THEME")
+    private String[] theme;
 
-    @Schema(example = "false")
-    @JsonProperty("LDAP_ID")
-    private UUID[] ldapId;
+    @Schema(example = "en")
+    @JsonProperty("LANGUAGE")
+    private String[] language;
+
+    @Schema(example = "https://ror.org/04d836q62")
+    @JsonProperty("AFFILIATION")
+    private String[] affiliation;
+
+    @Schema(example = "https://orcid.org/0000-0003-4216-302X")
+    @JsonProperty("ORCID")
+    private String[] orcid;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java
deleted file mode 100644
index a2d7811ab0aa334a4f3a5d49916428b58166317b..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package at.tuwien.api.keycloak;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.util.UUID;
-
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class UserDto {
-
-    @NotNull
-    private UUID id;
-
-    @NotNull
-    @Schema(example = "jcarberry", description = "Only contains lowercase characters")
-    private String username;
-
-    @NotNull
-    @Schema(example = "true")
-    private Boolean enabled;
-
-    @NotNull
-    @Schema(example = "false")
-    private Boolean totp;
-
-    @NotNull
-    @JsonProperty("emailVerified")
-    @Schema(example = "false")
-    private Boolean emailVerified;
-
-    @NotNull
-    @Schema(example = "jcarberry@brown.edu")
-    private String email;
-
-    @NotNull
-    @JsonProperty("notBefore")
-    @Schema(example = "0")
-    private Long notBefore;
-
-    @NotNull
-    private UserAttributesDto attributes;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..3155d75f027d2864f2a06ecf19376c13c9be7d35
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java
@@ -0,0 +1,27 @@
+package at.tuwien.api.keycloak;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.util.UUID;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class UserIdAttributesDto {
+
+    @Schema(example = "s3cr3t")
+    @JsonProperty("LDAP_ENTRY_DN")
+    private String[] ldapEntryDn;
+
+    @Schema(example = "false")
+    @JsonProperty("LDAP_ID")
+    private UUID[] ldapId;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java
index 78b87e33212ab48ba2e37a583100eea780c459e7..f883a034f55bd5f04d3059f8eb50ef50a3867c79 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated;
 
 public enum OrcidDisambiguatedSourceTypeDto {
-    RINGGOLD
+    RINGGOLD,
+    ROR
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
index cd5e8fd3e0cefe2f016261470b1236e9a3442b16..2ab170d616c75c40d4be36af42854d518d3ec7c5 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
@@ -1,6 +1,5 @@
 package at.tuwien.api.user;
 
-import jakarta.validation.constraints.Email;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -30,10 +29,6 @@ public class UserDetailsDto implements UserDetails {
     @ToString.Exclude
     private String password;
 
-    @NotNull
-    @Email
-    private String email;
-
     @Override
     public boolean isAccountNonExpired() {
         return true;
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java
index 343d582b55da3af324aa23fd31ef61d8e1cd564d..e7367e2fb4e513a9681783dfdec89b55e57519e0 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java
@@ -1,33 +1,40 @@
 package at.tuwien.api.user;
 
+import at.tuwien.api.CacheableDto;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
+import java.time.Instant;
 import java.util.UUID;
 
 @Getter
 @Setter
 @Builder
-@EqualsAndHashCode
+@EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class UserDto {
+public class UserDto extends CacheableDto {
 
     @NotNull
     @Schema(example = "1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4")
     private UUID id;
 
+    @Schema(example = "Josiah Carberry")
+    private String name;
+
     @NotNull
-    @Schema(example = "jcarberry", description = "Only contains lowercase characters")
+    @Schema(example = "username")
     private String username;
 
-    @Schema(example = "Josiah Carberry")
-    private String name;
+    @NotNull
+    @ToString.Exclude
+    @Schema(example = "p4ssw0rd")
+    private String password;
 
     @JsonProperty("qualified_name")
     @Schema(example = "Josiah Carberry — @jcarberry")
@@ -44,4 +51,10 @@ public class UserDto {
     @NotNull
     private UserAttributesDto attributes;
 
+    /* lombok limitations prevent from convenient builder functions */
+
+    @JsonProperty("last_retrieved")
+    @Schema(example = "2025-01-23T12:09:01")
+    private Instant lastRetrieved;
+
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/PrivilegedUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/PrivilegedUserDto.java
deleted file mode 100644
index 56e24cd81590261137cfa3d4f0f3c45399d80e70..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/PrivilegedUserDto.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package at.tuwien.api.user.internal;
-
-import at.tuwien.api.PrivilegedObjectDto;
-import at.tuwien.api.user.UserAttributesDto;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.time.Instant;
-import java.util.UUID;
-
-@Getter
-@Setter
-@Builder
-@EqualsAndHashCode
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class PrivilegedUserDto extends PrivilegedObjectDto {
-
-    @NotNull
-    @Schema(example = "1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4")
-    private UUID id;
-
-    @NotBlank
-    @Schema(example = "jcarberry", description = "Only contains lowercase characters")
-    private String username;
-
-    @NotBlank
-    @Schema(example = "jcarberry")
-    private String password;
-
-    @Schema(example = "Josiah Carberry")
-    private String name;
-
-    @JsonProperty("qualified_name")
-    @Schema(example = "Josiah Carberry — @jcarberry")
-    private String qualifiedName;
-
-    @JsonProperty("given_name")
-    @Schema(example = "Josiah")
-    private String firstname;
-
-    @JsonProperty("family_name")
-    @Schema(example = "Carberry")
-    private String lastname;
-
-    @NotNull
-    private UserAttributesDto attributes;
-
-    @JsonProperty("last_retrieved")
-    private Instant lastRetrieved;
-
-}
diff --git a/dbrepo-metadata-service/entities/pom.xml b/dbrepo-metadata-service/entities/pom.xml
index 5b1c1d0cf133fcfea9de76e37cc0462d318481b6..1967b24868d61e29351b34c8608c6f428bc316f9 100644
--- a/dbrepo-metadata-service/entities/pom.xml
+++ b/dbrepo-metadata-service/entities/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-entities</artifactId>
     <name>dbrepo-metadata-service-entity</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies/>
 
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java
index fd87852c6ecce0e2e614a9c7dd05a5e41cfe2e16..ba86e3d29c6913d45d51ae0498fdac8d3092b657 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java
@@ -30,6 +30,10 @@ public class User {
     @Column(name = "ID", nullable = false, columnDefinition = "VARCHAR(36)")
     private UUID id;
 
+    @JdbcTypeCode(java.sql.Types.VARCHAR)
+    @Column(name = "keycloak_id", nullable = false, columnDefinition = "VARCHAR(36)")
+    private UUID keycloakId;
+
     @Column(nullable = false)
     private String username;
 
@@ -39,9 +43,6 @@ public class User {
     @Column
     private String lastname;
 
-    @Column(nullable = false)
-    private String email;
-
     @Column
     private String orcid;
 
diff --git a/dbrepo-metadata-service/metrics.md b/dbrepo-metadata-service/metrics.md
index 56a69c68f6913ab2e3ea192cde66f329ea336e10..f3e0a3130f23e149a54f1eca8247c559443809da 100644
--- a/dbrepo-metadata-service/metrics.md
+++ b/dbrepo-metadata-service/metrics.md
@@ -59,8 +59,6 @@
 | `dbrepo_user_find`                 | Get user                      |
 | `dbrepo_user_modify`               | Update user                   |
 | `dbrepo_user_password_modify`      | Update user password          |
-| `dbrepo_user_refresh_token`        | Refresh token                 |
-| `dbrepo_user_token`                | Create token                  |
 | `dbrepo_users_list`                | List users                    |
 | `dbrepo_view_create`               | Create view                   |
 | `dbrepo_view_delete`               | Delete view                   |
diff --git a/dbrepo-metadata-service/oai/pom.xml b/dbrepo-metadata-service/oai/pom.xml
index a3778f036317625e12a6b526a7f1fafadbe237f6..b6db9e69674d52ae557644b94b7eb5302563c86f 100644
--- a/dbrepo-metadata-service/oai/pom.xml
+++ b/dbrepo-metadata-service/oai/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-oai</artifactId>
     <name>dbrepo-metadata-service-oai</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies/>
 
diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml
index 2803d9b5f39ddd69f34151251083c35e8a46b406..5dd6ce3318f7cb88a16c9c6ecc60c8d4c5ff5aa2 100644
--- a/dbrepo-metadata-service/pom.xml
+++ b/dbrepo-metadata-service/pom.xml
@@ -11,7 +11,7 @@
     <groupId>at.tuwien</groupId>
     <artifactId>dbrepo-metadata-service</artifactId>
     <name>dbrepo-metadata-service</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <description>Service that manages the metadata</description>
 
@@ -27,7 +27,7 @@
         <module>report</module>
     </modules>
 
-    <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/</url>
+    <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url>
     <developers>
         <developer>
             <name>Martin Weise</name>
@@ -52,7 +52,7 @@
         <apache-jena.version>4.10.0</apache-jena.version>
         <opencsv.version>5.7.1</opencsv.version>
         <super-csv.version>2.4.0</super-csv.version>
-        <keycloak.version>21.0.2</keycloak.version>
+        <keycloak.version>26.0.4</keycloak.version>
         <springdoc-openapi.version>2.3.0</springdoc-openapi.version>
         <testcontainers.version>1.19.1</testcontainers.version>
         <jackson.version>2.15.2</jackson.version>
@@ -187,6 +187,11 @@
             <artifactId>keycloak-common</artifactId>
             <version>${keycloak.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-admin-client</artifactId>
+            <version>${keycloak.version}</version>
+        </dependency>
         <dependency>
             <groupId>com.auth0</groupId>
             <artifactId>java-jwt</artifactId>
diff --git a/dbrepo-metadata-service/report/pom.xml b/dbrepo-metadata-service/report/pom.xml
index 6234a844d2c89c01c7e3d200ce79397ac99eac37..8d4d32c15d3e50cb65ba2300c58d25dcbb87eebd 100644
--- a/dbrepo-metadata-service/report/pom.xml
+++ b/dbrepo-metadata-service/report/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-report</artifactId>
     <name>dbrepo-metadata-service-report</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/repositories/pom.xml b/dbrepo-metadata-service/repositories/pom.xml
index 44fde031c181fa559abdbce4b81e59f76c5f4b48..57f89e7ed46587a564e57536d05b79fc1e5cb121 100644
--- a/dbrepo-metadata-service/repositories/pom.xml
+++ b/dbrepo-metadata-service/repositories/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-repositories</artifactId>
     <name>dbrepo-metadata-service-repositories</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
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 c5482f70411433f5df08bd0281a60c75d132bf26..cfbf858000ae4b2e58be5999c3c98123cc70582c 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
@@ -1,26 +1,25 @@
 package at.tuwien.mapper;
 
-import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.container.ContainerBriefDto;
-import at.tuwien.api.container.ContainerCreateDto;
 import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.api.container.image.DataTypeDto;
 import at.tuwien.api.container.image.ImageBriefDto;
 import at.tuwien.api.container.image.ImageCreateDto;
 import at.tuwien.api.container.image.ImageDto;
 import at.tuwien.api.crossref.CrossrefDto;
 import at.tuwien.api.database.*;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
 import at.tuwien.api.database.table.TableBriefDto;
 import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.columns.ColumnBriefDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.concepts.ConceptDto;
 import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto;
 import at.tuwien.api.database.table.columns.concepts.UnitDto;
 import at.tuwien.api.database.table.columns.concepts.UnitSaveDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
 import at.tuwien.api.database.table.constraints.ConstraintsDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto;
 import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
 import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
@@ -31,9 +30,7 @@ import at.tuwien.api.datacite.doi.*;
 import at.tuwien.api.identifier.*;
 import at.tuwien.api.identifier.ld.LdCreatorDto;
 import at.tuwien.api.identifier.ld.LdDatasetDto;
-import at.tuwien.api.keycloak.CredentialDto;
-import at.tuwien.api.keycloak.CredentialTypeDto;
-import at.tuwien.api.keycloak.UpdateCredentialsDto;
+import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.keycloak.UserCreateDto;
 import at.tuwien.api.maintenance.BannerMessageBriefDto;
 import at.tuwien.api.maintenance.BannerMessageCreateDto;
@@ -50,8 +47,8 @@ import at.tuwien.api.semantics.OntologyBriefDto;
 import at.tuwien.api.semantics.OntologyCreateDto;
 import at.tuwien.api.semantics.OntologyDto;
 import at.tuwien.api.user.UserBriefDto;
-import at.tuwien.api.user.UserDetailsDto;
 import at.tuwien.api.user.UserDto;
+import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.api.user.external.ExternalMetadataDto;
 import at.tuwien.api.user.external.ExternalResultType;
 import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
@@ -74,6 +71,8 @@ import at.tuwien.entities.maintenance.BannerMessage;
 import at.tuwien.entities.maintenance.BannerMessageType;
 import at.tuwien.entities.semantics.Ontology;
 import at.tuwien.entities.user.User;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.mapstruct.*;
 
 import java.text.Normalizer;
@@ -97,6 +96,16 @@ public interface MetadataMapper {
     })
     DataTypeDto dataTypeToDataTypeDto(DataType data);
 
+    @Mappings({
+            @Mapping(target = "attributes", ignore = true)
+    })
+    UserRepresentation userCreateDtoToUserRepresentation(UserCreateDto data);
+
+    @Mappings({
+            @Mapping(target = "accessToken", source = "token")
+    })
+    TokenDto accessTokenResponseToTokenDto(AccessTokenResponse data);
+
     BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data);
 
     BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data);
@@ -110,7 +119,17 @@ public interface MetadataMapper {
     @Mappings({
             @Mapping(target = "internalName", source = "name", qualifiedByName = "internalMapping")
     })
-    Container containerCreateRequestDtoToContainer(ContainerCreateDto data);
+    Container containerCreateRequestDtoToContainer(CreateContainerDto data);
+
+    UserUpdateDto userToUserUpdateDto(User data);
+
+    default List<String> optionalValueToMap(String value) {
+        final List<String> attr = new LinkedList<>();
+        if (value != null) {
+            attr.add(value);
+        }
+        return attr;
+    }
 
     ContainerDto containerToContainerDto(Container data);
 
@@ -120,7 +139,10 @@ public interface MetadataMapper {
     })
     ContainerBriefDto containerToContainerBriefDto(Container data);
 
-    PrivilegedDatabaseDto databaseToPrivilegedDatabaseDto(Database data);
+    @Mappings({
+            @Mapping(target = "previewImage", expression = "java(database.getImage() != null ? \"/api/database/\" + database.getId() + \"/image\" : null)")
+    })
+    DatabaseDto databaseToDatabaseDto(Database database);
 
     @Mappings({
             @Mapping(target = "titles", source = "."),
@@ -300,7 +322,8 @@ public interface MetadataMapper {
     IdentifierDto identifierToIdentifierDto(Identifier data);
 
     @Mappings({
-            @Mapping(target = "databaseId", source = "database.id")
+            @Mapping(target = "databaseId", source = "database.id"),
+            @Mapping(target = "ownedBy", source = "owner.id")
     })
     IdentifierBriefDto identifierToIdentifierBriefDto(Identifier data);
 
@@ -359,19 +382,19 @@ public interface MetadataMapper {
                 .build();
     }
 
-    Identifier identifierCreateDtoToIdentifier(IdentifierCreateDto data);
+    Identifier identifierCreateDtoToIdentifier(CreateIdentifierDto data);
 
     Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data);
 
     License licenseDtoToLicense(LicenseDto data);
 
-    IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(IdentifierSaveTitleDto data);
+    IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(SaveIdentifierTitleDto data);
 
-    IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(IdentifierSaveDescriptionDto data);
+    IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(SaveIdentifierDescriptionDto data);
 
-    IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(IdentifierFunderSaveDto data);
+    IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(SaveIdentifierFunderDto data);
 
-    IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(IdentifierCreateDto data);
+    IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(CreateIdentifierDto data);
 
     RelatedIdentifierDto relatedIdentifierToRelatedIdentifierDto(RelatedIdentifier data);
 
@@ -385,12 +408,14 @@ public interface MetadataMapper {
             @Mapping(target = "nameIdentifierSchemeUri", source = "nameIdentifierScheme", qualifiedByName = "nameSchemaMapper"),
             @Mapping(target = "affiliationIdentifierSchemeUri", source = "affiliationIdentifierScheme", qualifiedByName = "affiliationSchemaMapper"),
     })
-    Creator creatorCreateDtoToCreator(CreatorSaveDto data);
+    Creator creatorCreateDtoToCreator(SaveIdentifierCreatorDto data);
 
-    RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(RelatedIdentifierSaveDto data);
+    RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(SaveRelatedIdentifierDto data);
 
     IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data);
 
+    IdentifierStatusType identifierStatusTypeDtoToIdentifierStatusType(IdentifierStatusTypeDto data);
+
     default String identifierToLocationUrl(String baseUrl, Identifier data) {
         if (data.getType().equals(IdentifierType.SUBSET)) {
             return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId();
@@ -490,7 +515,7 @@ public interface MetadataMapper {
                 .name(data.getName())
                 .columns(data.getColumns()
                         .stream()
-                        .map(this::tableColumnToColumnDto)
+                        .map(this::tableColumnToColumnBriefDto)
                         .toList())
                 .table(tableToTableBriefDto(data.getTable()))
                 .build();
@@ -531,7 +556,7 @@ public interface MetadataMapper {
                 .build();
     }
 
-    default TableDto customTableToTableDto(Table data) {
+    default TableDto tableToTableDto(Table data) {
         final TableDto table = TableDto.builder()
                 .id(data.getId())
                 .name(data.getName())
@@ -544,6 +569,10 @@ public interface MetadataMapper {
                 .description(data.getDescription())
                 .identifiers(new LinkedList<>())
                 .columns(new LinkedList<>())
+                .database(databaseToDatabaseDto(data.getDatabase()
+                        .toBuilder()
+                        .tables(null)
+                        .build()))
                 .constraints(constraintsToConstraintsDto(data.getConstraints()))
                 .build();
         if (data.getIdentifiers() != null) {
@@ -620,7 +649,8 @@ public interface MetadataMapper {
     Unique uniqueDtoToUnique(UniqueDto data);
 
     @Mappings({
-            @Mapping(target = "ownedBy", source = "owner.id")
+            @Mapping(target = "ownedBy", source = "owner.id"),
+            @Mapping(target = "database", ignore = true)
     })
     Table tableDtoToTable(TableDto data);
 
@@ -629,7 +659,7 @@ public interface MetadataMapper {
     ReferenceType referenceTypeDtoToReferenceType(ReferenceTypeDto data);
 
     /* keep */
-    default Constraints constraintsCreateDtoToConstraints(ConstraintsCreateDto data, Database database, Table table) {
+    default Constraints constraintsCreateDtoToConstraints(CreateTableConstraintsDto data, Database database, Table table) {
         final int[] idx = new int[]{0, 0};
         final Constraints constrains = Constraints.builder()
                 .checks(data.getChecks())
@@ -723,6 +753,12 @@ public interface MetadataMapper {
     })
     ColumnDto tableColumnToColumnDto(TableColumn data);
 
+    @Mappings({
+            @Mapping(target = "tableId", source = "table.id"),
+            @Mapping(target = "databaseId", source = "table.database.id")
+    })
+    ColumnBriefDto tableColumnToColumnBriefDto(TableColumn data);
+
     @Mappings({
             @Mapping(target = "id", expression = "java(null)"),
             @Mapping(target = "columnType", source = "data.type"),
@@ -730,41 +766,7 @@ public interface MetadataMapper {
             @Mapping(target = "name", source = "data.name"),
             @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"),
     })
-    TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image);
-
-    default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) {
-        return UpdateCredentialsDto.builder()
-                .credentials(List.of(CredentialDto.builder()
-                        .temporary(false)
-                        .type(CredentialTypeDto.PASSWORD)
-                        .value(password)
-                        .build()))
-                .build();
-    }
-
-    default UserCreateDto signupRequestDtoToUserCreateDto(SignupRequestDto data) {
-        return UserCreateDto.builder()
-                .username(data.getUsername())
-                .email(data.getEmail())
-                .credentials(List.of(CredentialDto.builder()
-                        .type(CredentialTypeDto.PASSWORD)
-                        .temporary(false)
-                        .value(data.getPassword())
-                        .build()))
-                .enabled(true)
-                .build();
-    }
-
-    /* keep */
-    UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data);
-
-    /* keep */
-    @Mappings({
-            @Mapping(target = "id", expression = "java(data.getId().toString())")
-    })
-    UserDetailsDto userDtoToUserDetailsDto(UserDto data);
-
-    User userDtoToUser(at.tuwien.api.keycloak.UserDto data);
+    TableColumn columnCreateDtoToTableColumn(CreateTableColumnDto data, ContainerImage image);
 
     /* keep */
     @Mappings({
@@ -773,8 +775,6 @@ public interface MetadataMapper {
     })
     UserBriefDto userToUserBriefDto(User data);
 
-    UserBriefDto userDtoToUserBriefDto(UserDto data);
-
     /* keep */
     @Mappings({
             @Mapping(target = "attributes.language", source = "language"),
@@ -787,9 +787,6 @@ public interface MetadataMapper {
     })
     UserDto userToUserDto(User data);
 
-    /* keep */
-    User userDtoToUserDto(UserDto data);
-
     /* keep */
     @Named("userToFullName")
     default String userToFullName(User data) {
@@ -822,6 +819,10 @@ public interface MetadataMapper {
                 .trim();
     }
 
+    @Mappings({
+            @Mapping(target = "database.views", ignore = true),
+            @Mapping(target = "database.tables", ignore = true)
+    })
     ViewDto viewToViewDto(View data);
 
     @Mappings({
@@ -831,6 +832,9 @@ public interface MetadataMapper {
 
     ViewBriefDto viewToViewBriefDto(View data);
 
+    @Mappings({
+            @Mapping(target = "database", ignore = true)
+    })
     View viewDtoToView(ViewDto data);
 
     /* keep */
@@ -852,60 +856,7 @@ public interface MetadataMapper {
 
     LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data);
 
-    default DatabaseDto customDatabaseToDatabaseDto(Database data) {
-        if (data == null) {
-            return null;
-        }
-        final DatabaseDto database = DatabaseDto.builder()
-                .id(data.getId())
-                .name(data.getName())
-                .internalName(data.getInternalName())
-                .description(data.getDescription())
-                .exchangeName(data.getExchangeName())
-                .previewImage(data.getImage() != null ? "/api/database/" + data.getId() + "/image" : null)
-                .isPublic(data.getIsPublic())
-                .isSchemaPublic(data.getIsSchemaPublic())
-                .container(containerToContainerBriefDto(data.getContainer()))
-                .owner(userToUserBriefDto(data.getOwner()))
-                .contact(userToUserBriefDto(data.getContact()))
-                .subsets(new LinkedList<>())
-                .accesses(new LinkedList<>())
-                .tables(new LinkedList<>())
-                .identifiers(new LinkedList<>())
-                .build();
-        if (data.getSubsets() != null) {
-            database.setSubsets(new LinkedList<>(data.getSubsets()
-                    .stream()
-                    .map(this::identifierToIdentifierBriefDto)
-                    .toList()));
-        }
-        if (data.getTables() != null) {
-            database.setTables(new LinkedList<>(data.getTables()
-                    .stream()
-                    .map(this::tableToTableBriefDto)
-                    .toList()));
-        }
-        if (data.getViews() != null) {
-            database.setViews(new LinkedList<>(data.getViews()
-                    .stream()
-                    .map(this::viewToViewBriefDto)
-                    .toList()));
-        }
-        if (data.getAccesses() != null) {
-            database.setAccesses(new LinkedList<>(data.getAccesses()
-                    .stream()
-                    .filter(a -> !a.getUser().getIsInternal())
-                    .map(this::databaseAccessToDatabaseAccessDto)
-                    .toList()));
-        }
-        if (data.getIdentifiers() != null) {
-            database.setIdentifiers(new LinkedList<>(data.getIdentifiers()
-                    .stream()
-                    .map(this::identifierToIdentifierBriefDto)
-                    .toList()));
-        }
-        return database;
-    }
+    DatabaseBriefDto databaseDtoToDatabaseBriefDto(DatabaseDto data);
 
     @Mappings({
             @Mapping(target = "ownerId", source = "owner.id")
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java
index 7415fb422c03882f7f71786b0edf756c7bd58159..30f2f20c1670f550f7463265f1d2d6afde967777 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java
@@ -17,7 +17,5 @@ public interface UserRepository extends JpaRepository<User, UUID> {
 
     boolean existsByUsername(String username);
 
-    boolean existsByEmail(String email);
-
 }
 
diff --git a/dbrepo-metadata-service/rest-service/pom.xml b/dbrepo-metadata-service/rest-service/pom.xml
index 233d2ac4658612ad06bccc5140bad70c08265ec5..ff5966688771f30a93b2ce4d95bc99ab6aa0a83f 100644
--- a/dbrepo-metadata-service/rest-service/pom.xml
+++ b/dbrepo-metadata-service/rest-service/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-rest-service</artifactId>
     <name>dbrepo-metadata-service-rest</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bdb80973176bc7ae5722b932e7f7b1a2a183d45
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java
@@ -0,0 +1,16 @@
+package at.tuwien.config;
+
+import at.tuwien.converters.IdentifierStatusTypeDtoConverter;
+import at.tuwien.converters.IdentifierTypeDtoConverter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.format.FormatterRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+    @Override
+    public void addFormatters(FormatterRegistry registry) {
+        registry.addConverter(new IdentifierStatusTypeDtoConverter());
+        registry.addConverter(new IdentifierTypeDtoConverter());
+    }
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..96e67f63d2bb85bb0aaebd02237a2d8aaa6ecdfa
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java
@@ -0,0 +1,14 @@
+package at.tuwien.converters;
+
+import at.tuwien.api.identifier.IdentifierStatusTypeDto;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IdentifierStatusTypeDtoConverter implements Converter<String, IdentifierStatusTypeDto> {
+
+    @Override
+    public IdentifierStatusTypeDto convert(String source) {
+        return IdentifierStatusTypeDto.valueOf(source.toUpperCase());
+    }
+}
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java
similarity index 79%
rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java
rename to dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java
index b3f52c4377989a1380c6be42b46ce96f1d902163..61e169604fa2cf1e10c464fdb1d1bc310ea7f125 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java
@@ -5,7 +5,7 @@ import org.springframework.core.convert.converter.Converter;
 import org.springframework.stereotype.Component;
 
 @Component
-public class IdentifierTypeConverter implements Converter<String, IdentifierTypeDto> {
+public class IdentifierTypeDtoConverter implements Converter<String, IdentifierTypeDto> {
 
     @Override
     public IdentifierTypeDto convert(String source) {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java
index 4779a6428e33bde6be581921a9d15bd81a25c5b6..7ec1471f4d1f110e9d6eefff902b6190a4dbde5b 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java
@@ -1,10 +1,8 @@
 package at.tuwien.endpoints;
 
+import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.user.UserDetailsDto;
-import at.tuwien.exception.UserNotFoundException;
-import at.tuwien.service.UserService;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.User;
 
 import java.security.Principal;
 import java.util.UUID;
@@ -45,4 +43,11 @@ public abstract class AbstractEndpoint {
         throw new IllegalArgumentException("Unknown principal instance: " + authentication.getPrincipal().getClass());
     }
 
+    public void removeInternalData(ContainerDto container) {
+        container.setPassword(null);
+        container.setUsername(null);
+        container.setHost(null);
+        container.setPort(null);
+    }
+
 }
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
index f184ffc3372ac10e35f2d6686b0c79e2ecaca818..9c109c87d68664793b3033d7be123d71a7b02d69 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.DatabaseAccessDto;
-import at.tuwien.api.database.UpdateDatabaseAccessDto;
+import at.tuwien.api.database.CreateAccessDto;
 import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
@@ -91,7 +91,7 @@ public class AccessEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<DatabaseAccessDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
                                                     @PathVariable("userId") UUID userId,
-                                                    @Valid @RequestBody UpdateDatabaseAccessDto data,
+                                                    @Valid @RequestBody CreateAccessDto data,
                                                     @NotNull Principal principal) throws NotAllowedException, DataServiceException,
             DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
@@ -153,7 +153,7 @@ public class AccessEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId,
                                        @PathVariable("userId") UUID userId,
-                                       @Valid @RequestBody UpdateDatabaseAccessDto data,
+                                       @Valid @RequestBody CreateAccessDto data,
                                        @NotNull Principal principal) throws NotAllowedException,
             DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
             AccessNotFoundException, SearchServiceException, SearchServiceConnectionException {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index 3c506cfd0a910d10bba6401eebe5467d1c97e738..b5d153318cc9688d13784a80df41c6f28a862de3 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.container.ContainerBriefDto;
-import at.tuwien.api.container.ContainerCreateDto;
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.entities.container.Container;
@@ -105,7 +105,7 @@ public class ContainerEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<ContainerDto> create(@Valid @RequestBody ContainerCreateDto data)
+    public ResponseEntity<ContainerDto> create(@Valid @RequestBody CreateContainerDto data)
             throws ImageNotFoundException, ContainerAlreadyExistsException {
         log.debug("endpoint create container, data={}", data);
         return ResponseEntity.status(HttpStatus.CREATED)
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index ad72fb0756f20fac58bc717c0da601f9b5bb1c74..50016103d83ccfffab65ddc153e6b88074e34e2c 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -5,8 +5,6 @@ import at.tuwien.api.error.ApiErrorDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
-import at.tuwien.entities.database.View;
-import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.MetadataMapper;
@@ -73,7 +71,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             @Header(name = "Access-Control-Expose-Headers", description = "Expose `X-Count` custom header", schema = @Schema(implementation = String.class), required = true)},
                     content = {@Content(
                             mediaType = "application/json",
-                            array = @ArraySchema(schema = @Schema(implementation = DatabaseDto.class)))}),
+                            array = @ArraySchema(schema = @Schema(implementation = DatabaseBriefDto.class)))}),
     })
     public ResponseEntity<List<DatabaseBriefDto>> list(@RequestParam(name = "internal_name", required = false) String internalName,
                                                        Principal principal) {
@@ -118,7 +116,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     description = "Created a new database",
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "400",
                     description = "Database create query is malformed or image is not supported",
                     content = {@Content(
@@ -155,8 +153,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<DatabaseDto> create(@Valid @RequestBody DatabaseCreateDto data,
-                                              @NotNull Principal principal) throws DataServiceException,
+    public ResponseEntity<DatabaseBriefDto> create(@Valid @RequestBody CreateDatabaseDto data,
+                                                   @NotNull Principal principal) throws DataServiceException,
             DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
             ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException,
             ContainerQuotaException {
@@ -168,8 +166,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
         }
         final User caller = userService.findById(getId(principal));
         return ResponseEntity.status(HttpStatus.CREATED)
-                .body(databaseMapper.customDatabaseToDatabaseDto(
-                        databaseService.create(container, data, caller, userService.findAllInternalUsers())));
+                .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto(
+                        databaseService.create(container, data, caller, userService.findAllInternalUsers()))));
     }
 
     @PutMapping("/{databaseId}/metadata/table")
@@ -184,7 +182,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     description = "Refreshed database tables metadata",
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "400",
                     description = "Failed to parse payload at search service",
                     content = {@Content(
@@ -196,7 +194,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
             @ApiResponse(responseCode = "404",
-                    description = "Failed to fin user/database in metadata database",
+                    description = "Failed to find database in metadata database",
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
@@ -211,9 +209,9 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<DatabaseDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                            @NotNull Principal principal) throws DataServiceException,
-            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, UserNotFoundException,
+    public ResponseEntity<DatabaseBriefDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                                 @NotNull Principal principal) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, MalformedException,
             TableNotFoundException {
         log.debug("endpoint refresh database metadata, databaseId={}", databaseId);
@@ -222,8 +220,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             log.error("Failed to refresh database tables metadata: not owner");
             throw new NotAllowedException("Failed to refresh tables metadata: not owner");
         }
-        return ResponseEntity.ok(databaseMapper.customDatabaseToDatabaseDto(
-                databaseService.updateTableMetadata(database)));
+        return ResponseEntity.ok(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto(
+                databaseService.updateTableMetadata(database))));
     }
 
     @PutMapping("/{databaseId}/metadata/view")
@@ -238,7 +236,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     description = "Refreshed database views metadata",
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "403",
                     description = "Refresh view metadata is not permitted",
                     content = {@Content(
@@ -260,9 +258,9 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<DatabaseDto> refreshViewMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                           @NotNull Principal principal) throws DataServiceException,
-            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, UserNotFoundException,
+    public ResponseEntity<DatabaseBriefDto> refreshViewMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                                @NotNull Principal principal) throws DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, ViewNotFoundException {
         log.debug("endpoint refresh database metadata, databaseId={}, principal.name={}", databaseId, principal.getName());
         final Database database = databaseService.findById(databaseId);
@@ -270,8 +268,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             log.error("Failed to refresh database views metadata: not owner");
             throw new NotAllowedException("Failed to refresh database views metadata: not owner");
         }
-        return ResponseEntity.ok(databaseMapper.customDatabaseToDatabaseDto(
-                databaseService.updateViewMetadata(database)));
+        return ResponseEntity.ok(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto(
+                databaseService.updateViewMetadata(database))));
     }
 
     @PutMapping("/{databaseId}/visibility")
@@ -286,7 +284,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     description = "Visibility modified successfully",
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "400",
                     description = "The visibility payload is malformed",
                     content = {@Content(
@@ -313,9 +311,9 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<DatabaseDto> visibility(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                  @Valid @RequestBody DatabaseModifyVisibilityDto data,
-                                                  @NotNull Principal principal) throws DatabaseNotFoundException,
+    public ResponseEntity<DatabaseBriefDto> visibility(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                       @Valid @RequestBody DatabaseModifyVisibilityDto data,
+                                                       @NotNull Principal principal) throws DatabaseNotFoundException,
             NotAllowedException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException {
         log.debug("endpoint modify database visibility, databaseId={}, data={}", databaseId, data);
         final Database database = databaseService.findById(databaseId);
@@ -324,8 +322,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Failed to modify database visibility: not owner");
         }
         return ResponseEntity.accepted()
-                .body(databaseMapper.customDatabaseToDatabaseDto(
-                        databaseService.modifyVisibility(database, data)));
+                .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto(
+                        databaseService.modifyVisibility(database, data))));
     }
 
     @PutMapping("/{databaseId}/owner")
@@ -340,7 +338,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     description = "Transfer of ownership was successful",
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "400",
                     description = "Owner payload is malformed",
                     content = {@Content(
@@ -367,9 +365,9 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<DatabaseDto> transfer(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                @Valid @RequestBody DatabaseTransferDto data,
-                                                @NotNull Principal principal) throws NotAllowedException,
+    public ResponseEntity<DatabaseBriefDto> transfer(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                     @Valid @RequestBody DatabaseTransferDto data,
+                                                     @NotNull Principal principal) throws NotAllowedException,
             DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint transfer database, databaseId={}, transferDto.id={}", databaseId, data.getId());
@@ -380,8 +378,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Failed to transfer database: not owner");
         }
         return ResponseEntity.accepted()
-                .body(databaseMapper.customDatabaseToDatabaseDto(
-                        databaseService.modifyOwner(database, newOwner)));
+                .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto(
+                        databaseService.modifyOwner(database, newOwner))));
     }
 
     @PutMapping("/{databaseId}/image")
@@ -396,7 +394,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     description = "Modify of image was successful",
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "403",
                     description = "Modify of image is not permitted",
                     content = {@Content(
@@ -423,9 +421,9 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<DatabaseDto> modifyImage(@NotNull @PathVariable("databaseId") Long databaseId,
-                                                   @Valid @RequestBody DatabaseModifyImageDto data,
-                                                   @NotNull Principal principal) throws NotAllowedException,
+    public ResponseEntity<DatabaseBriefDto> modifyImage(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                        @Valid @RequestBody DatabaseModifyImageDto data,
+                                                        @NotNull Principal principal) throws NotAllowedException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException,
             StorageUnavailableException, StorageNotFoundException {
         log.debug("endpoint modify database image, databaseId={}, data.key={}", databaseId, data.getKey());
@@ -439,8 +437,8 @@ public class DatabaseEndpoint extends AbstractEndpoint {
             image = storageService.getBytes(data.getKey());
         }
         return ResponseEntity.accepted()
-                .body(databaseMapper.customDatabaseToDatabaseDto(
-                        databaseService.modifyImage(database, image)));
+                .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto(
+                        databaseService.modifyImage(database, image))));
     }
 
     @GetMapping("/{databaseId}/image")
@@ -480,7 +478,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             @Header(name = "Access-Control-Expose-Headers", description = "Expose custom headers", schema = @Schema(implementation = String.class))},
                     content = {@Content(
                             mediaType = "application/json",
-                            schema = @Schema(implementation = DatabaseDto.class))}),
+                            schema = @Schema(implementation = DatabaseBriefDto.class))}),
             @ApiResponse(responseCode = "403",
                     description = "Not allowed to view database",
                     content = {@Content(
@@ -515,7 +513,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     .findFirst();
             if (!database.getIsPublic() && !database.getIsSchemaPublic() && optional.isEmpty() && !isSystem(principal)) {
                 log.error("Failed to find database: not public and no access found");
-                throw new DatabaseNotFoundException("Failed to find database: not public and no access found");
+                throw new NotAllowedException("Failed to find database: not public and no access found");
             }
             /* reduce metadata */
             database.setTables(database.getTables()
@@ -536,24 +534,26 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                 throw new NotAllowedException("Failed to find database: not public and not authenticated");
             }
             /* reduce metadata */
-            database.setTables(database.getTables()
-                    .stream()
-                    .filter(t -> t.getIsPublic() || t.getIsSchemaPublic())
-                    .toList());
-            database.setViews(database.getViews()
-                    .stream()
-                    .filter(v -> v.getIsPublic() || v.getIsSchemaPublic())
-                    .toList());
+            database.getTables()
+                    .removeAll(database.getTables()
+                            .stream()
+                            .filter(t -> !t.getIsPublic() && !t.getIsSchemaPublic())
+                            .toList());
+            database.getViews()
+                    .removeAll(database.getViews()
+                            .stream()
+                            .filter(v -> !v.getIsPublic() && !v.getIsSchemaPublic())
+                            .toList());
             database.setAccesses(List.of());
         }
-        final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database);
+        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
         final HttpHeaders headers = new HttpHeaders();
         if (isSystem(principal)) {
             headers.set("X-Username", database.getContainer().getPrivilegedUsername());
             headers.set("X-Password", database.getContainer().getPrivilegedPassword());
-            headers.set("X-Host", database.getContainer().getHost());
-            headers.set("X-Port", "" + database.getContainer().getPort());
-            headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port");
+            headers.set("Access-Control-Expose-Headers", "X-Username X-Password");
+        } else {
+            removeInternalData(dto.getContainer());
         }
         return ResponseEntity.status(HttpStatus.OK)
                 .headers(headers)
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
index 2830f9714a62cb7fea0b0cf616b4bd54eff8d340..b3d699086ee93b943801a3139a2e2488dc9dcc8c 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
@@ -73,7 +73,7 @@ public class IdentifierEndpoint extends AbstractEndpoint {
         this.identifierService = identifierService;
     }
 
-    @GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json"})
+    @GetMapping
     @Transactional(readOnly = true)
     @Observed(name = "dbrepo_identifier_list")
     @Operation(summary = "List identifiers",
@@ -87,48 +87,41 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                             @Content(mediaType = "application/ld+json",
                                     array = @ArraySchema(schema = @Schema(implementation = LdDatasetDto.class)))
                     }),
-            @ApiResponse(responseCode = "406",
-                    description = "Identifier could not be exported, the requested style is not known",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<?> findAll(@Valid @RequestParam(value = "dbid", required = false) Long dbid,
+    public ResponseEntity<?> findAll(@Valid @RequestParam(value = "type", required = false) IdentifierTypeDto type,
+                                     @Valid @RequestParam(value = "status", required = false) IdentifierStatusTypeDto status,
+                                     @Valid @RequestParam(value = "dbid", required = false) Long dbid,
                                      @Valid @RequestParam(value = "qid", required = false) Long qid,
                                      @Valid @RequestParam(value = "vid", required = false) Long vid,
                                      @Valid @RequestParam(value = "tid", required = false) Long tid,
-                                     @RequestHeader(HttpHeaders.ACCEPT) String accept)
-            throws FormatNotAvailableException {
-        log.debug("endpoint find identifiers, dbid={}, qid={}, vid={}, tid={}, accept={}", dbid, qid, vid, tid, accept);
+                                     @RequestHeader(HttpHeaders.ACCEPT) String accept,
+                                     Principal principal) {
+        log.debug("endpoint find identifiers, type={}, status={}, dbid={}, qid={}, vid={}, tid={}, accept={}", type,
+                status, dbid, qid, vid, tid, accept);
         final List<Identifier> identifiers = identifierService.findAll()
                 .stream()
+                .filter(i -> !Objects.nonNull(type) || metadataMapper.identifierTypeDtoToIdentifierType(type).equals(i.getType()))
+                .filter(i -> !Objects.nonNull(status) || metadataMapper.identifierStatusTypeDtoToIdentifierStatusType(status).equals(i.getStatus()))
                 .filter(i -> !Objects.nonNull(dbid) || dbid.equals(i.getDatabase().getId()))
                 .filter(i -> !Objects.nonNull(qid) || qid.equals(i.getQueryId()))
                 .filter(i -> !Objects.nonNull(vid) || vid.equals(i.getViewId()))
                 .filter(i -> !Objects.nonNull(tid) || tid.equals(i.getTableId()))
+                .filter(i -> principal != null && i.getStatus().equals(IdentifierStatusType.DRAFT) ? i.getOwnedBy().equals(getId(principal)) : i.getStatus().equals(IdentifierStatusType.PUBLISHED))
                 .toList();
         if (identifiers.isEmpty()) {
             return ResponseEntity.ok(List.of());
         }
         log.trace("found persistent identifiers {}", identifiers);
-        return switch (accept) {
-            case "application/json" -> {
-                log.trace("accept header matches json");
-                yield ResponseEntity.ok(identifiers.stream()
-                        .map(metadataMapper::identifierToIdentifierBriefDto)
-                        .toList());
-            }
-            case "application/ld+json" -> {
-                log.trace("accept header matches json-ld");
-                yield ResponseEntity.ok(identifiers.stream()
-                        .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
-                        .toList());
-            }
-            default -> {
-                log.error("accept header {} is not supported", accept);
-                throw new FormatNotAvailableException("Must provide either application/json or application/ld+json headers");
-            }
-        };
+        if (accept.equals("application/ld+json")) {
+            log.trace("accept header matches json-ld");
+            return ResponseEntity.ok(identifiers.stream()
+                    .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
+                    .toList());
+        }
+        log.trace("default to json");
+        return ResponseEntity.ok(identifiers.stream()
+                .map(metadataMapper::identifierToIdentifierBriefDto)
+                .toList());
     }
 
     @GetMapping(value = "/{identifierId}", produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json",
@@ -156,6 +149,11 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "403",
+                    description = "Not allowed to view identifier",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
             @ApiResponse(responseCode = "404",
                     description = "Identifier could not be found",
                     content = {@Content(
@@ -188,14 +186,23 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<?> find(@Valid @PathVariable("identifierId") Long identifierId,
-                                  @RequestHeader(HttpHeaders.ACCEPT) String accept) throws IdentifierNotFoundException,
+                                  @RequestHeader(HttpHeaders.ACCEPT) String accept,
+                                  Principal principal) throws IdentifierNotFoundException,
             DataServiceException, DataServiceConnectionException, MalformedException, FormatNotAvailableException,
-            QueryNotFoundException {
+            QueryNotFoundException, NotAllowedException {
         log.debug("endpoint find identifier, identifierId={}, accept={}", identifierId, accept);
         if (accept == null) {
             accept = "";
         }
         final Identifier identifier = identifierService.find(identifierId);
+        if (identifier.getStatus().equals(IdentifierStatusType.DRAFT)) {
+            if (principal == null) {
+                throw new NotAllowedException("Draft identifier: authentication required");
+            }
+            if (!identifier.getOwnedBy().equals(getId(principal))) {
+                throw new NotAllowedException("Draft identifier: not authorized");
+            }
+        }
         log.info("Found persistent identifier with id: {}", identifier.getId());
         switch (accept) {
             case "application/json":
@@ -475,7 +482,7 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<IdentifierDto> create(@NotNull @Valid @RequestBody IdentifierCreateDto data,
+    public ResponseEntity<IdentifierDto> create(@NotNull @Valid @RequestBody CreateIdentifierDto data,
                                                 @NotNull Principal principal) throws DatabaseNotFoundException,
             UserNotFoundException, NotAllowedException, MalformedException, DataServiceConnectionException,
             SearchServiceException, DataServiceException, QueryNotFoundException, SearchServiceConnectionException,
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
index 9f4542fc023f8aaf336fc2de196d0c36ab93cea4..08535fde69a20f162ea3d4478110d9360db55f99 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TableUpdateDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
@@ -358,9 +358,9 @@ public class TableEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
-                                           @NotNull @Valid @RequestBody TableCreateDto data,
-                                           @NotNull Principal principal) throws NotAllowedException, MalformedException,
+    public ResponseEntity<TableBriefDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                @NotNull @Valid @RequestBody CreateTableDto data,
+                                                @NotNull Principal principal) throws NotAllowedException, MalformedException,
             DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException,
             AccessNotFoundException, TableNotFoundException, TableExistsException, SearchServiceException,
             SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
@@ -370,7 +370,7 @@ public class TableEndpoint extends AbstractEndpoint {
         endpointValidator.validateOnlyAccess(database, principal, true);
         endpointValidator.validateColumnCreateConstraints(data);
         return ResponseEntity.status(HttpStatus.CREATED)
-                .body(metadataMapper.customTableToTableDto(
+                .body(metadataMapper.tableToTableBriefDto(
                         tableService.createTable(database, data, principal)));
     }
 
@@ -413,10 +413,10 @@ public class TableEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<TableDto> update(@NotNull @PathVariable("databaseId") Long databaseId,
-                                           @NotNull @PathVariable("tableId") Long tableId,
-                                           @NotNull @Valid @RequestBody TableUpdateDto data,
-                                           @NotNull Principal principal) throws NotAllowedException,
+    public ResponseEntity<TableBriefDto> update(@NotNull @PathVariable("databaseId") Long databaseId,
+                                                @NotNull @PathVariable("tableId") Long tableId,
+                                                @NotNull @Valid @RequestBody TableUpdateDto data,
+                                                @NotNull Principal principal) throws NotAllowedException,
             DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, TableNotFoundException,
             SearchServiceException, SearchServiceConnectionException {
         log.debug("endpoint update table, databaseId={}, data.is_public={}, data.is_schema_public={}, principal.name={}",
@@ -428,7 +428,7 @@ public class TableEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Failed to update table: not owner");
         }
         return ResponseEntity.accepted()
-                .body(metadataMapper.customTableToTableDto(
+                .body(metadataMapper.tableToTableBriefDto(
                         tableService.updateTable(table, data)));
     }
 
@@ -443,11 +443,6 @@ public class TableEndpoint extends AbstractEndpoint {
                     description = "Find table successfully",
                     headers = {@Header(name = "X-Username", description = "The authentication username", schema = @Schema(implementation = String.class)),
                             @Header(name = "X-Password", description = "The authentication password", schema = @Schema(implementation = String.class)),
-                            @Header(name = "X-Host", description = "The database hostname", schema = @Schema(implementation = String.class)),
-                            @Header(name = "X-Port", description = "The database port number", schema = @Schema(implementation = Integer.class)),
-                            @Header(name = "X-Type", description = "The JDBC connection type", schema = @Schema(implementation = String.class)),
-                            @Header(name = "X-Database", description = "The database internal name", schema = @Schema(implementation = String.class)),
-                            @Header(name = "X-Table", description = "The table internal name", schema = @Schema(implementation = String.class)),
                             @Header(name = "Access-Control-Expose-Headers", description = "Expose custom headers", schema = @Schema(implementation = String.class))},
                     content = {@Content(
                             mediaType = "application/json",
@@ -500,20 +495,18 @@ public class TableEndpoint extends AbstractEndpoint {
             table.setColumns(List.of());
             table.setConstraints(null);
         }
+        final TableDto dto = metadataMapper.tableToTableDto(table);
         final HttpHeaders headers = new HttpHeaders();
         if (isSystem(principal)) {
             headers.set("X-Username", table.getDatabase().getContainer().getPrivilegedUsername());
             headers.set("X-Password", table.getDatabase().getContainer().getPrivilegedPassword());
-            headers.set("X-Host", table.getDatabase().getContainer().getHost());
-            headers.set("X-Port", "" + table.getDatabase().getContainer().getPort());
-            headers.set("X-Type", table.getDatabase().getContainer().getImage().getJdbcMethod());
-            headers.set("X-Database", table.getDatabase().getInternalName());
-            headers.set("X-Table", table.getInternalName());
-            headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table");
+            headers.set("Access-Control-Expose-Headers", "X-Username X-Password");
+        } else {
+            removeInternalData(dto.getDatabase().getContainer());
         }
         return ResponseEntity.ok()
                 .headers(headers)
-                .body(metadataMapper.customTableToTableDto(table));
+                .body(dto);
     }
 
     @DeleteMapping("/{tableId}")
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
index 5a349ff3782f1c94a4aea6f4d609f3402437b9c0..51f323c30f1581314df88dab86ec2900775c215e 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
@@ -1,10 +1,7 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.RefreshTokenRequestDto;
-import at.tuwien.api.auth.SignupRequestDto;
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.error.ApiErrorDto;
-import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
@@ -95,10 +92,11 @@ public class UserEndpoint extends AbstractEndpoint {
 
     @PostMapping
     @Transactional(rollbackFor = {Exception.class})
-    @PreAuthorize("!isAuthenticated()")
+    @PreAuthorize("hasAuthority('system')")
     @Observed(name = "dbrepo_user_create")
     @Operation(summary = "Create user",
-            description = "Creates a user in the auth service and metadata database. Requires that no credentials are sent in the request.")
+            description = "This webhook is called from the auth service to add a user to the metadata database. Requires role `system`.",
+            hidden = true)
     @ApiResponses(value = {
             @ApiResponse(responseCode = "201",
                     description = "Created user",
@@ -139,117 +137,13 @@ public class UserEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<UserDto> create(@NotNull @Valid @RequestBody SignupRequestDto data)
+    public ResponseEntity<UserBriefDto> create(@NotNull @Valid @RequestBody CreateUserDto data)
             throws UserExistsException, EmailExistsException, AuthServiceException, AuthServiceConnectionException,
             UserNotFoundException, CredentialsInvalidException {
-        log.debug("endpoint create user, data.username={}", data.getUsername());
-        userService.validateUsernameNotExists(data.getUsername());
-        userService.validateEmailNotExists(data.getEmail());
+        log.debug("endpoint create user, data.id={}, data.username={}", data.getId(), data.getUsername());
         return ResponseEntity.status(HttpStatus.CREATED)
-                .body(userMapper.userToUserDto(
-                        userService.create(data, authenticationService.create(data).getAttributes().getLdapId()[0])));
-    }
-
-    @PostMapping("/token")
-    @Observed(name = "dbrepo_user_token")
-    @Operation(summary = "Create token",
-            description = "Creates a user token via the Auth Service.")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "202",
-                    description = "Obtained user token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = TokenDto.class))}),
-            @ApiResponse(responseCode = "400",
-                    description = "Invalid login request",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "403",
-                    description = "Not allowed to get token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "404",
-                    description = "Failed to find user in auth database",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "428",
-                    description = "Account is not fully setup in auth service (requires password change?)",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "502",
-                    description = "Connection to auth service failed",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "503",
-                    description = "Failed to get user in auth service",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-    })
-    public ResponseEntity<TokenDto> getToken(@NotNull @Valid @RequestBody LoginRequestDto data)
-            throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException,
-            AccountNotSetupException {
-        log.debug("endpoint get token, data.username={}", data.getUsername());
-        /* check */
-        try {
-            userService.findByUsername(data.getUsername());
-        } catch (UserNotFoundException e) {
-            /* need to sync */
-            log.warn("User with username {} does not exist in metadata database yet", data.getUsername());
-            final SignupRequestDto request = SignupRequestDto.builder()
-                    .username(data.getUsername())
-                    .email("noreply@example.com")
-                    .password(data.getPassword())
-                    .build();
-            final at.tuwien.api.keycloak.UserDto user = authenticationService.findByUsername(data.getUsername());
-            if (user.getAttributes().getLdapId() == null || user.getAttributes().getLdapId().length != 1) {
-                log.error("Failed to map ldap id for user with username: {}", data.getUsername());
-                throw new UserNotFoundException("Failed to map ldap id");
-            }
-            userService.create(request, user.getAttributes().getLdapId()[0]);
-            log.info("Patched missing user information for user with username: {}", data.getUsername());
-        }
-        return ResponseEntity.accepted()
-                .body(authenticationService.obtainToken(data));
-    }
-
-    @PutMapping("/token")
-    @Observed(name = "dbrepo_user_refresh_token")
-    @Operation(summary = "Refresh token",
-            description = "Refreshes user token by refresh token.")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "202",
-                    description = "Refreshed user token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = TokenDto.class))}),
-            @ApiResponse(responseCode = "400",
-                    description = "Invalid refresh token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "403",
-                    description = "Not allowed",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "502",
-                    description = "Connection to auth service failed",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-    })
-    public ResponseEntity<TokenDto> refreshToken(@NotNull @Valid @RequestBody RefreshTokenRequestDto data)
-            throws AuthServiceConnectionException, CredentialsInvalidException {
-        log.debug("endpoint refresh token");
-        /* check */
-        return ResponseEntity.accepted()
-                .body(authenticationService.refreshToken(data.getRefreshToken()));
+                .body(userMapper.userToUserBriefDto(
+                        userService.create(data)));
     }
 
     @GetMapping("/{userId}")
@@ -327,11 +221,16 @@ public class UserEndpoint extends AbstractEndpoint {
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "503",
+                    description = "Failed to modify user at auth service",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<UserDto> modify(@NotNull @PathVariable("userId") UUID userId,
-                                          @NotNull @Valid @RequestBody UserUpdateDto data,
-                                          @NotNull Principal principal) throws NotAllowedException,
-            UserNotFoundException, DatabaseNotFoundException {
+    public ResponseEntity<UserBriefDto> modify(@NotNull @PathVariable("userId") UUID userId,
+                                               @NotNull @Valid @RequestBody UserUpdateDto data,
+                                               @NotNull Principal principal) throws NotAllowedException,
+            UserNotFoundException, AuthServiceException {
         log.debug("endpoint modify a user, userId={}, data={}", userId, data);
         final User user = userService.findById(userId);
         if (!user.getId().equals(getId(principal))) {
@@ -339,7 +238,7 @@ public class UserEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Failed to modify user: not current user " + user.getId());
         }
         return ResponseEntity.accepted()
-                .body(userMapper.userToUserDto(
+                .body(userMapper.userToUserBriefDto(
                         userService.modify(user, data)));
     }
 
@@ -381,9 +280,9 @@ public class UserEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<Void> password(@NotNull @PathVariable("userId") UUID userId,
                                          @NotNull @Valid @RequestBody UserPasswordDto data,
-                                         @NotNull Principal principal) throws NotAllowedException, AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, DataServiceException,
-            DataServiceConnectionException, CredentialsInvalidException {
+                                         @NotNull Principal principal) throws NotAllowedException,
+            UserNotFoundException, DatabaseNotFoundException, DataServiceException,
+            DataServiceConnectionException {
         log.debug("endpoint modify a user password, userId={}, principal.name={}", userId, principal.getName());
         final User user = userService.findById(userId);
         if (!user.getUsername().equals(principal.getName())) {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
index 8a4a087da20e4578a40801ac670a7ed5a3826521..e8b40de8b2bfa05f9901a01ce0e269fbbffefe41 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.ViewBriefDto;
-import at.tuwien.api.database.ViewCreateDto;
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.database.ViewUpdateDto;
 import at.tuwien.api.error.ApiErrorDto;
@@ -137,7 +137,7 @@ public class ViewEndpoint extends AbstractEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<ViewBriefDto> create(@NotNull @PathVariable("databaseId") Long databaseId,
-                                               @NotNull @Valid @RequestBody ViewCreateDto data,
+                                               @NotNull @Valid @RequestBody CreateViewDto data,
                                                @NotNull Principal principal) throws NotAllowedException,
             MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
             UserNotFoundException, SearchServiceException, SearchServiceConnectionException {
@@ -202,9 +202,13 @@ public class ViewEndpoint extends AbstractEndpoint {
             headers.set("X-View", view.getInternalName());
             headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-View");
         }
+        final ViewDto dto = metadataMapper.viewToViewDto(view);
+        if (!isSystem(principal)) {
+            removeInternalData(dto.getDatabase().getContainer());
+        }
         return ResponseEntity.status(HttpStatus.OK)
                 .headers(headers)
-                .body(metadataMapper.viewToViewDto(view));
+                .body(dto);
     }
 
     @DeleteMapping("/{viewId}")
@@ -248,9 +252,9 @@ public class ViewEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<?> delete(@NotNull @PathVariable("databaseId") Long databaseId,
-                                    @NotNull @PathVariable("viewId") Long viewId,
-                                    @NotNull Principal principal) throws NotAllowedException, DataServiceException,
+    public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") Long databaseId,
+                                       @NotNull @PathVariable("viewId") Long viewId,
+                                       @NotNull Principal principal) throws NotAllowedException, DataServiceException,
             DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException,
             SearchServiceConnectionException, UserNotFoundException {
         log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId);
@@ -301,10 +305,10 @@ public class ViewEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<ViewDto> update(@NotNull @PathVariable("databaseId") Long databaseId,
-                                          @NotNull @PathVariable("viewId") Long viewId,
-                                          @NotNull @Valid @RequestBody ViewUpdateDto data,
-                                          @NotNull Principal principal) throws NotAllowedException,
+    public ResponseEntity<ViewBriefDto> update(@NotNull @PathVariable("databaseId") Long databaseId,
+                                               @NotNull @PathVariable("viewId") Long viewId,
+                                               @NotNull @Valid @RequestBody ViewUpdateDto data,
+                                               @NotNull Principal principal) throws NotAllowedException,
             DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException,
             SearchServiceConnectionException, UserNotFoundException {
         log.debug("endpoint update view, databaseId={}, viewId={}", databaseId, viewId);
@@ -315,7 +319,7 @@ public class ViewEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Failed to update view: not the database- or view owner");
         }
         return ResponseEntity.accepted()
-                .body(metadataMapper.viewToViewDto(
+                .body(metadataMapper.viewToViewBriefDto(
                         viewService.update(database, view, data)));
     }
 
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
index 1f7c391bd2ef63d49ed1acd5255409a1564af0ca..a54f616b01e61edad50d85d4b5f0d494c9e429d6 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
@@ -1,9 +1,9 @@
 package at.tuwien.validation;
 
 import at.tuwien.SortType;
-import at.tuwien.api.database.table.TableCreateDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.endpoints.AbstractEndpoint;
 import at.tuwien.entities.database.AccessType;
@@ -43,15 +43,6 @@ public class EndpointValidator extends AbstractEndpoint {
         this.accessService = accessService;
     }
 
-    public void validateOnlyPrivateDataAccess(Database database, Principal principal, boolean writeAccessOnly)
-            throws NotAllowedException, UserNotFoundException, AccessNotFoundException {
-        if (database.getIsPublic()) {
-            log.trace("database with id {} is public: no access needed", database.getId());
-            return;
-        }
-        validateOnlyAccess(database, principal, writeAccessOnly);
-    }
-
     public void validateOnlyPrivateSchemaAccess(Database database, Principal principal, boolean writeAccessOnly)
             throws NotAllowedException, UserNotFoundException, AccessNotFoundException {
         if (database.getIsSchemaPublic()) {
@@ -61,11 +52,6 @@ public class EndpointValidator extends AbstractEndpoint {
         validateOnlyAccess(database, principal, writeAccessOnly);
     }
 
-    public void validateOnlyPrivateDataAccess(Database database, Principal principal) throws NotAllowedException,
-            UserNotFoundException, AccessNotFoundException {
-        validateOnlyPrivateDataAccess(database, principal, false);
-    }
-
     public void validateOnlyPrivateSchemaAccess(Database database, Principal principal) throws NotAllowedException,
             UserNotFoundException, AccessNotFoundException {
         validateOnlyPrivateSchemaAccess(database, principal, false);
@@ -87,12 +73,12 @@ public class EndpointValidator extends AbstractEndpoint {
         }
     }
 
-    public void validateColumnCreateConstraints(TableCreateDto data) throws MalformedException {
+    public void validateColumnCreateConstraints(CreateTableDto data) throws MalformedException {
         if (data == null) {
             throw new MalformedException("Validation failed: table data is null");
         }
         /* check size */
-        final Optional<ColumnCreateDto> optional0 = data.getColumns()
+        final Optional<CreateTableColumnDto> optional0 = data.getColumns()
                 .stream()
                 .filter(c -> Objects.isNull(c.getSize()))
                 .filter(c -> NEED_SIZE.contains(c.getType()))
@@ -101,7 +87,7 @@ public class EndpointValidator extends AbstractEndpoint {
             log.error("Validation failed: column {} need size parameter", optional0.get().getName());
             throw new MalformedException("Validation failed: column " + optional0.get().getName() + " need size parameter");
         }
-        final Optional<ColumnCreateDto> optional0a = data.getColumns()
+        final Optional<CreateTableColumnDto> optional0a = data.getColumns()
                 .stream()
                 .filter(c -> !Objects.isNull(c.getSize()))
                 .filter(c -> CAN_HAVE_SIZE.contains(c.getType()) || CAN_HAVE_SIZE_AND_D.contains(c.getType()))
@@ -111,7 +97,7 @@ public class EndpointValidator extends AbstractEndpoint {
             log.error("Validation failed: column {} needs positive size parameter", optional0a.get().getName());
             throw new MalformedException("Validation failed: column " + optional0a.get().getName() + " needs positive size parameter");
         }
-        final Optional<ColumnCreateDto> optional0b = data.getColumns()
+        final Optional<CreateTableColumnDto> optional0b = data.getColumns()
                 .stream()
                 .filter(c -> !Objects.isNull(c.getD()))
                 .filter(c -> CAN_HAVE_SIZE_AND_D.contains(c.getType()))
@@ -122,7 +108,7 @@ public class EndpointValidator extends AbstractEndpoint {
             throw new MalformedException("Validation failed: column " + optional0b.get().getName() + " needs positive d parameter");
         }
         /* check size and d */
-        final Optional<ColumnCreateDto> optional1 = data.getColumns()
+        final Optional<CreateTableColumnDto> optional1 = data.getColumns()
                 .stream()
                 .filter(c -> Objects.isNull(c.getSize()) ^ Objects.isNull(c.getD()))
                 .filter(c -> CAN_HAVE_SIZE_AND_D.contains(c.getType()))
@@ -132,7 +118,7 @@ public class EndpointValidator extends AbstractEndpoint {
             throw new MalformedException("Validation failed: column " + optional1.get().getName() + " either needs both size and d parameter or none (use default)");
         }
         /* check enum */
-        final Optional<ColumnCreateDto> optional2 = data.getColumns()
+        final Optional<CreateTableColumnDto> optional2 = data.getColumns()
                 .stream()
                 .filter(c -> c.getType().equals(ColumnTypeDto.ENUM))
                 .filter(c -> c.getEnums() == null || c.getEnums().isEmpty())
@@ -142,7 +128,7 @@ public class EndpointValidator extends AbstractEndpoint {
             throw new MalformedException("Validation failed: column " + optional2.get().getName() + " needs at least 1 allowed enum value");
         }
         /* check set */
-        final Optional<ColumnCreateDto> optional3 = data.getColumns()
+        final Optional<CreateTableColumnDto> optional3 = data.getColumns()
                 .stream()
                 .filter(c -> c.getType().equals(ColumnTypeDto.SET))
                 .filter(c -> c.getEnums() == null || c.getSets().isEmpty())
@@ -152,7 +138,7 @@ public class EndpointValidator extends AbstractEndpoint {
             throw new MalformedException("Validation failed: column " + optional3.get().getName() + " needs at least 1 allowed set value");
         }
         /* check serial */
-        final List<ColumnCreateDto> list4a = data.getColumns()
+        final List<CreateTableColumnDto> list4a = data.getColumns()
                 .stream()
                 .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL))
                 .toList();
@@ -160,26 +146,15 @@ public class EndpointValidator extends AbstractEndpoint {
             log.error("Validation failed: only one column of type serial allowed");
             throw new MalformedException("Validation failed: only one column of type serial allowed");
         }
-        final Optional<ColumnCreateDto> optional4a = data.getColumns()
+        final Optional<CreateTableColumnDto> optional4a = data.getColumns()
                 .stream()
                 .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL))
-                .filter(ColumnCreateDto::getNullAllowed)
+                .filter(CreateTableColumnDto::getNullAllowed)
                 .findFirst();
         if (optional4a.isPresent()) {
             log.error("Validation failed: column {} type serial demands non-null", optional4a.get().getName());
             throw new MalformedException("Validation failed: column " + optional4a.get().getName() + " type serial demands non-null");
         }
-        final Optional<ColumnCreateDto> optional4b = data.getColumns()
-                .stream()
-                .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL) && data.getConstraints()
-                        .getUniques()
-                        .stream()
-                        .noneMatch(uk -> uk.size() == 1 && uk.contains(c.getName())))
-                .findFirst();
-        if (optional4b.isPresent()) {
-            log.error("Validation failed: column {} type serial demands a unique constraint", optional4b.get().getName());
-            throw new MalformedException("Validation failed: column " + optional4b.get().getName() + " type serial demands a unique constraint");
-        }
     }
 
     public boolean validateOnlyMineOrWriteAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) {
@@ -204,18 +179,6 @@ public class EndpointValidator extends AbstractEndpoint {
         return false;
     }
 
-    public boolean validateOnlyMineOrReadAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) {
-        if (validateOnlyMineOrWriteAccessOrHasRole(owner, principal, access, role)) {
-            return true;
-        }
-        if (access.getType().equals(AccessType.READ)) {
-            log.debug("validation passed: user {} has read access", principal.getName());
-            return true;
-        }
-        log.debug("validation failed: user {} has insufficient access {} or role", principal.getName(), access.getType());
-        return false;
-    }
-
     @Transactional(readOnly = true)
     public void validateOnlyOwnerOrWriteAll(Table table, User user) throws NotAllowedException,
             AccessNotFoundException {
diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
index 290864eea961100236eea2764297d01251c1ccbc..01d2de7d8a0f73dcc667b69ed499ae350a81d317 100644
--- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
+++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
@@ -3,7 +3,7 @@ application:
   version: '@project.version@'
 spring:
   datasource:
-    url: "jdbc:mariadb://${METADATA_HOST:metadata-db}:${METADATA_PORT:3306}/${METADATA_DB:dbrepo}${METADATA_JDBC_EXTRA_ARGS}"
+    url: "jdbc:mariadb://${METADATA_HOST:localhost}:${METADATA_PORT:3306}/${METADATA_DB:dbrepo}${METADATA_JDBC_EXTRA_ARGS:}"
     driver-class-name: org.mariadb.jdbc.Driver
     username: "${METADATA_USERNAME:root}"
     password: "${METADATA_DB_PASSWORD:dbrepo}"
@@ -18,7 +18,7 @@ spring:
   application:
     name: metadata-service
   rabbitmq:
-    host: "${BROKER_HOST:broker-service}"
+    host: "${BROKER_HOST:localhost}"
     virtual-host: "${BROKER_VIRTUALHOST:dbrepo}"
     username: "${BROKER_USERNAME:admin}"
     password: "${BROKER_PASSWORD:admin}"
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c7316b3d15590979652ea4a04498271f068d2fc
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java
@@ -0,0 +1,42 @@
+package at.tuwien.converters;
+
+import at.tuwien.api.identifier.IdentifierStatusTypeDto;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@SpringBootTest
+public class IdentifierStatusTypeDtoConverterUnitTest extends AbstractUnitTest {
+
+    @Autowired
+    private IdentifierStatusTypeDtoConverter identifierStatusTypeDtoConverter;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+    }
+
+    @Test
+    public void identifierStatusTypeDtoConverter_succeeds() {
+
+        /* test */
+        final IdentifierStatusTypeDto response = identifierStatusTypeDtoConverter.convert(IdentifierStatusTypeDto.DRAFT.getName());
+        assertEquals(IdentifierStatusTypeDto.DRAFT, response);
+    }
+
+    @Test
+    public void identifierStatusTypeDtoConverter_fails() {
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            identifierStatusTypeDtoConverter.convert("i_do_not_exist");
+        });
+    }
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java
similarity index 55%
rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java
rename to dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java
index 7215e5db918f226e6a826fce66e4e129ca4f0c5f..98abd668d8ec0e30a0f420682a0c7b7fd3e5704d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java
@@ -8,14 +8,15 @@ import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 @Log4j2
 @SpringBootTest
-public class IdentifierTypeConverterUnitTest extends AbstractUnitTest {
+public class IdentifierTypeDtoConverterUnitTest extends AbstractUnitTest {
 
     @Autowired
-    private IdentifierTypeConverter identifierTypeConverter;
+    private IdentifierTypeDtoConverter identifierTypeDtoConverter;
 
     @BeforeEach
     public void beforeEach() {
@@ -23,19 +24,19 @@ public class IdentifierTypeConverterUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void identifierTypeConverter_succeeds() {
+    public void IdentifierTypeDtoConverter_succeeds() {
 
         /* test */
-        final IdentifierTypeDto response = identifierTypeConverter.convert(IdentifierTypeDto.DATABASE.getName());
+        final IdentifierTypeDto response = identifierTypeDtoConverter.convert(IdentifierTypeDto.DATABASE.getName());
         assertEquals(IdentifierTypeDto.DATABASE, response);
     }
 
     @Test
-    public void identifierTypeConverter_fails() {
+    public void IdentifierTypeDtoConverter_fails() {
 
         /* test */
         assertThrows(IllegalArgumentException.class, () -> {
-            identifierTypeConverter.convert("i_do_not_exist");
+            identifierTypeDtoConverter.convert("i_do_not_exist");
         });
     }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfa4924957b9c300aeda92ad2ed305a4dd29b444
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java
@@ -0,0 +1,94 @@
+package at.tuwien.endpoints;
+
+import at.tuwien.api.database.AccessTypeDto;
+import at.tuwien.api.database.DatabaseAccessDto;
+import at.tuwien.api.user.UserDetailsDto;
+import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.DatabaseAccess;
+import at.tuwien.entities.user.User;
+import at.tuwien.exception.*;
+import at.tuwien.mapper.MetadataMapper;
+import at.tuwien.service.AccessService;
+import at.tuwien.service.DatabaseService;
+import at.tuwien.service.UserService;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+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.security.Principal;
+import java.util.List;
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+public class AbstractEndpointUnitTest extends AbstractUnitTest {
+
+    @Autowired
+    private AccessEndpoint accessEndpoint;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+    }
+
+    @Test
+    public void hasRole_noPrincipal_fails() {
+
+        /* test */
+        assertFalse(accessEndpoint.hasRole(null, "some-role"));
+    }
+
+    @Test
+    public void hasRole_noRole_fails() {
+
+        /* test */
+        assertFalse(accessEndpoint.hasRole(USER_1_PRINCIPAL, null));
+    }
+
+    @Test
+    public void getId_fails() {
+
+        /* test */
+        assertNull(accessEndpoint.getId(null));
+    }
+
+    @Test
+    public void getId_noId_fails() {
+        final Principal principal = new UsernamePasswordAuthenticationToken(UserDetailsDto.builder()
+                .id(null) // <<<
+                .build(), null);
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            accessEndpoint.getId(principal);
+        });
+    }
+
+    @Test
+    public void getId_incompatible_fails() {
+        final Principal principal = new UsernamePasswordAuthenticationToken("", null);
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            accessEndpoint.getId(principal);
+        });
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
index f4a700e859e68f5705475a63dbc66f2afeaeb5c4..376769e3c318eaabc93e2a65def2673d85d3e7d2 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
@@ -219,6 +219,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         generic_update(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2, DATABASE_1_USER_2_WRITE_OWN_ACCESS);
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
+    public void update_ownerNoAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_update(USER_1_PRINCIPAL, USER_1, USER_1_ID, null, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
+    public void update_ownerNoWriteAllAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_update(USER_1_PRINCIPAL, USER_1, USER_LOCAL_ADMIN_ID, USER_LOCAL, null);
+        });
+    }
+
     @Test
     @WithAnonymousUser
     public void revoke_anonymous_fails() {
@@ -249,6 +269,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
+    public void revoke_ownerNoAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_revoke(USER_1_PRINCIPAL, USER_1, USER_1_ID, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
+    public void revoke_ownerNoWriteAllAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_revoke(USER_1_PRINCIPAL, USER_1, USER_LOCAL_ADMIN_ID, USER_LOCAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
     public void revoke_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
index ab3f4485b2cf35134c2d0ee126ee30af04636165..00185d9ea134c33eba73ba7c24a02ff2d606ab1d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
@@ -1,12 +1,14 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.api.container.ContainerBriefDto;
-import at.tuwien.api.container.ContainerCreateDto;
 import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.entities.container.Container;
-import at.tuwien.exception.*;
+import at.tuwien.exception.ContainerAlreadyExistsException;
+import at.tuwien.exception.ContainerNotFoundException;
+import at.tuwien.exception.ImageNotFoundException;
 import at.tuwien.service.impl.ContainerServiceImpl;
+import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -14,6 +16,7 @@ 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.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.test.context.support.WithAnonymousUser;
@@ -52,19 +55,23 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-container"})
-    public void findById_hasRole_succeeds() throws ContainerNotFoundException {
+    @WithMockUser(username = USER_1_USERNAME)
+    public void findById_succeeds() throws ContainerNotFoundException {
 
         /* test */
         findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
     }
 
     @Test
-    @WithMockUser(username = USER_4_USERNAME)
-    public void findById_noRole_succeeds() throws ContainerNotFoundException {
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
+    public void findById_system_succeeds() throws ContainerNotFoundException {
 
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_4_PRINCIPAL);
+        final ResponseEntity<ContainerDto> response = findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_LOCAL_ADMIN_PRINCIPAL);
+        final HttpHeaders headers = response.getHeaders() ;
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_USERNAME), headers.get("X-Username"));
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_PASSWORD), headers.get("X-Password"));
+        assertEquals(List.of("X-Username X-Password"), headers.get("Access-Control-Expose-Headers"));
     }
 
     @Test
@@ -122,7 +129,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void create_anonymous_fails() {
-        final ContainerCreateDto request = ContainerCreateDto.builder()
+        final CreateContainerDto request = CreateContainerDto.builder()
                 .name(CONTAINER_1_NAME)
                 .imageId(IMAGE_1_ID)
                 .build();
@@ -136,7 +143,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-container"})
     public void create_hasRole_succeeds() throws ContainerAlreadyExistsException, ImageNotFoundException {
-        final ContainerCreateDto request = ContainerCreateDto.builder()
+        final CreateContainerDto request = CreateContainerDto.builder()
                 .name(CONTAINER_1_NAME)
                 .imageId(IMAGE_1_ID)
                 .build();
@@ -148,7 +155,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_4_USERNAME)
     public void create_noRole_fails() {
-        final ContainerCreateDto request = ContainerCreateDto.builder()
+        final CreateContainerDto request = CreateContainerDto.builder()
                 .name(CONTAINER_1_NAME)
                 .imageId(IMAGE_1_ID)
                 .build();
@@ -171,7 +178,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
-    public void findById_generic(Long containerId, Container container, Principal principal)
+    public ResponseEntity<ContainerDto> findById_generic(Long containerId, Container container, Principal principal)
             throws ContainerNotFoundException {
 
         /* mock */
@@ -182,6 +189,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
         final ResponseEntity<ContainerDto> response = containerEndpoint.findById(containerId, principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
+        return response;
     }
 
     public void delete_generic(Long containerId, Container container) throws ContainerNotFoundException {
@@ -221,7 +229,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
         assertEquals(CONTAINER_2_INTERNALNAME, container2.getInternalName());
     }
 
-    public void create_generic(ContainerCreateDto data) throws ContainerAlreadyExistsException, ImageNotFoundException {
+    public void create_generic(CreateContainerDto data) throws ContainerAlreadyExistsException, ImageNotFoundException {
 
         /* mock */
         when(containerService.create(data))
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
index 11d64faf8b9562ff42ab2120d5f6fa151710d462..fd91fb5655ad563ee0b4f8503dbdb5b60db6fea9 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
@@ -4,7 +4,6 @@ import at.tuwien.api.database.*;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.service.*;
 import at.tuwien.service.impl.DatabaseServiceImpl;
 import at.tuwien.test.AbstractUnitTest;
@@ -42,9 +41,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @MockBean
     private AccessService accessService;
 
-    @MockBean
-    private KeycloakGateway keycloakGateway;
-
     @MockBean
     private ContainerService containerService;
 
@@ -68,7 +64,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void create_anonymous_fails() {
-        final DatabaseCreateDto request = DatabaseCreateDto.builder()
+        final CreateDatabaseDto request = CreateDatabaseDto.builder()
                 .cid(CONTAINER_1_ID)
                 .name(DATABASE_1_NAME)
                 .isPublic(DATABASE_1_PUBLIC)
@@ -83,7 +79,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_4_USERNAME)
     public void create_noRole_fails() {
-        final DatabaseCreateDto request = DatabaseCreateDto.builder()
+        final CreateDatabaseDto request = CreateDatabaseDto.builder()
                 .cid(CONTAINER_3_ID)
                 .name(DATABASE_3_NAME)
                 .isPublic(DATABASE_3_PUBLIC)
@@ -101,7 +97,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
             DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException,
             SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
             BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException {
-        final DatabaseCreateDto request = DatabaseCreateDto.builder()
+        final CreateDatabaseDto request = CreateDatabaseDto.builder()
                 .cid(CONTAINER_1_ID)
                 .name(DATABASE_1_NAME)
                 .isPublic(DATABASE_1_PUBLIC)
@@ -124,7 +120,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database"})
     public void create_quotaExceeded_fails() throws UserNotFoundException, ContainerNotFoundException {
-        final DatabaseCreateDto request = DatabaseCreateDto.builder()
+        final CreateDatabaseDto request = CreateDatabaseDto.builder()
                 .cid(CONTAINER_4_ID)
                 .name(DATABASE_1_NAME)
                 .isPublic(DATABASE_1_PUBLIC)
@@ -144,7 +140,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void refreshTableMetadata_anonymous_succeeds() {
+    public void refreshTableMetadata_anonymous_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -154,7 +150,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void refreshTableMetadata_noRole_succeeds() {
+    public void refreshTableMetadata_noRole_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -198,7 +194,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1);
 
         /* test */
-        final ResponseEntity<DatabaseDto> response = databaseEndpoint.refreshTableMetadata(DATABASE_1_ID, USER_1_PRINCIPAL);
+        final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.refreshTableMetadata(DATABASE_1_ID, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
     }
@@ -218,7 +214,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1);
 
         /* test */
-        final ResponseEntity<DatabaseDto> response = databaseEndpoint.refreshViewMetadata(DATABASE_1_ID, USER_1_PRINCIPAL);
+        final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.refreshViewMetadata(DATABASE_1_ID, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
     }
@@ -353,15 +349,12 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-visibility"})
     public void visibility_hasRole_succeeds() throws NotAllowedException, UserNotFoundException,
-            DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, AuthServiceException,
-            AuthServiceConnectionException {
+            DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
         final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
                 .isPublic(true)
                 .build();
 
         /* mock */
-        when(keycloakGateway.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
         when(userService.findById(USER_1_ID))
                 .thenReturn(USER_1);
 
@@ -509,7 +502,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-owner"})
     public void transfer_hasRole_succeeds() throws DataServiceConnectionException, DataServiceException,
             NotAllowedException, UserNotFoundException, DatabaseNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException {
+            SearchServiceConnectionException {
         final DatabaseTransferDto request = DatabaseTransferDto.builder()
                 .id(USER_4_ID)
                 .build();
@@ -517,8 +510,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(databaseService.findById(DATABASE_1_ID))
                 .thenReturn(DATABASE_1);
-        when(keycloakGateway.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
         when(userService.findById(USER_1_ID))
                 .thenReturn(USER_1);
         when(userService.findById(USER_4_ID))
@@ -550,7 +541,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_anonymous_fails() {
+    public void findById_anonymousPrivateSchemaNoAccess_fails() {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -560,40 +551,51 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_anonymousNotFound_fails() {
+    public void findById_anonymousPublicSchemaNoAccess_succeeds() throws UserNotFoundException, NotAllowedException,
+            DataServiceException, DatabaseNotFoundException, ExchangeNotFoundException, DataServiceConnectionException {
 
         /* test */
-        assertThrows(DatabaseNotFoundException.class, () -> {
-            findById_generic(DATABASE_1_ID, null, null);
-        });
+        final DatabaseDto database = findById_generic(DATABASE_2_ID, DATABASE_2, null);
+        assertEquals(3, database.getTables().size());
+        assertEquals(1, database.getViews().size());
+        assertEquals(0, database.getAccesses().size());
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_hasRole_succeeds() throws DataServiceException, DataServiceConnectionException,
-            DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
+    @WithAnonymousUser
+    public void findById_anonymousPrivateSchemaNoAccessSystem_succeeds() throws UserNotFoundException,
+            NotAllowedException, DataServiceException, DatabaseNotFoundException, ExchangeNotFoundException,
+            DataServiceConnectionException {
 
         /* test */
-        findById_generic(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
+        final DatabaseDto database = findById_generic(DATABASE_1_ID, DATABASE_1, USER_LOCAL_ADMIN_PRINCIPAL);
+        assertEquals(4, database.getTables().size());
+        assertEquals(2, database.getViews().size());
+        assertNotEquals(0, database.getAccesses().size());
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_hasRoleForeign_succeeds() throws DataServiceException, DataServiceConnectionException,
-            DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException {
+    @WithAnonymousUser
+    public void findById_privateSchema_fails() {
 
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            findById_generic(DATABASE_1_ID, DATABASE_1, null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void findById_anonymousNotFound_fails() {
 
         /* test */
-        findById_generic(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            findById_generic(DATABASE_1_ID, null, null);
+        });
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
+    @WithMockUser(username = USER_1_USERNAME)
     public void findById_ownerSeesAccessRights_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException {
 
@@ -602,10 +604,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS, DATABASE_1_USER_2_READ_ACCESS));
 
         /* test */
-        final DatabaseDto response = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL);
-        final List<DatabaseAccessDto> accessList = response.getAccesses();
-        assertNotNull(accessList);
-        assertEquals(3, accessList.size());
+        final DatabaseDto database = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL);
+        assertEquals(4, database.getTables().size());
+        assertEquals(3, database.getViews().size());
+        assertEquals(3, database.getAccesses().size());
     }
 
     @Test
@@ -669,7 +671,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         assertEquals(expectedSize, body.size());
     }
 
-    public void create_generic(DatabaseCreateDto data, Principal principal, User user) throws DataServiceException,
+    public void create_generic(CreateDatabaseDto data, Principal principal, User user) throws DataServiceException,
             DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
             ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException,
             BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException {
@@ -682,7 +684,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(DATABASE_1);
 
         /* test */
-        final ResponseEntity<DatabaseDto> response = databaseEndpoint.create(data, principal);
+        final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.create(data, principal);
         assertEquals(HttpStatus.CREATED, response.getStatusCode());
         assertNotNull(response.getBody());
     }
@@ -704,7 +706,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         }
 
         /* test */
-        final ResponseEntity<DatabaseDto> response = databaseEndpoint.visibility(databaseId, data, principal);
+        final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.visibility(databaseId, data, principal);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
         assertNotNull(response.getBody());
     }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
index 74a252c5a63572e569a1e7b8379637e2d34dc03d..419393b485096b84f6495bfcd6ce2910e0c9ae46 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
@@ -122,12 +122,58 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         );
     }
 
+    public static Stream<Arguments> findAll_anonymousFilterDatabase_parameters() {
+        return Stream.of(
+                Arguments.arguments("dbid", DATABASE_1_ID, null, null, null, null, 1),
+                Arguments.arguments("qid", DATABASE_1_ID, QUERY_1_ID, null, null, null, 0),
+                Arguments.arguments("vid", DATABASE_1_ID, null, VIEW_1_ID, null, null, 0),
+                Arguments.arguments("tid", DATABASE_1_ID, null, null, TABLE_1_ID, null, 0),
+                Arguments.arguments("status_published", DATABASE_1_ID, null, null, null, "PUBLISHED", 1),
+                Arguments.arguments("status_draft", DATABASE_1_ID, null, null, null, "DRAFT", 0)
+        );
+    }
+
+    public static Stream<Arguments> findAll_filterSubset_parameters() {
+        return Stream.of(
+                Arguments.arguments("status_published", DATABASE_2_ID, null, null, null, "PUBLISHED", 0),
+                Arguments.arguments("status_draft", DATABASE_2_ID, null, null, null, "DRAFT", 1)
+        );
+    }
+
     public static Stream<Arguments> findAll_filterDatabase_parameters() {
         return Stream.of(
-                Arguments.arguments("dbid", DATABASE_1_ID, null, null, null, 4),
-                Arguments.arguments("qid", DATABASE_1_ID, QUERY_1_ID, null, null, 1),
-                Arguments.arguments("vid", DATABASE_1_ID, null, VIEW_1_ID, null, 1),
-                Arguments.arguments("tid", DATABASE_1_ID, null, null, TABLE_1_ID, 1)
+                Arguments.arguments("database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("anon_database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null),
+                Arguments.arguments("anon_database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null),
+                Arguments.arguments("anon_database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null),
+                Arguments.arguments("anon_subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, null),
+                Arguments.arguments("anon_subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null),
+                Arguments.arguments("anon_subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null),
+                Arguments.arguments("anon_view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null),
+                Arguments.arguments("anon_view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, null),
+                Arguments.arguments("anon_view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null),
+                Arguments.arguments("anon_table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null),
+                Arguments.arguments("anon_table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null),
+                Arguments.arguments("anon_table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, null)
         );
     }
 
@@ -146,14 +192,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_empty_succeeds() throws FormatNotAvailableException {
+    public void findAll_empty_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of());
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/json", null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
@@ -161,12 +207,90 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         assertEquals(0, identifiers.size());
     }
 
+    @ParameterizedTest
+    @MethodSource("findAll_anonymousFilterDatabase_parameters")
+    @WithAnonymousUser
+    public void findAll_anonymousFilterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId,
+                                                         Long tableId, IdentifierStatusTypeDto status,
+                                                         Integer expectedSize) throws ViewNotFoundException,
+            TableNotFoundException, DatabaseNotFoundException {
+
+        /* mock */
+        when(identifierService.findAll())
+                .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7));
+        if (viewId != null) {
+            when(viewService.findById(DATABASE_1, VIEW_1_ID))
+                    .thenReturn(VIEW_1);
+        }
+        if (tableId != null) {
+            when(tableService.findById(DATABASE_1, TABLE_1_ID))
+                    .thenReturn(TABLE_1);
+        }
+
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, status, databaseId, queryId, viewId, tableId, "application/json", null);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(expectedSize, identifiers.size());
+    }
+
+    @ParameterizedTest
+    @MethodSource("findAll_filterSubset_parameters")
+    @WithMockUser(username = USER_2_USERNAME)
+    public void findAll_filterSubset_succeeds(String name, Long databaseId, Long queryId, Long viewId, Long tableId,
+                                              IdentifierStatusTypeDto status, Integer expectedSize) {
+
+        /* mock */
+        when(identifierService.findAll())
+                .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7));
+
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.SUBSET, status, databaseId, queryId, viewId, tableId, "application/json", USER_2_PRINCIPAL);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(expectedSize, identifiers.size());
+    }
+
+    @ParameterizedTest
+    @MethodSource("findAll_anonymousFilterDatabase_parameters")
+    @WithAnonymousUser
+    public void findAll_wrongPrincipalFilterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId,
+                                                              Long tableId, IdentifierStatusTypeDto status,
+                                                              Integer expectedSize)
+            throws ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException {
+
+        /* mock */
+        when(identifierService.findAll())
+                .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7));
+        if (viewId != null) {
+            when(viewService.findById(DATABASE_1, VIEW_1_ID))
+                    .thenReturn(VIEW_1);
+        }
+        if (tableId != null) {
+            when(tableService.findById(DATABASE_1, TABLE_1_ID))
+                    .thenReturn(TABLE_1);
+        }
+
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, status, databaseId, queryId, viewId, tableId, "application/json", USER_2_PRINCIPAL);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(expectedSize, identifiers.size());
+    }
+
     @ParameterizedTest
     @MethodSource("findAll_filterDatabase_parameters")
     @WithAnonymousUser
-    public void findAll_filterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId, Long tableId,
-                                                Integer expectedSize) throws FormatNotAvailableException,
-            ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException {
+    public void findAll_filterDatabase_succeeds(String name, IdentifierTypeDto type, IdentifierStatusTypeDto status,
+                                                Long databaseId, Long queryId, Long viewId, Long tableId,
+                                                Integer expectedSize, Principal principal) throws ViewNotFoundException,
+            TableNotFoundException, DatabaseNotFoundException {
 
         /* mock */
         when(identifierService.findAll())
@@ -181,7 +305,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         }
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(databaseId, queryId, viewId, tableId, "application/json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(type, status, databaseId, queryId, viewId, tableId, "application/json", principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
@@ -191,14 +315,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_json_succeeds() throws FormatNotAvailableException {
+    public void findAll_json_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of(IDENTIFIER_1));
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/json", null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
@@ -208,14 +332,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_jsonLd_succeeds() throws FormatNotAvailableException {
+    public void findAll_jsonLd_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of(IDENTIFIER_1));
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/ld+json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/ld+json", null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<LdDatasetDto> identifiers = (List<LdDatasetDto>) response.getBody();
@@ -225,23 +349,95 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_format_fails() {
+    public void findAll_format_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of(IDENTIFIER_1));
 
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "text/html", null);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(1, identifiers.size());
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void find_textCsvDatabase_fails() throws IdentifierNotFoundException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_1_ID))
+                .thenReturn(IDENTIFIER_1);
+
         /* test */
         assertThrows(FormatNotAvailableException.class, () -> {
-            identifierEndpoint.findAll(null, null, null, null, "text/csv");
+            identifierEndpoint.find(IDENTIFIER_1_ID, "text/csv", null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void find_draft_fails() throws IdentifierNotFoundException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_5_ID))
+                .thenReturn(IDENTIFIER_5);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME)
+    public void find_draftNotOwner_fails() throws IdentifierNotFoundException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_5_ID))
+                .thenReturn(IDENTIFIER_5);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", USER_1_PRINCIPAL);
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void find_draft_succeeds() throws IdentifierNotFoundException, MalformedException, NotAllowedException,
+            DataServiceException, QueryNotFoundException, DataServiceConnectionException, FormatNotAvailableException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_5_ID))
+                .thenReturn(IDENTIFIER_5);
+
+        /* test */
+        identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", USER_2_PRINCIPAL);
+    }
+
     @Test
     @WithAnonymousUser
+    public void find_defaultHtmlRespondsJson_succeeds() throws IdentifierNotFoundException, MalformedException,
+            NotAllowedException, DataServiceException, QueryNotFoundException, DataServiceConnectionException,
+            FormatNotAvailableException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_1_ID))
+                .thenReturn(IDENTIFIER_1);
+
+        /* test */
+        identifierEndpoint.find(IDENTIFIER_1_ID, "text/html", null);
+    }
+
+    @Test
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_json0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "application/json";
         final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata0.json"), StandardCharsets.UTF_8), IdentifierDto.class);
 
@@ -250,7 +446,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final IdentifierDto body = (IdentifierDto) response.getBody();
         assertNotNull(body);
@@ -271,7 +467,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_json1_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "application/json";
         final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata1.json"), StandardCharsets.UTF_8), IdentifierDto.class);
 
@@ -280,7 +476,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final IdentifierDto body = (IdentifierDto) response.getBody();
         assertNotNull(body);
@@ -321,7 +517,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_csv_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/csv";
         final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv")));
         final InputStreamResource mock = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv")));
@@ -333,7 +529,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(mock);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final InputStreamResource body = (InputStreamResource) response.getBody();
         assertNotNull(body);
@@ -344,7 +540,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliography_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"),
                 StandardCharsets.UTF_8);
@@ -356,7 +552,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -365,9 +561,29 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
+    public void find_anonymousBibliographyApa0_fails() throws IOException, MalformedException,
+            IdentifierNotFoundException {
+        final String accept = "text/bibliography; style=apa";
+        final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"),
+                StandardCharsets.UTF_8);
+
+        /* mock */
+        when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.APA))
+                .thenReturn(compare);
+        when(identifierService.find(IDENTIFIER_7_ID))
+                .thenReturn(IDENTIFIER_7);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_7_ID, accept, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_bibliographyApa0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"),
                 StandardCharsets.UTF_8);
@@ -379,7 +595,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -390,7 +606,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyApa1_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"),
                 StandardCharsets.UTF_8);
@@ -402,7 +618,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -410,10 +626,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
-    public void find_bibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException,
+    @WithMockUser(username = USER_2_USERNAME)
+    public void find_draftBibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa2.txt"),
                 StandardCharsets.UTF_8);
@@ -425,7 +641,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_5);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -436,7 +652,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyApa3_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa3.txt"),
                 StandardCharsets.UTF_8);
@@ -448,7 +664,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_6);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_6_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_6_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -459,7 +675,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyApa4_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa4.txt"),
                 StandardCharsets.UTF_8);
@@ -471,7 +687,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1_WITH_DOI);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -479,10 +695,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_bibliographyIeee0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee0.txt"),
                 StandardCharsets.UTF_8);
@@ -494,7 +710,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -505,7 +721,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyIeee1_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee1.txt"),
                 StandardCharsets.UTF_8);
@@ -517,7 +733,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -525,10 +741,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_2_USERNAME)
     public void find_bibliographyIeee2_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee2.txt"),
                 StandardCharsets.UTF_8);
@@ -540,7 +756,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_5);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -551,7 +767,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyIeee3_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee3.txt"),
                 StandardCharsets.UTF_8);
@@ -563,7 +779,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1_WITH_DOI);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -571,10 +787,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_bibliographyBibtex0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex0.txt"),
                 StandardCharsets.UTF_8);
@@ -586,7 +802,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -597,7 +813,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyBibtex1_succeeds() throws MalformedException, IOException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex1.txt"),
                 StandardCharsets.UTF_8);
@@ -609,7 +825,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -617,10 +833,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_2_USERNAME)
     public void find_bibliographyBibtex2_succeeds() throws MalformedException, DataServiceException, IOException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex2.txt"),
                 StandardCharsets.UTF_8);
@@ -632,7 +848,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_5);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -643,7 +859,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyBibtex3_succeeds() throws MalformedException, DataServiceException,
             DataServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex3.txt"),
                 StandardCharsets.UTF_8);
@@ -655,7 +871,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1_WITH_DOI);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -665,7 +881,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void find_jsonLd_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException {
         final String accept = "application/ld+json";
 
         /* mock */
@@ -673,7 +889,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final LdDatasetDto body = (LdDatasetDto) response.getBody();
         assertNotNull(body);
@@ -689,22 +905,22 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        assertThrows(FormatNotAvailableException.class, () -> {
-            identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_7_ID, accept, null);
         });
     }
 
     @Test
     @WithAnonymousUser
     public void find_move_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException {
 
         /* mock */
         when(identifierService.find(IDENTIFIER_1_ID))
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, null);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, null, null);
         assertEquals(HttpStatus.MOVED_PERMANENTLY, response.getStatusCode());
     }
 
@@ -848,7 +1064,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void find_json_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException {
+            FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException, NotAllowedException {
         final String accept = "application/json";
 
         /* mock */
@@ -856,7 +1072,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final IdentifierDto body = (IdentifierDto) response.getBody();
         assertNotNull(body);
@@ -875,7 +1091,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void find_xml_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+            IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException,
+            NotAllowedException {
         final InputStreamResource resource = new InputStreamResource(FileUtils.openInputStream(
                 new File("src/test/resources/xml/datacite-example-dataset-v4.xml")));
 
@@ -892,7 +1109,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_httpRedirect_succeeds() throws MalformedException, DataServiceException,
             DataServiceConnectionException, FormatNotAvailableException, QueryNotFoundException,
-            IdentifierNotFoundException {
+            IdentifierNotFoundException, NotAllowedException {
 
         /* test */
         final ResponseEntity<?> response = generic_find(null, null);
@@ -1291,7 +1508,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     protected ResponseEntity<?> generic_find(String accept, InputStreamResource resource)
             throws MalformedException, DataServiceException, DataServiceConnectionException, FormatNotAvailableException,
-            QueryNotFoundException, IdentifierNotFoundException {
+            QueryNotFoundException, IdentifierNotFoundException, NotAllowedException {
 
         /* mock */
         when(identifierService.find(IDENTIFIER_1_ID))
@@ -1304,7 +1521,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         }
 
         /* test */
-        return identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        return identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
     }
 
     protected static String inputStreamToString(InputStream inputStream) throws IOException {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
index ef06d7f37fd01373df24be3c27f95919850b9fae..a17d31649e6824442613261b91bca4ee923a4817 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java
@@ -1,14 +1,14 @@
 package at.tuwien.endpoints;
 
 import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TableUpdateDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import at.tuwien.api.semantics.EntityDto;
 import at.tuwien.api.semantics.TableColumnEntityDto;
 import at.tuwien.entities.database.Database;
@@ -203,10 +203,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicDecimalColumnSizeTooSmall_fails() {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(ColumnTypeDto.DECIMAL)
                         .size(-1L) // <<<
@@ -224,10 +224,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicDecimalColumnDTooSmall_fails() {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(ColumnTypeDto.DECIMAL)
                         .size(0L)
@@ -247,10 +247,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicOptionalSizeNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException,
             NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(null) // <<<
@@ -278,10 +278,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicOptionalSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException,
             NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(40L)
@@ -303,15 +303,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicNeedNothing_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException,
             NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .nullAllowed(false)
                         .build()))
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .uniques(List.of(List.of("ID")))
                         .build())
                 .build();
@@ -329,10 +329,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicNeedSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException,
             NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(40L)
@@ -353,10 +353,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @MethodSource("needSize_parameters")
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicNeedSizeNone_fails(ColumnTypeDto columnType) {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(null) // <<<
@@ -375,10 +375,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @MethodSource("canHaveSizeAndD_parameters")
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicCanHaveSizeAndDSizeNone_fails(ColumnTypeDto columnType) {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(null) // <<<
@@ -397,10 +397,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @MethodSource("canHaveSizeAndD_parameters")
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicCanHaveSizeAndDDNone_fails(ColumnTypeDto columnType) {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(0L)
@@ -423,10 +423,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
             DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException,
             DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException,
             SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(null) // <<<
@@ -446,20 +446,20 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicHasMultipleSerial_fails() {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                                 .name("ID")
                                 .type(ColumnTypeDto.SERIAL)
                                 .nullAllowed(false)
                                 .build(),
-                        ColumnCreateDto.builder()
+                        CreateTableColumnDto.builder()
                                 .name("Counter")
                                 .type(ColumnTypeDto.SERIAL)
                                 .nullAllowed(false)
                                 .build()))
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .uniques(List.of(List.of("ID"),
                                 List.of("Counter")))
                         .build())
@@ -474,15 +474,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"})
     public void create_publicSerialNullAllowed_fails() {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(ColumnTypeDto.SERIAL)
                         .nullAllowed(true) // <<<
                         .build()))
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .uniques(List.of(List.of("ID")))
                         .build())
                 .build();
@@ -501,10 +501,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
             DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException,
             DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException,
             SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("Some Table")
                 .description("Some Description")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("ID")
                         .type(columnType)
                         .size(0L) // <<<
@@ -1040,7 +1040,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
                 .build();
 
         /* test */
-        final ResponseEntity<TableDto> response = generic_update(request, USER_1_PRINCIPAL);
+        final ResponseEntity<TableBriefDto> response = generic_update(request, USER_1_PRINCIPAL);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
         assertNotNull(response.getBody());
     }
@@ -1147,7 +1147,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         return tableEndpoint.list(databaseId, principal);
     }
 
-    protected ResponseEntity<TableDto> generic_create(Long databaseId, Database database, TableCreateDto data,
+    protected ResponseEntity<TableBriefDto> generic_create(Long databaseId, Database database, CreateTableDto data,
                                                       Principal principal, User user, DatabaseAccess access)
             throws MalformedException, NotAllowedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, TableNotFoundException,
@@ -1273,7 +1273,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
         return tableEndpoint.updateColumn(databaseId, tableId, columnId, data, principal);
     }
 
-    protected ResponseEntity<TableDto> generic_update(TableUpdateDto data, Principal caller)
+    protected ResponseEntity<TableBriefDto> generic_update(TableUpdateDto data, Principal caller)
             throws TableNotFoundException, SearchServiceException, NotAllowedException, DataServiceException,
             DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException {
 
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 be0ea28c496d9c3bd65df14f8a312af5c9003069..b1a65fc0cdce05ee9d1bcdfa0ad63e03f47933ba 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
@@ -1,8 +1,6 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.SignupRequestDto;
-import at.tuwien.api.keycloak.UserAttributesDto;
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
@@ -17,9 +15,6 @@ 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;
@@ -34,7 +29,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 import java.security.Principal;
 import java.util.List;
 import java.util.UUID;
-import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -56,13 +50,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     @Autowired
     private UserEndpoint userEndpoint;
 
-    public static Stream<Arguments> getToken_parameters() {
-        return Stream.of(
-                Arguments.arguments("null", null),
-                Arguments.arguments("empty", new UUID[]{})
-        );
-    }
-
     @BeforeEach
     public void beforeEach() {
         genesis();
@@ -104,31 +91,21 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
-    public void create_anonymous_succeeds() throws UserExistsException, EmailExistsException, UserNotFoundException,
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_succeeds() throws UserExistsException, EmailExistsException, UserNotFoundException,
             AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
-        final SignupRequestDto request = SignupRequestDto.builder()
-                .email(USER_1_EMAIL)
-                .username(USER_1_USERNAME)
-                .password(USER_1_PASSWORD)
-                .build();
 
         /* test */
-        create_generic(request, USER_1, USER_1_KEYCLOAK_DTO, USER_1_ID);
+        create_generic(USER_1_SIGNUP_REQUEST_DTO, USER_1);
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void create_isAuthenticated_fails() {
-        final SignupRequestDto request = SignupRequestDto.builder()
-                .email(USER_2_EMAIL)
-                .username(USER_2_USERNAME)
-                .password(USER_2_PASSWORD)
-                .build();
+    public void create_noRole_fails() {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            create_generic(request, null, null, null);
+            create_generic(USER_1_SIGNUP_REQUEST_DTO, null);
         });
     }
 
@@ -235,7 +212,8 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-user-information"})
-    public void modify_succeeds() throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException {
+    public void modify_succeeds() throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException,
+            AuthServiceException, AuthServiceConnectionException {
         final UserUpdateDto request = UserUpdateDto.builder()
                 .firstname(USER_1_FIRSTNAME)
                 .lastname(USER_1_LASTNAME)
@@ -286,136 +264,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
         password_generic(USER_1_PRINCIPAL, request);
     }
 
-    @Test
-    @WithAnonymousUser
-    public void getToken_anonymous_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException {
-
-        /* test */
-        getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, USER_1);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void getToken_loggedIn_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException {
-
-        /* test */
-        getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, USER_1);
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void getToken_notExists_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException {
-
-        /* mock */
-        when(authenticationService.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
-        when(userService.create(any(SignupRequestDto.class), any(UUID.class)))
-                .thenReturn(USER_1);
-
-        /* test */
-        getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null);
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void getToken_notExists_fails() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        doThrow(UserNotFoundException.class)
-                .when(authenticationService)
-                .findByUsername(USER_1_USERNAME);
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null);
-        });
-    }
-
-    @ParameterizedTest
-    @MethodSource("getToken_parameters")
-    @WithAnonymousUser
-    public void getToken_missingLdapId_fails(String name, UUID[] ldapId) throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException {
-        final at.tuwien.api.keycloak.UserDto mock = at.tuwien.api.keycloak.UserDto.builder()
-                .attributes(UserAttributesDto.builder()
-                        .ldapId(ldapId)
-                        .build())
-                .build();
-
-        /* mock */
-        when(authenticationService.findByUsername(USER_1_USERNAME))
-                .thenReturn(mock);
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null);
-        });
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void refreshToken_anonymous_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        when(authenticationService.refreshToken(anyString()))
-                .thenReturn(TOKEN_DTO);
-
-        /* test */
-        final ResponseEntity<?> response = userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void refreshToken_loggedIn_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        when(authenticationService.refreshToken(anyString()))
-                .thenReturn(TOKEN_DTO);
-
-        /* test */
-        final ResponseEntity<?> response = userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void refreshToken_authServiceConnection_fails() throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-
-        /* mock */
-        doThrow(AuthServiceConnectionException.class)
-                .when(authenticationService)
-                .refreshToken(anyString());
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void refreshToken_invalidCredentials_fails() throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-
-        /* mock */
-        doThrow(CredentialsInvalidException.class)
-                .when(authenticationService)
-                .refreshToken(anyString());
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        });
-    }
-
     /* ################################################################################################### */
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
@@ -445,22 +293,17 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
         return response.getBody();
     }
 
-    protected void create_generic(SignupRequestDto data, User user, at.tuwien.api.keycloak.UserDto userDto, UUID id)
-            throws UserExistsException, EmailExistsException, UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException {
+    protected void create_generic(CreateUserDto data, User user) throws UserExistsException, EmailExistsException,
+            UserNotFoundException, AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
-        when(userService.create(eq(data), any(UUID.class)))
+        when(userService.create(any(CreateUserDto.class)))
                 .thenReturn(user);
-        when(authenticationService.findByUsername(data.getUsername()))
-                .thenReturn(userDto);
-        when(authenticationService.create(data))
-                .thenReturn(userDto);
 
         /* test */
-        final ResponseEntity<UserDto> response = userEndpoint.create(data);
+        final ResponseEntity<UserBriefDto> response = userEndpoint.create(data);
         assertEquals(HttpStatus.CREATED, response.getStatusCode());
-        final UserDto body = response.getBody();
+        final UserBriefDto body = response.getBody();
         assertNotNull(body);
     }
 
@@ -486,7 +329,8 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected void modify_generic(UUID userId, User user, Principal principal, UserUpdateDto data)
-            throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException {
+            throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException, AuthServiceException,
+            AuthServiceConnectionException {
         /* mock */
         if (user != null) {
             when(userService.findById(userId))
@@ -496,9 +340,9 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(user);
 
         /* test */
-        final ResponseEntity<UserDto> response = userEndpoint.modify(userId, data, principal);
+        final ResponseEntity<UserBriefDto> response = userEndpoint.modify(userId, data, principal);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        final UserDto body = response.getBody();
+        final UserBriefDto body = response.getBody();
         assertNotNull(body);
     }
 
@@ -522,26 +366,4 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
         final ResponseEntity<?> response = userEndpoint.password(USER_1_ID, data, principal);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
-
-    protected void getToken_generic(LoginRequestDto request, Principal principal, User user)
-            throws UserNotFoundException, AuthServiceConnectionException, AccountNotSetupException,
-            CredentialsInvalidException, AuthServiceException {
-
-        /* mock */
-        when(authenticationService.obtainToken(any(LoginRequestDto.class)))
-                .thenReturn(TOKEN_DTO);
-        if (user != null) {
-            when(userService.findByUsername(principal.getName()))
-                    .thenReturn(user);
-        } else {
-            doThrow(UserNotFoundException.class)
-                    .when(userService)
-                    .findByUsername(principal.getName());
-        }
-
-        /* test */
-        final ResponseEntity<?> response = userEndpoint.getToken(request);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
index 2815dd6c0557a31490dff959bcff7f60e559b805..d1434ef9e4035cd13d81a4f12ec68bad71683bf1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.api.database.ViewBriefDto;
-import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.database.ViewUpdateDto;
 import at.tuwien.entities.database.Database;
@@ -21,6 +21,7 @@ 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.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.AccessDeniedException;
@@ -173,6 +174,25 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS);
     }
 
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void find_publicSystem_succeeds() throws UserNotFoundException, DatabaseNotFoundException,
+            AccessNotFoundException, ViewNotFoundException {
+
+        /* test */
+        final ResponseEntity<ViewDto> response = find_generic(DATABASE_3_ID, DATABASE_3, USER_LOCAL_ADMIN_PRINCIPAL,
+                USER_LOCAL_ADMIN_ID, null, null);
+        final HttpHeaders headers = response.getHeaders();
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_USERNAME), headers.get("X-Username"));
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_PASSWORD), headers.get("X-Password"));
+        assertEquals(List.of(CONTAINER_1_HOST), headers.get("X-Host"));
+        assertEquals(List.of("" + CONTAINER_1_PORT), headers.get("X-Port"));
+        assertEquals(List.of(IMAGE_1_JDBC), headers.get("X-Type"));
+        assertEquals(List.of(DATABASE_3_INTERNALNAME), headers.get("X-Database"));
+        assertEquals(List.of(VIEW_5_INTERNAL_NAME), headers.get("X-View"));
+        assertEquals(List.of("X-Username X-Password X-Host X-Port X-Type X-Database X-View"), headers.get("Access-Control-Expose-Headers"));
+    }
+
     @Test
     @WithMockUser(username = USER_2_USERNAME)
     public void find_publicHasRoleHasAccess_succeeds() throws UserNotFoundException, DatabaseNotFoundException,
@@ -461,7 +481,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
                                   DatabaseAccess access) throws MalformedException, DataServiceException,
             DataServiceConnectionException, NotAllowedException, UserNotFoundException, DatabaseNotFoundException,
             AccessNotFoundException, SearchServiceException, SearchServiceConnectionException {
-        final ViewCreateDto request = ViewCreateDto.builder()
+        final CreateViewDto request = CreateViewDto.builder()
                 .name(VIEW_1_NAME)
                 .query(VIEW_1_QUERY)
                 .isPublic(VIEW_1_PUBLIC)
@@ -494,9 +514,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         assertEquals(VIEW_1_NAME, response.getBody().getName());
     }
 
-    protected void find_generic(Long databaseId, Database database, Principal principal, UUID userId, User user,
-                                DatabaseAccess access) throws DatabaseNotFoundException, UserNotFoundException,
-            AccessNotFoundException, ViewNotFoundException {
+    protected ResponseEntity<ViewDto> find_generic(Long databaseId, Database database, Principal principal,
+                                                   UUID userId, User user, DatabaseAccess access)
+            throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, ViewNotFoundException {
 
         /* mock */
         when(databaseService.findById(databaseId))
@@ -514,18 +534,18 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             when(userService.findById(userId))
                     .thenReturn(user);
             when(viewService.findById(any(Database.class), anyLong()))
-                    .thenReturn(VIEW_1);
+                    .thenReturn(VIEW_5);
         } else {
             when(viewService.findById(any(Database.class), anyLong()))
-                    .thenReturn(VIEW_1);
+                    .thenReturn(VIEW_5);
         }
 
         /* test */
-        final ResponseEntity<ViewDto> response = viewEndpoint.find(databaseId, VIEW_1_ID, USER_1_PRINCIPAL);
+        final ResponseEntity<ViewDto> response = viewEndpoint.find(databaseId, VIEW_5_ID, principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
-        assertEquals(VIEW_1_ID, response.getBody().getId());
-        assertEquals(VIEW_1_NAME, response.getBody().getName());
+        assertEquals(VIEW_5_ID, response.getBody().getId());
+        return response;
     }
 
     protected void delete_generic(Long databaseId, Database database, Long viewId, View view, Principal principal,
@@ -571,7 +591,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(VIEW_1);
 
         /* test */
-        final ResponseEntity<ViewDto> response = viewEndpoint.update(DATABASE_1_ID, VIEW_1_ID, request, principal);
+        final ResponseEntity<ViewBriefDto> response = viewEndpoint.update(DATABASE_1_ID, VIEW_1_ID, request, principal);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
         assertNotNull(response.getBody());
     }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e72cd7fa7591a7e641c74df6eab07845b0a193ea
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java
@@ -0,0 +1,114 @@
+package at.tuwien.gateway;
+
+import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.gateway.impl.KeycloakGatewayImpl;
+import at.tuwien.test.AbstractUnitTest;
+import at.tuwien.utils.KeycloakUtils;
+import dasniko.testcontainers.keycloak.KeycloakContainer;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.images.PullPolicy;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@SpringBootTest
+@Testcontainers
+@ExtendWith(SpringExtension.class)
+public class KeycloakGatewayIntegrationTest extends AbstractUnitTest {
+
+    @Autowired
+    private KeycloakGatewayImpl keycloakGateway;
+
+    @Autowired
+    private KeycloakUtils keycloakUtils;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+        /* auth service */
+        keycloakUtils.deleteUser(USER_1_USERNAME);
+    }
+
+    @Container
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE)
+            .withImagePullPolicy(PullPolicy.alwaysPull())
+            .withAdminUsername("admin")
+            .withAdminPassword("admin")
+            .withRealmImportFile("./init/dbrepo-realm.json")
+            .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false");
+
+    @DynamicPropertySource
+    static void keycloakProperties(DynamicPropertyRegistry registry) {
+        final String authServiceEndpoint = "http://localhost:" + keycloakContainer.getMappedPort(8080);
+        log.trace("set auth endpoint: {}", authServiceEndpoint);
+        registry.add("dbrepo.endpoints.authService", () -> authServiceEndpoint);
+    }
+
+    @Test
+    public void deleteUser_succeeds() throws UserNotFoundException {
+
+        /* mock */
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        keycloakGateway.deleteUser(keycloakUtils.getUserId(USER_1_USERNAME));
+    }
+
+    @Test
+    public void deleteUser_notFound_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.deleteUser(USER_1_ID);
+        });
+    }
+
+    @Test
+    public void findByUsername_succeeds() throws UserNotFoundException {
+
+        /* mock */
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        keycloakGateway.findByUsername(USER_1_USERNAME);
+    }
+
+    @Test
+    public void findByUsername_notFound_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.findByUsername(USER_1_USERNAME);
+        });
+    }
+
+    @Test
+    public void updateUserCredentials_succeeds() throws UserNotFoundException {
+
+        /* mock */
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        keycloakGateway.updateUserCredentials(keycloakUtils.getUserId(USER_1_USERNAME), USER_1_PASSWORD_DTO);
+    }
+
+    @Test
+    public void updateUserCredentials_notFound_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.updateUserCredentials(keycloakUtils.getUserId(USER_1_USERNAME), USER_1_PASSWORD_DTO);
+        });
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
deleted file mode 100644
index bb3bcbb094ad1e9a2510abe20b9649ee73e6e975..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
+++ /dev/null
@@ -1,489 +0,0 @@
-package at.tuwien.gateway;
-
-import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserDto;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.impl.KeycloakGatewayImpl;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.http.*;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
-
-import java.nio.charset.Charset;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
-
-@Log4j2
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class KeycloakGatewayUnitTest extends AbstractUnitTest {
-
-    @MockBean
-    @Qualifier("keycloakRestTemplate")
-    private RestTemplate keycloakRestTemplate;
-
-    @MockBean
-    @Qualifier("restTemplate")
-    private RestTemplate restTemplate;
-
-    @Autowired
-    private KeycloakGatewayImpl keycloakGateway;
-
-    @Test
-    public void createUser_succeeds() throws UserExistsException, EmailExistsException, AuthServiceException,
-            AuthServiceConnectionException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
-                        .build());
-
-        /* test */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-    }
-
-    @Test
-    public void createUser_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
-    @Test
-    public void createUser_sameUsername_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(UserExistsException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
-    @Test
-    public void createUser_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
-    @Test
-    public void deleteUser_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .build());
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void deleteUser_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        keycloakGateway.deleteUser(USER_1_ID);
-    }
-
-    @Test
-    public void deleteUser_notFound_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.NotFound.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void deleteUser_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void deleteUser_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void updateUserCredentials_succeeds() throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-    }
-
-    @Test
-    public void updateUserCredentials_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .build());
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-        });
-    }
-
-    @Test
-    public void updateUserCredentials_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-        });
-    }
-
-    @Test
-    public void updateUserCredentials_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-        });
-    }
-
-    @Test
-    public void findByUsername_notFound_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(new UserDto[]{}));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
-        });
-    }
-
-    @Test
-    public void findByUsername_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
-        });
-    }
-
-    @Test
-    public void findByUsername_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
-        });
-    }
-
-    @Test
-    public void findById_succeeds() throws UserNotFoundException, AuthServiceException, AuthServiceConnectionException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(USER_1_KEYCLOAK_DTO));
-
-        /* test */
-        final UserDto response = keycloakGateway.findById(USER_1_ID);
-        assertEquals(USER_1_ID, response.getId());
-    }
-
-    @Test
-    public void findById_notFound_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.NotFound.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            keycloakGateway.findById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void findById_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.findById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void findById_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.findById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void refreshUserToken_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-
-        /* test */
-        final TokenDto response = keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        assertNotNull(response.getAccessToken());
-    }
-
-    @Test
-    public void refreshUserToken_connection_fails() {
-
-        /* mock */
-        doThrow(HttpServerErrorException.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void refreshUserToken_unauthorized_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.Unauthorized.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void refreshUserToken_badRequest_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.BadRequest.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void refreshUserToken_badRequestInactiveSession_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.BadRequest.create(HttpStatus.BAD_REQUEST, "Session not active", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void obtainUserToken_succeeds() throws AuthServiceConnectionException,
-            AccountNotSetupException, CredentialsInvalidException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-
-        /* test */
-        final TokenDto response = keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        assertNotNull(response.getAccessToken());
-    }
-
-    @Test
-    public void obtainUserToken_connection_fails() {
-
-        /* mock */
-        doThrow(HttpServerErrorException.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-    @Test
-    public void obtainUserToken_unauthorized_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.Unauthorized.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java
index b1ce21d4e5e8315b08087dc0d85712509a07973e..b39dd06bac8cd722ccc6e464b1b97438f48b4850 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java
@@ -1,7 +1,7 @@
 package at.tuwien.gateway;
 
 import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.exception.*;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.Test;
@@ -37,11 +37,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
     @Test
     public void update_succeeds() throws DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
-        final ResponseEntity<DatabaseDto> mock = ResponseEntity.accepted()
+        final ResponseEntity<DatabaseBriefDto> mock = ResponseEntity.accepted()
                 .build();
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)))
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)))
                 .thenReturn(mock);
 
         /* test */
@@ -50,11 +50,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
 
     @Test
     public void update_badRequest_fails() {
-        final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.BAD_REQUEST)
+        final ResponseEntity<DatabaseBriefDto> mock = ResponseEntity.status(HttpStatus.BAD_REQUEST)
                 .build();
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)))
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)))
                 .thenReturn(mock);
 
         /* test */
@@ -65,11 +65,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
 
     @Test
     public void update_unexpectedResponse_fails() {
-        final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.OK)
+        final ResponseEntity<DatabaseBriefDto> mock = ResponseEntity.status(HttpStatus.OK)
                 .build();
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)))
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)))
                 .thenReturn(mock);
 
         /* test */
@@ -84,7 +84,7 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
         /* mock */
         doThrow(HttpServerErrorException.ServiceUnavailable.class)
                 .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceConnectionException.class, () -> {
@@ -98,7 +98,7 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
         /* mock */
         doThrow(HttpClientErrorException.NotFound.class)
                 .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
index 9b778e67fb3243e238053972add0f3522c07b9d6..6505506eeaca607cd96e3324e869c2db0907cc4f 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java
@@ -1,13 +1,7 @@
 package at.tuwien.mapper;
 
-import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.database.ViewBriefDto;
-import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.identifier.IdentifierDto;
 import at.tuwien.api.identifier.IdentifierTypeDto;
 import at.tuwien.api.user.UserBriefDto;
-import at.tuwien.api.user.UserDto;
 import at.tuwien.entities.identifier.Identifier;
 import at.tuwien.entities.identifier.IdentifierType;
 import at.tuwien.test.AbstractUnitTest;
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java
index eec5aebf4bea668164c51bae655c074cb306e4c2..0365db6c4a09dfaedb742528b3bb08d4784d53f1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java
@@ -9,8 +9,6 @@ import at.tuwien.repository.ContainerRepository;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.repository.LicenseRepository;
 import at.tuwien.repository.UserRepository;
-import at.tuwien.service.AuthenticationService;
-import at.tuwien.service.UserService;
 import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.utils.KeycloakUtils;
 import dasniko.testcontainers.keycloak.KeycloakContainer;
@@ -31,7 +29,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
 
 import java.util.List;
 
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -50,9 +48,6 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     @Autowired
     private KeycloakUtils keycloakUtils;
 
-    @Autowired
-    private KeycloakGateway keycloakGateway;
-
     @Autowired
     private UserRepository userRepository;
 
@@ -66,7 +61,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     private DatabaseRepository databaseRepository;
 
     @Autowired
-    private AuthenticationService authenticationService;
+    private KeycloakGateway keycloakGateway;
 
     @Container
     private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE)
@@ -98,7 +93,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_database_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
@@ -113,16 +108,14 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_database_basicAdmin_succeeds() throws Exception {
 
         /* pre condition */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD)))
                 .andDo(print())
                 .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
                 .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
-                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
-                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
-                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port"))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
                 .andExpect(status().isOk());
     }
 
@@ -130,17 +123,15 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_database_bearerAdmin_succeeds() throws Exception {
 
         /* pre condition */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
-        final TokenDto jwt = authenticationService.obtainToken(USER_LOCAL_ADMIN_LOGIN_REQUEST_DTO);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        final TokenDto jwt = keycloakGateway.obtainUserToken(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1").header("Authorization", "Bearer " + jwt.getAccessToken()))
                 .andDo(print())
                 .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
                 .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
-                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
-                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
-                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port"))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
                 .andExpect(status().isOk());
     }
 
@@ -148,8 +139,8 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_table_bearerAdmin_succeeds() throws Exception {
 
         /* pre condition */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
-        final TokenDto jwt = authenticationService.obtainToken(USER_LOCAL_ADMIN_LOGIN_REQUEST_DTO);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        final TokenDto jwt = keycloakGateway.obtainUserToken(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD);
 
 
         /* test */
@@ -157,12 +148,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
                 .andDo(print())
                 .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
                 .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
-                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
-                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
-                .andExpect(header().string("X-Type", IMAGE_1_JDBC))
-                .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME))
-                .andExpect(header().string("X-Table", TABLE_1_INTERNAL_NAME))
-                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table"))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
                 .andExpect(status().isOk());
     }
 
@@ -170,18 +156,13 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_table_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
                 .andDo(print())
                 .andExpect(header().doesNotExist("X-Username"))
                 .andExpect(header().doesNotExist("X-Password"))
-                .andExpect(header().doesNotExist("X-Host"))
-                .andExpect(header().doesNotExist("X-Port"))
-                .andExpect(header().doesNotExist("X-Type"))
-                .andExpect(header().doesNotExist("X-Database"))
-                .andExpect(header().doesNotExist("X-Table"))
                 .andExpect(header().doesNotExist("Access-Control-Expose-Headers"))
                 .andExpect(status().isOk());
     }
@@ -190,19 +171,14 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_table_basicAdmin_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD)))
                 .andDo(print())
                 .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME))
                 .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD))
-                .andExpect(header().string("X-Host", CONTAINER_1_HOST))
-                .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT))
-                .andExpect(header().string("X-Type", IMAGE_1_JDBC))
-                .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME))
-                .andExpect(header().string("X-Table", TABLE_1_INTERNAL_NAME))
-                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table"))
+                .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password"))
                 .andExpect(status().isOk());
     }
 
@@ -210,18 +186,13 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_view_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1/view/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
                 .andDo(print())
                 .andExpect(header().doesNotExist("X-Username"))
                 .andExpect(header().doesNotExist("X-Password"))
-                .andExpect(header().doesNotExist("X-Host"))
-                .andExpect(header().doesNotExist("X-Port"))
-                .andExpect(header().doesNotExist("X-Type"))
-                .andExpect(header().doesNotExist("X-Database"))
-                .andExpect(header().doesNotExist("X-View"))
                 .andExpect(header().doesNotExist("Access-Control-Expose-Headers"))
                 .andExpect(status().isOk());
     }
@@ -230,7 +201,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_container_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/container/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
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 5ae4aad0187cc52749416bdb3208d3ff678d5285..790262c7399d36fb0d9a3cf6103f7899300daffb 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
@@ -1,15 +1,14 @@
 package at.tuwien.mvc;
 
-import at.tuwien.api.auth.RefreshTokenRequestDto;
-import at.tuwien.api.database.table.TableStatisticDto;
-import at.tuwien.api.database.table.columns.ColumnStatisticDto;
-import at.tuwien.api.semantics.TableColumnEntityDto;
-import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.container.ContainerCreateDto;
-import at.tuwien.api.database.*;
+import at.tuwien.api.container.CreateContainerDto;
+import at.tuwien.api.database.DatabaseModifyImageDto;
+import at.tuwien.api.database.DatabaseModifyVisibilityDto;
+import at.tuwien.api.database.DatabaseTransferDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
+import at.tuwien.api.identifier.IdentifierTypeDto;
 import at.tuwien.config.MetricsConfig;
 import at.tuwien.endpoints.*;
+import at.tuwien.test.AbstractUnitTest;
 import io.micrometer.observation.annotation.Observed;
 import io.micrometer.observation.tck.TestObservationRegistry;
 import io.swagger.v3.oas.annotations.Operation;
@@ -27,7 +26,6 @@ import org.springframework.boot.test.context.TestConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Import;
 import org.springframework.http.MediaType;
-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 org.springframework.test.web.servlet.MockMvc;
@@ -35,7 +33,10 @@ import org.springframework.test.web.servlet.MockMvc;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -173,7 +174,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            containerEndpoint.create(ContainerCreateDto.builder().name(CONTAINER_1_NAME).imageId(IMAGE_1_ID).build());
+            containerEndpoint.create(CreateContainerDto.builder().name(CONTAINER_1_NAME).imageId(IMAGE_1_ID).build());
         } catch (Exception e) {
             /* ignore */
         }
@@ -276,7 +277,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            identifierEndpoint.findAll(DATABASE_1_ID, null, null, null, MediaType.APPLICATION_JSON_VALUE);
+            identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, MediaType.APPLICATION_JSON_VALUE, null);
         } catch (Exception e) {
             /* ignore */
         }
@@ -590,45 +591,16 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
         } catch (Exception e) {
             /* ignore */
         }
-        try {
-            userEndpoint.refreshToken(RefreshTokenRequestDto.builder().build());
-        } catch (Exception e) {
-            /* ignore */
-        }
 
         /* test */
-        for (String metric : List.of("dbrepo_user_refresh_token", "dbrepo_users_list",
-                "dbrepo_user_find", "dbrepo_user_modify", "dbrepo_user_password_modify")) {
+        for (String metric : List.of("dbrepo_users_list", "dbrepo_user_find", "dbrepo_user_modify",
+                "dbrepo_user_password_modify")) {
             assertThat(registry)
                     .hasObservationWithNameEqualTo(metric);
         }
         generic_openApiDocs(UserEndpoint.class);
     }
 
-    @Test
-    @WithAnonymousUser
-    public void prometheusUserEndpoint2_succeeds() {
-
-        /* mock */
-        try {
-            userEndpoint.create(USER_1_SIGNUP_REQUEST_DTO);
-        } catch (Exception e) {
-            /* ignore */
-        }
-        try {
-            userEndpoint.getToken(USER_1_LOGIN_REQUEST_DTO);
-        } catch (Exception e) {
-            /* ignore */
-        }
-
-        /* test */
-        for (String metric : List.of("dbrepo_user_create", "dbrepo_user_token")) {
-            assertThat(registry)
-                    .hasObservationWithNameEqualTo(metric);
-        }
-        // already done above
-    }
-
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-view", "delete-database-view"})
     public void prometheusViewEndpoint_succeeds() {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
index c647cdbd7403b5f5c742953fd9978e0c8d98ab06..1c96e6283d3d62bc5c31652f82a73312454e2035 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
@@ -3,7 +3,7 @@ package at.tuwien.service;
 import at.tuwien.exception.*;
 import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.api.database.AccessTypeDto;
-import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.entities.database.AccessType;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
@@ -80,7 +80,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
         when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
                         .build());
-        when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)))
+        when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)))
                 .thenReturn(ResponseEntity.accepted()
                         .build());
 
@@ -155,7 +155,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.BadRequest.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceException.class, () -> {
@@ -174,7 +174,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.Unauthorized.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceException.class, () -> {
@@ -193,7 +193,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.NotFound.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
@@ -212,7 +212,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpServerErrorException.InternalServerError.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceConnectionException.class, () -> {
@@ -230,7 +230,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
         when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.accepted()
                         .build());
-        when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)))
+        when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)))
                 .thenReturn(ResponseEntity.accepted()
                         .build());
 
@@ -305,7 +305,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.BadRequest.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceException.class, () -> {
@@ -324,7 +324,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.Unauthorized.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceException.class, () -> {
@@ -343,7 +343,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.NotFound.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
@@ -362,7 +362,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpServerErrorException.InternalServerError.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceConnectionException.class, () -> {
@@ -382,7 +382,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
         when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
                 .thenReturn(ResponseEntity.accepted()
                         .build());
-        when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)))
+        when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)))
                 .thenReturn(ResponseEntity.accepted()
                         .build());
 
@@ -445,7 +445,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.BadRequest.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceException.class, () -> {
@@ -466,7 +466,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.Unauthorized.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceException.class, () -> {
@@ -487,7 +487,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpClientErrorException.NotFound.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
@@ -508,7 +508,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest {
                         .build());
         doThrow(HttpServerErrorException.InternalServerError.class)
                 .when(searchServiceRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class));
+                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class));
 
         /* test */
         assertThrows(SearchServiceConnectionException.class, () -> {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
index fa1cd5d4beeb1fe8fb40d8f59fa974b5d2501dba..d655a25cf1f599b2e92a9fd426cfa343747a3fe1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
@@ -1,9 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.test.AbstractUnitTest;
+import at.tuwien.utils.KeycloakUtils;
 import dasniko.testcontainers.keycloak.KeycloakContainer;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -19,6 +20,8 @@ import org.testcontainers.images.PullPolicy;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import java.util.UUID;
+
 @Log4j2
 @Testcontainers
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@@ -32,13 +35,16 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
     @Autowired
     private KeycloakGateway keycloakGateway;
 
+    @Autowired
+    private KeycloakUtils keycloakUtils;
+
     @BeforeEach
     public void beforeEach() {
         genesis();
     }
 
     @Container
-    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0")
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE)
             .withImagePullPolicy(PullPolicy.alwaysPull())
             .withAdminUsername("admin")
             .withAdminPassword("admin")
@@ -47,7 +53,9 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
 
     @DynamicPropertySource
     static void keycloakProperties(DynamicPropertyRegistry registry) {
-        registry.add("dbrepo.endpoints.authService", () -> "http://localhost:" + keycloakContainer.getMappedPort(8080));
+        final String authServiceEndpoint = "http://localhost:" + keycloakContainer.getMappedPort(8080);
+        log.trace("set auth endpoint: {}", authServiceEndpoint);
+        registry.add("dbrepo.endpoints.authService", () -> authServiceEndpoint);
     }
 
     @Test
@@ -55,14 +63,10 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
             AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
-        try {
-            keycloakGateway.deleteUser(keycloakGateway.findByUsername(USER_1_USERNAME).getId());
-        } catch (Exception e) {
-            /* ignore */
-        }
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.deleteUser(USER_1_USERNAME);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
         final User request = User.builder()
-                .id(keycloakGateway.findByUsername(USER_1_USERNAME).getId())
+                .keycloakId(UUID.fromString(keycloakGateway.findByUsername(USER_1_USERNAME).getId()))
                 .username(USER_1_USERNAME)
                 .build();
 
@@ -70,20 +74,4 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
         authenticationService.delete(request);
     }
 
-    @Test
-    public void create_succeeds() throws EmailExistsException, UserExistsException,
-            DataServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
-            CredentialsInvalidException {
-
-        /* mock */
-        try {
-            keycloakGateway.deleteUser(keycloakGateway.findByUsername(USER_1_USERNAME).getId());
-        } catch (Exception e) {
-            /* ignore */
-        }
-
-        /* test */
-        authenticationService.create(USER_1_SIGNUP_REQUEST_DTO);
-    }
-
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java
index a4f067689355776977c648bfedb0a218941a1cbb..bb19a404ddf23f29e257808974c0ebd787e3c416 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java
@@ -1,7 +1,7 @@
 package at.tuwien.service;
 
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.container.ContainerCreateDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.exception.*;
 import at.tuwien.repository.ContainerRepository;
@@ -48,7 +48,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void create_succeeds() throws ContainerAlreadyExistsException, ImageNotFoundException {
-        final ContainerCreateDto request = ContainerCreateDto.builder()
+        final CreateContainerDto request = CreateContainerDto.builder()
                 .imageId(IMAGE_1_ID)
                 .name(CONTAINER_1_NAME)
                 .build();
@@ -68,7 +68,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void create_containerExists_fails() {
-        final ContainerCreateDto request = ContainerCreateDto.builder()
+        final CreateContainerDto request = CreateContainerDto.builder()
                 .imageId(IMAGE_1_ID)
                 .name(CONTAINER_1_NAME)
                 .build();
@@ -85,7 +85,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void create_imageNotFound_fails() {
-        final ContainerCreateDto request = ContainerCreateDto.builder()
+        final CreateContainerDto request = CreateContainerDto.builder()
                 .name(CONTAINER_3_NAME)
                 .imageId(9999L)
                 .build();
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java
index 182fe8e14ac5cd63ad1752fec07ee9b511ba8726..b77bc30d3811ed30c7994129ae2110e12903d0f9 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java
@@ -1,20 +1,20 @@
 package at.tuwien.service;
 
+import at.tuwien.api.datacite.DataCiteBody;
+import at.tuwien.api.datacite.doi.DataCiteDoi;
 import at.tuwien.api.identifier.BibliographyTypeDto;
+import at.tuwien.entities.database.Database;
 import at.tuwien.entities.identifier.Creator;
 import at.tuwien.entities.identifier.Identifier;
 import at.tuwien.entities.identifier.IdentifierStatusType;
 import at.tuwien.entities.identifier.NameIdentifierSchemeType;
+import at.tuwien.exception.*;
+import at.tuwien.gateway.SearchServiceGateway;
 import at.tuwien.repository.ContainerRepository;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.repository.LicenseRepository;
 import at.tuwien.repository.UserRepository;
 import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.datacite.DataCiteBody;
-import at.tuwien.api.datacite.doi.DataCiteDoi;
-import at.tuwien.entities.database.Database;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.SearchServiceGateway;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -141,7 +141,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
         when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)))
                 .thenReturn(mock);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         dataCiteIdentifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_DTO);
@@ -156,7 +156,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference));
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         assertThrows(MalformedException.class, () -> {
@@ -173,7 +173,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference));
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         assertThrows(DataServiceConnectionException.class, () -> {
@@ -332,7 +332,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
 
         /* mock */
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         dataCiteIdentifierService.delete(IDENTIFIER_1);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java
index 1b6570abd821337fe032bead021cf9d5a4b9fc8c..18d037fe452cb6cdab5b4d0f0fe68b5ed6142cf0 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java
@@ -110,7 +110,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.modifyImage(DATABASE_1, image);
@@ -164,7 +164,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.updateViewMetadata(DATABASE_1);
@@ -222,7 +222,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.updateViewMetadata(DATABASE_1);
@@ -240,7 +240,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.updateViewMetadata(DATABASE_1);
@@ -258,7 +258,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.updateTableMetadata(DATABASE_1);
@@ -276,7 +276,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.updateTableMetadata(DATABASE_1);
@@ -294,7 +294,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Database response = databaseService.updateTableMetadata(DATABASE_1);
@@ -517,7 +517,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
 
         /* mock */
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java
index 0c87dcdd692533cd751401f9be37fee69b5186cc..40fc28fe4d89524a928d474e0d3328853bee5df7 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java
@@ -176,7 +176,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
         when(dataServiceGateway.findQuery(IDENTIFIER_5_DATABASE_ID, IDENTIFIER_5_QUERY_ID))
                 .thenReturn(QUERY_2_DTO);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_2_DTO);
+                .thenReturn(DATABASE_2_BRIEF_DTO);
 
         /* test */
         identifierService.save(DATABASE_2, USER_2, IDENTIFIER_5_SAVE_DTO);
@@ -286,7 +286,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
 
         /* mock */
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         identifierService.delete(IDENTIFIER_1);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java
index 725d956f570e7ed6678047b4bb9d7baf85cbe33b..dc77ff263b37406845afb93e80a5afc27f59f380 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java
@@ -132,7 +132,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest {
         when(imageRepository.save(any()))
                 .thenReturn(IMAGE_1);
         when(mockImageService.update(IMAGE_1, request))
-                .thenReturn(CONTAINER_1_IMAGE);
+                .thenReturn(IMAGE_1);
 
         /* test */
         final ContainerImage response = mockImageService.update(IMAGE_1, request);
@@ -153,7 +153,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest {
         when(imageRepository.save(any()))
                 .thenReturn(IMAGE_1);
         when(mockImageService.update(IMAGE_1, request))
-                .thenReturn(CONTAINER_1_IMAGE);
+                .thenReturn(IMAGE_1);
 
         /* test */
         final ContainerImage response = mockImageService.update(IMAGE_1, request);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java
index 3126f9e9f42b36fb8dc09dfa3f8e60c88d851722..b0efccab9ac856f727ee3377554e7cf8a01bb2c7 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java
@@ -1,9 +1,9 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.table.TableCreateDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
@@ -82,22 +82,22 @@ public class TableServicePersistenceTest extends AbstractUnitTest {
     @Transactional
     public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("New Table")
                 .description("A wonderful table")
                 .isPublic(true)
                 .isSchemaPublic(true)
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                                 .name("id")
                                 .nullAllowed(false)
                                 .type(ColumnTypeDto.BIGINT)
                                 .build(),
-                        ColumnCreateDto.builder()
+                        CreateTableColumnDto.builder()
                                 .name("date")
                                 .nullAllowed(true)
                                 .type(ColumnTypeDto.DATE)
                                 .build()))
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .checks(Set.of())
                         .uniques(List.of(List.of("date")))
                         .foreignKeys(List.of())
@@ -112,7 +112,7 @@ public class TableServicePersistenceTest extends AbstractUnitTest {
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, request);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, request, USER_1_PRINCIPAL);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
index d975e808e3dd03e3b4fd0f27d3af4b60f4fec7a1..8cb5081f6d98b68971f71f2da5538ab72bd772a8 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java
@@ -1,13 +1,13 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableStatisticDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnStatisticDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
+import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
@@ -135,7 +135,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         tableService.updateStatistics(TABLE_8);
@@ -224,7 +224,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request);
@@ -256,7 +256,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request);
@@ -275,11 +275,11 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(USER_1);
         doNothing()
                 .when(dataServiceGateway)
-                .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class));
+                .createTable(eq(DATABASE_1_ID), any(CreateTableDto.class));
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL);
@@ -291,15 +291,15 @@ public class TableServiceUnitTest extends AbstractUnitTest {
             DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException,
             TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException,
             OntologyNotFoundException, SemanticEntityNotFoundException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("New Table")
                 .description("A wonderful table")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("I Am Späshül")
                         .nullAllowed(true)
                         .type(ColumnTypeDto.TEXT)
                         .build()))
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .checks(Set.of())
                         .uniques(List.of(List.of("I Am Späshül")))
                         .foreignKeys(List.of())
@@ -312,11 +312,11 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(USER_1);
         doNothing()
                 .when(dataServiceGateway)
-                .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class));
+                .createTable(eq(DATABASE_1_ID), any(CreateTableDto.class));
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, request, USER_1_PRINCIPAL);
@@ -344,15 +344,15 @@ public class TableServiceUnitTest extends AbstractUnitTest {
     public void createTable_dateFormatNotFound_fails() throws DataServiceException, DataServiceConnectionException,
             UserNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException,
             SearchServiceConnectionException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name("New Table")
                 .description("A wonderful table")
-                .columns(List.of(ColumnCreateDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .name("date")
                         .nullAllowed(true)
                         .type(ColumnTypeDto.DATE)
                         .build()))
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .checks(Set.of())
                         .uniques(List.of(List.of("date")))
                         .foreignKeys(List.of())
@@ -365,11 +365,11 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(USER_1);
         doNothing()
                 .when(dataServiceGateway)
-                .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class));
+                .createTable(eq(DATABASE_1_ID), any(CreateTableDto.class));
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         assertThrows(MalformedException.class, () -> {
@@ -392,7 +392,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, TABLE_3_CREATE_DTO);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL);
@@ -413,7 +413,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, TABLE_5_CREATE_DTO);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         assertThrows(DataServiceException.class, () -> {
@@ -423,11 +423,11 @@ public class TableServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void createTable_primaryKeyMalformed_fails() throws UserNotFoundException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name(TABLE_5_NAME)
                 .description(TABLE_5_DESCRIPTION)
                 .columns(TABLE_5_COLUMNS_CREATE)
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .foreignKeys(new LinkedList<>())
                         .checks(new LinkedHashSet<>())
                         .primaryKey(Set.of("i_do_not_exist"))
@@ -447,11 +447,11 @@ public class TableServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void createTable_uniquesMalformed_fails() throws UserNotFoundException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name(TABLE_5_NAME)
                 .description(TABLE_5_DESCRIPTION)
                 .columns(TABLE_5_COLUMNS_CREATE)
-                .constraints(ConstraintsCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
                         .foreignKeys(new LinkedList<>())
                         .checks(new LinkedHashSet<>())
                         .primaryKey(new LinkedHashSet<>())
@@ -473,12 +473,12 @@ public class TableServiceUnitTest extends AbstractUnitTest {
 
     @Test
     public void createTable_foreignKeyMalformed_fails() throws UserNotFoundException {
-        final TableCreateDto request = TableCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
                 .name(TABLE_5_NAME)
                 .description(TABLE_5_DESCRIPTION)
                 .columns(TABLE_5_COLUMNS_CREATE)
-                .constraints(ConstraintsCreateDto.builder()
-                        .foreignKeys(List.of(ForeignKeyCreateDto.builder()
+                .constraints(CreateTableConstraintsDto.builder()
+                        .foreignKeys(List.of(CreateForeignKeyDto.builder()
                                 .columns(List.of("some_column"))
                                 .referencedColumns(List.of("some_foreign_column"))
                                 .referencedTable("some_referenced_table")
@@ -511,7 +511,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .when(dataServiceGateway)
                 .deleteTable(DATABASE_1_ID, TABLE_1_ID);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         tableService.deleteTable(TABLE_1);
@@ -527,7 +527,7 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .when(dataServiceGateway)
                 .deleteTable(DATABASE_1_ID, TABLE_4_ID);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         tableService.deleteTable(TABLE_4);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java
index 09a372a6eb3ca23bb0539b8a1be4a648a1bff9a1..e9d6b158ce097fc469694ee1d09e068357120d39 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java
@@ -1,12 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.EmailExistsException;
-import at.tuwien.exception.UserExistsException;
-import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.exception.*;
+import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.repository.UserRepository;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
@@ -15,12 +13,14 @@ 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.boot.test.mock.mockito.MockBean;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.doNothing;
 
 @Log4j2
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@@ -34,6 +34,9 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
     @Autowired
     private UserService userService;
 
+    @MockBean
+    private KeycloakGateway keycloakGateway;
+
     @BeforeEach
     public void beforeEach() {
         genesis();
@@ -68,20 +71,16 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws UserExistsException, UserNotFoundException, EmailExistsException {
-        final SignupRequestDto request = SignupRequestDto.builder()
-                .username(USER_2_USERNAME)
-                .password(USER_2_PASSWORD)
-                .email(USER_2_EMAIL)
-                .build();
+    public void create_succeeds() throws UserExistsException, UserNotFoundException, EmailExistsException,
+            AuthServiceException, AuthServiceConnectionException {
 
         /* test */
-        final User response = userService.create(request, USER_2_ID);
+        final User response = userService.create(USER_2_SIGNUP_REQUEST_DTO);
         assertEquals(USER_2_USERNAME, response.getUsername());
     }
 
     @Test
-    public void modify_succeeds() {
+    public void modify_succeeds() throws UserNotFoundException, AuthServiceException {
         final UserUpdateDto request = UserUpdateDto.builder()
                 .firstname(USER_1_FIRSTNAME)
                 .lastname(USER_1_LASTNAME)
@@ -91,6 +90,11 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
                 .language("de")
                 .build();
 
+        /* mock */
+        doNothing()
+                .when(keycloakGateway)
+                .updateUser(USER_1_ID, request);
+
         /* test */
         final User response = userService.modify(USER_1, request);
         assertEquals(USER_1_ID, response.getId());
@@ -103,17 +107,14 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePassword_succeeds() {
+    public void updatePassword_succeeds() throws UserNotFoundException, AuthServiceException,
+            AuthServiceConnectionException {
         final UserPasswordDto request = UserPasswordDto.builder()
                 .password(USER_3_PASSWORD)
                 .build();
 
         /* mock */
-        final User user = userService.create(SignupRequestDto.builder()
-                .username(USER_3_USERNAME)
-                .password(USER_3_PASSWORD)
-                .email(USER_3_EMAIL)
-                .build(), USER_3_ID);
+        final User user = userService.create(USER_3_SIGNUP_REQUEST_DTO);
 
         /* test */
         userService.updatePassword(user, request);
@@ -151,20 +152,4 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
             userService.validateUsernameNotExists(USER_1_USERNAME);
         });
     }
-
-    @Test
-    public void validateEmailNotExists_succeeds() throws EmailExistsException {
-
-        /* test */
-        userService.validateEmailNotExists(USER_2_EMAIL);
-    }
-
-    @Test
-    public void validateEmailNotExists_fails() {
-
-        /* test */
-        assertThrows(EmailExistsException.class, () -> {
-            userService.validateEmailNotExists(USER_1_EMAIL);
-        });
-    }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
index a9fe4694cc69d8eb347e9fefd12498704b8797fd..4c423aa25b6fd36f82485d836c190c1b2779e12d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
@@ -1,10 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.repository.UserRepository;
+import at.tuwien.test.AbstractUnitTest;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -86,20 +86,15 @@ public class UserServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(Optional.of(USER_1));
         when(userRepository.save(any(User.class)))
                 .thenReturn(USER_1);
-        doNothing()
-                .when(keycloakGateway)
-                .createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        when(keycloakGateway.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
 
         /* test */
-        final User response = userService.create(USER_1_SIGNUP_REQUEST_DTO, USER_1_ID);
+        final User response = userService.create(USER_1_SIGNUP_REQUEST_DTO);
         assertEquals(USER_1_ID, response.getId());
         assertEquals(USER_1_USERNAME, response.getUsername());
     }
 
     @Test
-    public void modify_succeeds() {
+    public void modify_succeeds() throws UserNotFoundException, AuthServiceException {
 
         /* mock */
         when(userRepository.findById(USER_1_ID))
@@ -114,8 +109,7 @@ public class UserServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePassword_succeeds() throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
+    public void updatePassword_succeeds() throws UserNotFoundException {
 
         /* mock */
         doNothing()
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java
index 8ca002472a085a58ea5ee58fff8a2a0614c94fd9..57a84965dc81615613f201e6aee4e771582ac090 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java
@@ -89,7 +89,7 @@ public class ViewServicePersistenceTest extends AbstractUnitTest {
                 .when(dataServiceGateway)
                 .deleteView(DATABASE_1_ID, VIEW_1_ID);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         viewService.delete(VIEW_1);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java
index cd9fe03c655d33b014239af4f05f0f0ae9b6d1e9..4ba217a60c0b5a520e7fcd1c59a610769530760e 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java
@@ -2,7 +2,7 @@ package at.tuwien.service;
 
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.database.ViewCreateDto;
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.View;
 import at.tuwien.exception.*;
@@ -50,7 +50,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
     @Test
     public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
-        final ViewCreateDto request = ViewCreateDto.builder()
+        final CreateViewDto request = CreateViewDto.builder()
                 .name(VIEW_1_NAME)
                 .query(VIEW_1_QUERY)
                 .isPublic(VIEW_1_PUBLIC)
@@ -62,7 +62,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         final View response = viewService.create(DATABASE_1, USER_1, request);
@@ -117,7 +117,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
         when(searchServiceGateway.update(any(Database.class)))
-                .thenReturn(DATABASE_1_DTO);
+                .thenReturn(DATABASE_1_BRIEF_DTO);
 
         /* test */
         viewService.delete(VIEW_1);
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
index f5ad18b694081ed50b879d6690e2a85748b3bece..b3612fcc0fc306892db006bd12aa6ef483cf45a9 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
@@ -1,34 +1,71 @@
 package at.tuwien.utils;
 
-import at.tuwien.exception.AuthServiceConnectionException;
-import at.tuwien.exception.AuthServiceException;
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.config.KeycloakConfig;
 import at.tuwien.exception.UserNotFoundException;
-import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.mapper.MetadataMapper;
+import jakarta.ws.rs.core.Response;
 import lombok.extern.log4j.Log4j2;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
 import java.util.UUID;
 
 @Log4j2
 @Component
 public class KeycloakUtils {
 
-    final static UUID realmId = UUID.fromString("82c39861-d877-4667-a0f3-4daa2ee230e0");
-
-    private final KeycloakGateway keycloakGateway;
+    private final Keycloak keycloak;
+    private final KeycloakConfig keycloakConfig;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public KeycloakUtils(KeycloakGateway keycloakGateway) {
-        this.keycloakGateway = keycloakGateway;
+    public KeycloakUtils(Keycloak keycloak, KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
+        this.keycloak = keycloak;
+        this.keycloakConfig = keycloakConfig;
+        this.metadataMapper = metadataMapper;
+    }
+
+    public void createUser(UUID ldapId, UserCreateDto data) {
+        final UserRepresentation user = metadataMapper.userCreateDtoToUserRepresentation(data);
+        user.singleAttribute("CUSTOM_ID", ldapId.toString());
+        try (Response response = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .create(user)) {
+            if (response.getStatus() != 201) {
+                log.warn("Failed to create user: {}", response.getStatus());
+            }
+        }
+        log.debug("Created user {} at auth service", data.getUsername());
     }
 
-    public void deleteUser(String username) throws AuthServiceException, AuthServiceConnectionException {
-        try {
-            final UUID userId = keycloakGateway.findByUsername(username).getId();
-            keycloakGateway.deleteUser(userId);
-        } catch (UserNotFoundException e) {
-            /* ignore */
+    public UUID getUserId(String username) throws UserNotFoundException {
+        final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .search(username);
+        if (users.isEmpty()) {
+            throw new UserNotFoundException("Failed to find user: " + username);
+        }
+        return UUID.fromString(users.get(0).getId());
+    }
+
+    public void deleteUser(String username) {
+        final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .search(username);
+        if (users.isEmpty()) {
+            log.warn("Failed to find user");
+            return;
+        }
+        try (Response response = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .delete(users.get(0).getId())) {
+            if (response.getStatus() != 200) {
+                log.error("Failed to delete user: {}", response.getStatus());
+            }
         }
     }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
index 342a9e328ecc8e69abe7bfedf1827bdc7777fff3..486db28e5945737e776da4b8f0aaf6d6d977715e 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
@@ -1,9 +1,9 @@
 package at.tuwien.validator;
 
 import at.tuwien.SortType;
-import at.tuwien.api.database.table.TableCreateDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
@@ -70,6 +70,14 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         endpointValidator.validateDataParams(0L, 1L);
     }
 
+    @Test
+    public void validateOnlyAccess_system_succeeds() throws UserNotFoundException, NotAllowedException,
+            AccessNotFoundException {
+
+        /* test */
+        endpointValidator.validateOnlyAccess(DATABASE_1, USER_LOCAL_ADMIN_PRINCIPAL, false);
+    }
+
     @Test
     public void validateDataParams_bothNull_succeeds() throws PaginationException {
 
@@ -222,6 +230,20 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         endpointValidator.validateOnlyAccessOrPublic(DATABASE_1, USER_1_PRINCIPAL);
     }
 
+    @Test
+    public void validateOnlyWriteOwnOrWriteAllAccess_succeeds() throws DatabaseNotFoundException,
+            TableNotFoundException, AccessNotFoundException, NotAllowedException {
+
+        /* mock */
+        when(tableService.findById(DATABASE_1, TABLE_1_ID))
+                .thenReturn(TABLE_1);
+        when(accessService.find(eq(DATABASE_1), any(User.class)))
+                .thenReturn(DATABASE_1_USER_1_WRITE_ALL_ACCESS);
+
+        /* test */
+        endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(TABLE_1, USER_1);
+    }
+
     @Test
     public void validateOnlyWriteOwnOrWriteAllAccess_privateHasReadAccess_fails() throws DatabaseNotFoundException,
             TableNotFoundException, AccessNotFoundException {
@@ -264,8 +286,8 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
     @ParameterizedTest
     @MethodSource("needSize_parameters")
     public void validateColumnCreateConstraints_needSize_fails(ColumnTypeDto type) {
-        final TableCreateDto request = TableCreateDto.builder()
-                .columns(List.of(ColumnCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .type(type)
                         .size(null) // <<<<<<
                         .build()))
@@ -279,8 +301,8 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
 
     @Test
     public void validateColumnCreateConstraints_needEnum_fails() {
-        final TableCreateDto request = TableCreateDto.builder()
-                .columns(List.of(ColumnCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .type(ColumnTypeDto.ENUM)
                         .enums(null) // <<<<<<<
                         .build()))
@@ -294,8 +316,8 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
 
     @Test
     public void validateColumnCreateConstraints_needSet_fails() {
-        final TableCreateDto request = TableCreateDto.builder()
-                .columns(List.of(ColumnCreateDto.builder()
+        final CreateTableDto request = CreateTableDto.builder()
+                .columns(List.of(CreateTableColumnDto.builder()
                         .type(ColumnTypeDto.SET)
                         .sets(null) // <<<<<<<
                         .build()))
@@ -323,6 +345,20 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    public void validateOnlyPrivateDataHasRole_publicDatabase_succeeds() throws NotAllowedException {
+
+        /* test */
+        endpointValidator.validateOnlyPrivateDataHasRole(DATABASE_4, null, "nobody-role");
+    }
+
+    @Test
+    public void validateOnlyPrivateDataHasRole_privateDatabaseHasRole_succeeds() throws NotAllowedException {
+
+        /* test */
+        endpointValidator.validateOnlyPrivateDataHasRole(DATABASE_1, USER_1_PRINCIPAL, "find-database");
+    }
+
     @Test
     public void validateOnlyPrivateDataHasRole_privatePrincipalMissing_fails() {
 
@@ -491,6 +527,13 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         assertTrue(endpointValidator.validatePublicationDate(request));
     }
 
+    @Test
+    public void validateOnlyMineOrWriteAccessOrHasRole_succeeds() {
+
+        /* test */
+        assertTrue(endpointValidator.validateOnlyMineOrWriteAccessOrHasRole(USER_1, USER_1_PRINCIPAL, null, "find-database"));
+    }
+
     @Test
     public void validateOnlyMineOrWriteAccessOrHasRole_noAccess_fails() {
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
index 7ee28b34a4f2d662bb43979930732dec74da8a63..fb6df2007f2c5d50ab9ad744b622e248ea158cde 100644
--- a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
@@ -27,7 +27,7 @@
   "oauth2DevicePollingInterval" : 5,
   "enabled" : true,
   "sslRequired" : "none",
-  "registrationAllowed" : false,
+  "registrationAllowed" : true,
   "registrationEmailAsUsername" : false,
   "rememberMe" : false,
   "verifyEmail" : true,
@@ -38,6 +38,7 @@
   "bruteForceProtected" : false,
   "permanentLockout" : false,
   "maxTemporaryLockouts" : 0,
+  "bruteForceStrategy" : "MULTIPLE",
   "maxFailureWaitSeconds" : 900,
   "minimumQuickLoginWaitSeconds" : 60,
   "waitIncrementSeconds" : 60,
@@ -73,7 +74,7 @@
       "description" : "${default-system-roles}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-database-view-data", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
+        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "check-foreign-database-access", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -146,19 +147,11 @@
       "description" : "${default-table-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ]
+        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table", "update-table" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
-    }, {
-      "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3",
-      "name" : "view-database-view-data",
-      "description" : "${view-database-view-data}",
-      "composite" : false,
-      "clientRole" : false,
-      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
-      "attributes" : { }
     }, {
       "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44",
       "name" : "create-database-view",
@@ -219,7 +212,7 @@
       "description" : "${default-researcher-roles}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ]
+        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling", "default-view-handling" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -264,6 +257,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "22449528-00c9-4e86-9400-4b8ae6fd8f4d",
+      "name" : "modify-view-visibility",
+      "description" : "${modify-view-visibility}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6",
       "name" : "create-ontology",
@@ -296,6 +297,17 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "d75e7938-9d5e-4cb3-8c57-18a446867d3a",
+      "name" : "default-view-handling",
+      "description" : "${default-view-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "update-database-view", "create-database-view", "modify-view-visibility", "find-database-view", "list-database-views" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b",
       "name" : "create-container",
@@ -390,17 +402,33 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "6ae766b0-b8b4-4067-a95d-c8576bc4ac77",
+      "name" : "update-table",
+      "description" : "${update-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb",
       "name" : "default-query-handling",
       "description" : "${default-query-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-database-view-data", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
+        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "b05e9b2b-748d-490b-949b-e78655bf7805",
+      "name" : "check-foreign-database-access",
+      "description" : "${check-foreign-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "c047d521-cec3-4444-86c4-aef098489b7b",
       "name" : "delete-maintenance-message",
@@ -409,6 +437,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "df20b7d1-8d30-4a99-80eb-e8195fab0e76",
+      "name" : "update-database-view",
+      "description" : "${update-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "88f82262-be80-4d18-9fb4-5529da031f33",
       "name" : "system",
@@ -522,7 +558,7 @@
       "description" : "${default-container-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "find-container", "list-containers" ]
+        "realm" : [ "find-container" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -902,7 +938,7 @@
         "composite" : true,
         "composites" : {
           "client" : {
-            "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ]
+            "realm-management" : [ "query-realms", "manage-authorization", "manage-identity-providers", "view-identity-providers", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "create-client", "query-groups", "impersonation", "manage-clients", "manage-events", "view-events", "manage-realm" ]
           }
         },
         "clientRole" : true,
@@ -1203,12 +1239,13 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
     "fullScopeAllowed" : false,
     "nodeReRegistrationTimeout" : 0,
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   }, {
     "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96",
@@ -1233,6 +1270,7 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
@@ -1247,7 +1285,7 @@
       "consentRequired" : false,
       "config" : { }
     } ],
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   }, {
     "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6",
@@ -1270,12 +1308,14 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
+      "client.use.lightweight.access.token.enabled" : "true",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
-    "fullScopeAllowed" : false,
+    "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : 0,
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   }, {
     "id" : "88694c91-753d-4c44-9740-ec9ac06bba45",
@@ -1298,6 +1338,7 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "true",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -1331,6 +1372,7 @@
     "frontchannelLogout" : true,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "oidc.ciba.grant.enabled" : "false",
       "client.secret.creation.time" : "1680085365",
       "backchannel.logout.session.required" : "true",
@@ -1342,6 +1384,38 @@
     "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : -1,
     "protocolMappers" : [ {
+      "id" : "266edf62-a19a-483b-b594-81428e4af792",
+      "name" : "orcid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "ORCID",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "orcid",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "1a21798a-38b6-4df5-89f0-86942415246f",
+      "name" : "theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "THEME",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "theme",
+        "jsonType.label" : "String"
+      }
+    }, {
       "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
       "name" : "preferred_username",
       "protocol" : "openid-connect",
@@ -1355,27 +1429,77 @@
         "userinfo.token.claim" : "true"
       }
     }, {
-      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
-      "name" : "aud",
+      "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a",
+      "name" : "affiliation",
       "protocol" : "openid-connect",
-      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "dbrepo",
+        "introspection.token.claim" : "true",
         "userinfo.token.claim" : "true",
+        "user.attribute" : "AFFILIATION",
         "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
-        "claim.name" : "aud",
-        "access.tokenResponse.claim" : "false"
+        "claim.name" : "affiliation",
+        "jsonType.label" : "String"
       }
     }, {
-      "id" : "0b4c644f-0cf0-4794-8395-d5d83009dabe",
+      "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88",
+      "name" : "language",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "LANGUAGE",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "language",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
       "name" : "uid",
       "protocol" : "openid-connect",
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
+        "aggregate.attrs" : "false",
         "introspection.token.claim" : "true",
+        "multivalued" : "false",
         "userinfo.token.claim" : "true",
         "user.attribute" : "CUSTOM_ID",
         "id.token.claim" : "true",
@@ -1384,9 +1508,26 @@
         "claim.name" : "uid",
         "jsonType.label" : "String"
       }
+    }, {
+      "id" : "c304ed2f-5952-4772-838d-91998a45f154",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "claim.value" : "account",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "jsonType.label" : "String",
+        "access.tokenResponse.claim" : "false"
+      }
     } ],
-    "defaultClientScopes" : [ "roles", "attributes" ],
-    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+    "defaultClientScopes" : [ "roles", "basic" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
     "clientId" : "rabbitmq-client",
@@ -1413,6 +1554,7 @@
     "frontchannelLogout" : true,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "oidc.ciba.grant.enabled" : "false",
       "client.secret.creation.time" : "1680000860",
       "backchannel.logout.session.required" : "true",
@@ -1430,12 +1572,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "false",
         "user.attribute" : "username",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "client_id",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "false"
       }
     }, {
       "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
@@ -1444,15 +1586,15 @@
       "protocolMapper" : "oidc-hardcoded-claim-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "rabbitmq",
-        "userinfo.token.claim" : "false",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "aud",
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
         "access.tokenResponse.claim" : "false"
       }
     } ],
-    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management", "basic" ],
     "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
@@ -1475,6 +1617,7 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "true",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -1505,11 +1648,13 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
+      "client.use.lightweight.access.token.enabled" : "true",
       "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
     "authenticationFlowBindingOverrides" : { },
-    "fullScopeAllowed" : false,
+    "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : 0,
     "protocolMappers" : [ {
       "id" : "c4d54410-3f22-4259-9571-94da2c43b752",
@@ -1518,15 +1663,15 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ],
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   } ],
   "clientScopes" : [ {
@@ -1547,8 +1692,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${emailScopeConsentText}"
+      "consent.screen.text" : "${emailScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
@@ -1557,12 +1702,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "emailVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
@@ -1571,12 +1716,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "email",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1586,8 +1731,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${profileScopeConsentText}"
+      "consent.screen.text" : "${profileScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
@@ -1596,12 +1741,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "preferred_username",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
@@ -1610,12 +1755,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "gender",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "gender",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
@@ -1624,12 +1769,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "birthdate",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "birthdate",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
@@ -1649,12 +1794,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "profile",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "profile",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
@@ -1663,12 +1808,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "updatedAt",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "updated_at",
-        "jsonType.label" : "long"
+        "jsonType.label" : "long",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "841ea785-26ab-429a-a420-09ce3948924d",
@@ -1677,12 +1822,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "lastName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "family_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
@@ -1691,12 +1836,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "website",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "website",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "475f071d-5149-4379-b928-76482f5f519c",
@@ -1705,12 +1850,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "zoneinfo",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "zoneinfo",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
@@ -1719,12 +1864,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "middleName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "middle_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
@@ -1733,12 +1878,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "picture",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "picture",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
@@ -1747,12 +1892,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
@@ -1761,12 +1906,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "firstName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "given_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
@@ -1775,12 +1920,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "nickname",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "nickname",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1814,12 +1959,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "upn",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1861,8 +2006,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${phoneScopeConsentText}"
+      "consent.screen.text" : "${phoneScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
@@ -1871,12 +2016,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumber",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
@@ -1885,12 +2030,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumberVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1900,8 +2045,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "false",
-      "consent.screen.text" : ""
+      "consent.screen.text" : "",
+      "display.on.consent.screen" : "false"
     },
     "protocolMappers" : [ {
       "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
@@ -1981,6 +2126,61 @@
       "gui.order" : "",
       "consent.screen.text" : ""
     }
+  }, {
+    "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6",
+    "name" : "service_account",
+    "description" : "Specific scope for a client enabled for service accounts",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512",
+      "name" : "Client IP Address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientAddress",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientAddress",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a",
+      "name" : "Client Host",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientHost",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientHost",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae",
+      "name" : "Client ID",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "client_id",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    } ]
   }, {
     "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
     "name" : "offline_access",
@@ -1997,8 +2197,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${addressScopeConsentText}"
+      "consent.screen.text" : "${addressScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
@@ -2029,6 +2229,41 @@
       "gui.order" : "",
       "consent.screen.text" : ""
     }
+  }, {
+    "id" : "ba11267a-478b-4b32-872f-4eb2d125d116",
+    "name" : "basic",
+    "description" : "OpenID Connect scope for add all basic claims to the token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "1445e14f-49b0-4666-8ddc-691493c24ad9",
+      "name" : "sub",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-sub-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "access.token.claim" : "true"
+      }
+    }, {
+      "id" : "846f1ef0-2b86-4e07-9d25-691d25af5fce",
+      "name" : "auth_time",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "AUTH_TIME",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "auth_time",
+        "jsonType.label" : "long"
+      }
+    } ]
   }, {
     "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc",
     "name" : "roles",
@@ -2036,8 +2271,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${rolesScopeConsentText}"
+      "consent.screen.text" : "${rolesScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
@@ -2053,11 +2288,15 @@
       "protocolMapper" : "oidc-usermodel-realm-role-mapper",
       "consentRequired" : false,
       "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "false",
+        "multivalued" : "true",
         "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "realm_access.roles",
-        "jsonType.label" : "String",
-        "multivalued" : "true"
+        "jsonType.label" : "String"
       }
     }, {
       "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
@@ -2074,7 +2313,7 @@
       }
     } ]
   } ],
-  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ],
+  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management", "basic" ],
   "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ],
   "browserSecurityHeaders" : {
     "contentSecurityPolicyReportOnly" : "",
@@ -2087,6 +2326,10 @@
     "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
   },
   "smtpServer" : { },
+  "loginTheme" : "keycloak",
+  "accountTheme" : "",
+  "adminTheme" : "",
+  "emailTheme" : "",
   "eventsEnabled" : false,
   "eventsListeners" : [ "jboss-logging" ],
   "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
@@ -2136,7 +2379,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2162,11 +2405,11 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper" ]
       }
     } ],
     "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "fb763636-e1ea-49c7-adca-ea105cdec4ad",
+      "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
       "providerId" : "declarative-user-profile",
       "subComponents" : { },
       "config" : {
@@ -2185,17 +2428,6 @@
         "priority" : [ "100" ],
         "algorithm" : [ "RSA-OAEP" ]
       }
-    }, {
-      "id" : "230cb681-9ceb-4b1b-8a4c-929a11b08de0",
-      "name" : "hmac-generated-hs512",
-      "providerId" : "hmac-generated",
-      "subComponents" : { },
-      "config" : {
-        "kid" : [ "8a489935-9a95-459b-9059-59b438ef0fa8" ],
-        "secret" : [ "xSCVgBlrLPWoF54gKQdR7BqXlfNaCD43xtS_ZgQRC0tGNAbqhy2Q9y8LdD2IR7K__8VGaDGYtyZayopgTebhDBb4gHDjDOBX7flhFYRrm0G3aTIuCIyFG-bPULwmyP_oHeC6tjwdQhqx5G0tE2mQQqPC9dDZuUA5I7QREIGK8cI" ],
-        "priority" : [ "100" ],
-        "algorithm" : [ "HS512" ]
-      }
     }, {
       "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30",
       "name" : "aes-generated",
@@ -2212,8 +2444,8 @@
       "providerId" : "hmac-generated",
       "subComponents" : { },
       "config" : {
-        "kid" : [ "5034d264-cb50-4006-a59e-2ce636eb5f38" ],
-        "secret" : [ "ToVIw-a4IE-Yp9JpP8ztb8NAICYO8CT3tUiDPT6DdiBcgzKJ9Ym9vspxGVdmPceX3mAgbnGLAcTx1PkInSVrbZs-tX9QXFwdlyGbewhKiNpH8wEg32Wk4GuUDpTv8JCsymgWyQBY681jvIMv05eCoK2QWpqCzcgP828KM5peCzo" ],
+        "kid" : [ "7f9f9054-5697-4f60-bdc8-67e3bd0f4db6" ],
+        "secret" : [ "1SCIY20z3AbAHCL28LuJfBU-7zfsZv5dacgliUeGdRW_WK3vH9fJUpPu1f7iDrdlhF7YQmHxLXsWjxhQId4ShI7QBdgKCArHWqi0GeH37oNXfZFg_uv-K_3JSfxfGBRu5jpRQhhSBxESZWsFVkskhxWUvNe6b5l9dFbMIif72rI" ],
         "priority" : [ "100" ],
         "algorithm" : [ "HS256" ]
       }
@@ -2228,12 +2460,23 @@
         "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ],
         "priority" : [ "100" ]
       }
+    }, {
+      "id" : "addbae10-c6ae-4735-851f-7a5ea035ce25",
+      "name" : "hmac-generated-hs512",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "352d0ea1-8218-42b5-ab78-e2ca56cf6a95" ],
+        "secret" : [ "_kr6EZOZ8IKqPWgJltHAAsQ34wCIGPs8oOQLYWwJrSIH7Qie3CEVKZnICyBP1goR-QgUtg25tR8Qu5MkvYkb8assJ8Iok5x_8iYCR4Txkf_mS-emrlAtQajlIjmOfNBtx704dTnZlP9rWzqpW6mrpeiOaiCw1K0XCpY5C_ZjXKw" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS512" ]
+      }
     } ]
   },
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "88e5d526-2298-413c-a904-133ad839d47f",
+    "id" : "259dd7b6-01b7-433a-bda4-028857151ecd",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -2255,7 +2498,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a690c715-fbae-4c20-b680-bd4010718761",
+    "id" : "542ca1d7-9627-4102-b843-98837ce433fb",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2277,7 +2520,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad",
+    "id" : "4f153b98-6851-440b-a022-0a14e67a9b2f",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2299,7 +2542,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515",
+    "id" : "3d791b35-d35c-40b2-bb3e-e806d72b27ee",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2321,7 +2564,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523",
+    "id" : "9b746104-9371-4c3f-b69f-9322cead1b08",
     "alias" : "Handle Existing Account",
     "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
     "providerId" : "basic-flow",
@@ -2343,7 +2586,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "088f4051-36ab-4952-a4f2-4ba53c408083",
+    "id" : "7a164efe-c97b-4fbb-950d-7745359ba9a4",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2365,7 +2608,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4",
+    "id" : "4fdc5e1b-1b55-4662-8360-67d75fa22677",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2388,7 +2631,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4",
+    "id" : "75893341-c338-44d8-ae27-a3fc7bfe8f2d",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2410,7 +2653,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c",
+    "id" : "89626b76-f4cf-4c46-934c-4408c225a44b",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2446,7 +2689,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d",
+    "id" : "4112115a-e7a7-44c2-9af5-65d538e4ba0d",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2482,7 +2725,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63",
+    "id" : "f82a9b0a-2c0a-4cb1-96b2-6c78b0b1f14f",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2511,7 +2754,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781",
+    "id" : "3614e155-e8ce-4958-98fb-a27e4706cc70",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2526,7 +2769,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43",
+    "id" : "506f9b96-5002-47c0-96e3-3830a0fcfa26",
     "alias" : "first broker login",
     "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
     "providerId" : "basic-flow",
@@ -2549,7 +2792,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8",
+    "id" : "4b7a7e91-36db-4b27-8e2d-01a04a822980",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2571,7 +2814,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914",
+    "id" : "04c2fe01-5076-4aa4-9596-4efb4004195f",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2587,7 +2830,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "d62c8dd6-633c-408a-aa99-43071510efb4",
+    "id" : "d12f77e1-7733-44a2-98ff-fd75c784d721",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2616,7 +2859,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb",
+    "id" : "91f6048c-a376-4809-8f37-c8d7a517830c",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2652,7 +2895,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "389c1c37-e8af-4610-a507-e1257f55b954",
+    "id" : "7b8fb487-53b8-4533-a696-76bc05256cb1",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2668,13 +2911,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4",
+    "id" : "48372696-0579-45e5-b074-5e8dbdbbe7d6",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d",
+    "id" : "08df3b83-e522-42a7-9e24-9028b960bf39",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
@@ -2785,10 +3028,12 @@
     "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
     "parRequestUriLifespan" : "60",
     "clientSessionMaxLifespan" : "0",
+    "organizationsEnabled" : "false",
     "shortVerificationUri" : ""
   },
-  "keycloakVersion" : "24.0.5",
+  "keycloakVersion" : "26.0.4",
   "userManagedAccessAllowed" : false,
+  "organizationsEnabled" : false,
   "clientProfiles" : {
     "profiles" : [ ]
   },
diff --git a/dbrepo-metadata-service/services/pom.xml b/dbrepo-metadata-service/services/pom.xml
index 2961f680d12220dbfbf6c91a7cf64797ff213bf3..d1b8f9a7026e77f2235c580f0149f4dac17df779 100644
--- a/dbrepo-metadata-service/services/pom.xml
+++ b/dbrepo-metadata-service/services/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-services</artifactId>
     <name>dbrepo-metadata-service-services</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
index b9fea2b54b1c242f58dbc0cd578e9dff328ba49c..d6535bad491b18744afecbe4fdc4792dfd3e7f33 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
@@ -1,7 +1,6 @@
 package at.tuwien.auth;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import jakarta.servlet.ServletException;
 import lombok.extern.log4j.Log4j2;
@@ -34,8 +33,7 @@ public class BasicAuthenticationProvider implements AuthenticationManager {
             final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken());
             log.debug("set basic auth principal: {}", userDetails);
             return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
-        } catch (ServletException | CredentialsInvalidException | AccountNotSetupException |
-                 AuthServiceConnectionException e) {
+        } catch (ServletException e) {
             throw new BadCredentialsException("Failed to authenticate with authentication service", e);
         }
     }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
index 835b7245d1ef2ca017375990dd77c20693f3ef6f..b0edc929ed0097ce94e65153707dc47406f0f3c9 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
@@ -2,9 +2,6 @@ package at.tuwien.auth;
 
 import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.config.GatewayConfig;
-import at.tuwien.exception.AccountNotSetupException;
-import at.tuwien.exception.AuthServiceConnectionException;
-import at.tuwien.exception.CredentialsInvalidException;
 import at.tuwien.gateway.KeycloakGateway;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.http.HttpHeaders;
@@ -33,15 +30,10 @@ public class InternalRequestInterceptor implements ClientHttpRequestInterceptor
             throws IOException {
         final HttpHeaders headers = request.getHeaders();
         headers.setAccept(List.of(MediaType.APPLICATION_JSON));
-        try {
-            final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(),
-                    gatewayConfig.getSystemPassword());
-            headers.setBearerAuth(token.getAccessToken());
-            log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername());
-            return execution.execute(request, body);
-        } catch (AuthServiceConnectionException | CredentialsInvalidException | AccountNotSetupException e) {
-            log.error("Failed to obtain token for internal user: {}", gatewayConfig.getSystemUsername());
-            throw new IOException("Failed to obtain token for internal user", e);
-        }
+        final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(),
+                gatewayConfig.getSystemPassword());
+        headers.setBearerAuth(token.getAccessToken());
+        log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername());
+        return execution.execute(request, body);
     }
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
index a24bbf41b8168b6e5c9ffef70c1b7bbbd6f5c674..4b62b61dcba2e06f9847d9eb20042b1f535bbc8d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
@@ -1,12 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
+import org.keycloak.admin.client.Keycloak;
 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
@@ -27,17 +26,15 @@ public class KeycloakConfig {
     @Value("${dbrepo.keycloak.clientSecret}")
     private String keycloakClientSecret;
 
+    private final String realm = "dbrepo";
+
     @Bean
     public RestTemplate restTemplate() {
         return new RestTemplate();
     }
 
-    @Bean("keycloakRestTemplate")
-    public RestTemplate brokerRestTemplate() {
-        final RestTemplate restTemplate = new RestTemplate();
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
-        restTemplate.getInterceptors()
-                .add(new KeycloakInterceptor(restTemplate(), keycloakUsername, keycloakPassword, keycloakEndpoint));
-        return restTemplate;
+    @Bean
+    public Keycloak keycloak() {
+        return Keycloak.getInstance(keycloakEndpoint, "master", keycloakUsername, keycloakPassword, "admin-cli");
     }
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java
index 976830cebbb17d0378ee6e4afedba30170507250..4ee76c36bf7adf98fe38a32fcab869759ec3af0a 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java
@@ -3,11 +3,11 @@ package at.tuwien.gateway;
 import at.tuwien.ExportResourceDto;
 import at.tuwien.api.database.AccessTypeDto;
 import at.tuwien.api.database.DatabaseDto;
-import at.tuwien.api.database.ViewCreateDto;
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.database.internal.CreateDatabaseDto;
 import at.tuwien.api.database.query.QueryDto;
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TableStatisticDto;
 import at.tuwien.api.database.table.TableUpdateDto;
@@ -94,7 +94,7 @@ public interface DataServiceGateway {
      * @throws DatabaseNotFoundException      Some of the privileged parameters of the given database were not provided by the metadata service.
      * @throws TableExistsException           A table with this internal name exists already in the database.
      */
-    void createTable(Long databaseId, TableCreateDto data) throws DataServiceConnectionException, DataServiceException,
+    void createTable(Long databaseId, CreateTableDto data) throws DataServiceConnectionException, DataServiceException,
             DatabaseNotFoundException, TableExistsException;
 
     /**
@@ -118,7 +118,7 @@ public interface DataServiceGateway {
      * @throws DataServiceConnectionException The connection to the data service could not be established.
      * @throws DataServiceException           The data service responded unexpectedly.
      */
-    ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException;
+    ViewDto createView(Long databaseId, CreateViewDto data) throws DataServiceConnectionException, DataServiceException;
 
     /**
      * Deletes a given view in the given database.
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
index 94ea986f78727a6fdc927b4e7ebb25ca6f0616bd..cd5fd08a7ef64e88134a1fc19aa0840ad1e98020 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
@@ -1,37 +1,26 @@
 package at.tuwien.gateway;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserCreateDto;
-import at.tuwien.api.keycloak.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
-import at.tuwien.exception.*;
+import at.tuwien.api.user.UserUpdateDto;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.UserNotFoundException;
+import org.keycloak.representations.idm.UserRepresentation;
 
 import java.util.UUID;
 
 public interface KeycloakGateway {
 
-    TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException,
-            CredentialsInvalidException, AccountNotSetupException;
+    TokenDto obtainUserToken(String username, String password);
 
-    TokenDto refreshUserToken(String refreshToken) throws AuthServiceConnectionException,
-            CredentialsInvalidException;
-
-    /**
-     * Creates a user at the Authentication Service with given credentials.
-     *
-     * @param data The user credentials.
-     * @throws UserExistsException      The user already exists at the Authentication Service.
-     * @throws EmailExistsException The user email already exists in the metadata database.
-     */
-    void createUser(UserCreateDto data) throws AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException, UserExistsException;
+    UserRepresentation findByUsername(String username) throws UserNotFoundException;
 
     /**
      * Deletes a user at the Authentication Service with given user id.
      *
      * @param id The user id.
      */
-    void deleteUser(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException;
+    void deleteUser(UUID id) throws UserNotFoundException;
 
     /**
      * Update the credentials for a given user.
@@ -39,17 +28,7 @@ public interface KeycloakGateway {
      * @param id       The user id.
      * @param password The user credential.
      */
-    void updateUserCredentials(UUID id, UserPasswordDto password) throws AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException;
-
-    /**
-     * Finds a user in the metadata database by given username.
-     *
-     * @param username The user username.
-     * @return The updated user.
-     */
-    UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException;
+    void updateUserCredentials(UUID id, UserPasswordDto password) throws UserNotFoundException;
 
-    UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException;
+    void updateUser(UUID id, UserUpdateDto data) throws AuthServiceException, UserNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java
index f5e2f49c02023fe9145f137089e4550c9ae5b769..6632a08194411f74d5b4d22d4f1e0de6eda91a47 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java
@@ -1,12 +1,12 @@
 package at.tuwien.gateway;
 
-import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.exception.*;
 
 public interface SearchServiceGateway {
 
-    DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException;
+    DatabaseBriefDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException;
 
     void delete(Long databaseId) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException;
 }
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 2b0cd72dda4c3896ae104e477d3f825dab0cb995..6ee2ef084b962e30bd614dd1073aecf65a0ced09 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
@@ -4,7 +4,7 @@ import at.tuwien.ExportResourceDto;
 import at.tuwien.api.database.*;
 import at.tuwien.api.database.internal.CreateDatabaseDto;
 import at.tuwien.api.database.query.QueryDto;
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TableStatisticDto;
 import at.tuwien.api.database.table.TableUpdateDto;
@@ -48,7 +48,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
         log.trace("create access at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path);
         try {
             response = restTemplate.exchange(path, HttpMethod.POST,
-                    new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class);
+                    new HttpEntity<>(CreateAccessDto.builder().type(access).build()), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to create access: {}", e.getMessage());
             throw new DataServiceConnectionException("Failed to create access: " + e.getMessage(), e);
@@ -73,7 +73,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
         log.trace("update access at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path);
         try {
             response = restTemplate.exchange(path, HttpMethod.PUT,
-                    new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class);
+                    new HttpEntity<>(CreateAccessDto.builder().type(access).build()), Void.class);
         } catch (HttpServerErrorException e) {
             log.error("Failed to update access: {}", e.getMessage());
             throw new DataServiceConnectionException("Failed to update access: " + e.getMessage(), e);
@@ -188,7 +188,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
     }
 
     @Override
-    public void createTable(Long databaseId, TableCreateDto data) throws DataServiceConnectionException, DataServiceException,
+    public void createTable(Long databaseId, CreateTableDto data) throws DataServiceConnectionException, DataServiceException,
             DatabaseNotFoundException, TableExistsException {
         final ResponseEntity<Void> response;
         final String path = "/api/database/" + databaseId + "/table";
@@ -239,7 +239,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway {
     }
 
     @Override
-    public ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException {
+    public ViewDto createView(Long databaseId, CreateViewDto data) throws DataServiceConnectionException, DataServiceException {
         final ResponseEntity<ViewDto> response;
         final String path = "/api/database/" + databaseId + "/view";
         log.trace("create view at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
index bce9d6e264b5283864c4e0ce4d2a157bd3d7dab4..af54651d6c36197e136134003291ea88f5df2a49 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
@@ -1,232 +1,128 @@
 package at.tuwien.gateway.impl;
 
-import at.tuwien.api.auth.KeycloakErrorDto;
-import at.tuwien.api.keycloak.*;
+import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.user.UserPasswordDto;
+import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.config.KeycloakConfig;
-import at.tuwien.exception.*;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.UserNotFoundException;
 import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.mapper.MetadataMapper;
+import jakarta.ws.rs.BadRequestException;
+import jakarta.ws.rs.ForbiddenException;
+import jakarta.ws.rs.NotFoundException;
+import jakarta.ws.rs.core.Response;
 import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.http.*;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.KeycloakBuilder;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.springframework.stereotype.Service;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
+import java.util.List;
 import java.util.UUID;
 
 @Log4j2
 @Service
 public class KeycloakGatewayImpl implements KeycloakGateway {
 
-    private final RestTemplate restTemplate;
-    private final RestTemplate keycloakRestTemplate;
+    private final Keycloak keycloak;
     private final KeycloakConfig keycloakConfig;
     private final MetadataMapper metadataMapper;
 
-    public KeycloakGatewayImpl(@Qualifier("restTemplate") RestTemplate restTemplate,
-                               @Qualifier("keycloakRestTemplate") RestTemplate keycloakRestTemplate,
-                               KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakConfig.getKeycloakEndpoint()));
-        this.restTemplate = restTemplate;
-        this.keycloakRestTemplate = keycloakRestTemplate;
+    public KeycloakGatewayImpl(Keycloak keycloak, KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
+        this.keycloak = keycloak;
         this.keycloakConfig = keycloakConfig;
         this.metadataMapper = metadataMapper;
     }
 
     @Override
-    public TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException,
-            CredentialsInvalidException, AccountNotSetupException {
-        final HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
-        final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
-        payload.add("username", username);
-        payload.add("password", password);
-        payload.add("grant_type", "password");
-        payload.add("scope", "openid roles");
-        payload.add("client_id", keycloakConfig.getKeycloakClient());
-        payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
-        final String path = "/realms/dbrepo/protocol/openid-connect/token";
-        log.trace("obtain user token at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<TokenDto> response;
-        try {
-            response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to obtain user token: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.BadRequest e) {
-            final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
-            if (error != null && error.getError().equals("invalid_grant")) {
-                log.error("Failed to obtain user token: {}", error.getErrorDescription());
-                throw new AccountNotSetupException(error.getErrorDescription());
-            }
-            log.error("Failed to obtain user token: bad request");
-            throw new CredentialsInvalidException("Bad request", e);
-        } catch (HttpClientErrorException.Unauthorized e) {
-            log.error("Failed to obtain user token: invalid credentials");
-            throw new CredentialsInvalidException("Invalid credentials", e);
+    public TokenDto obtainUserToken(String username, String password) {
+        try (Keycloak userKeycloak = KeycloakBuilder.builder()
+                .serverUrl(keycloakConfig.getKeycloakEndpoint())
+                .realm(keycloakConfig.getRealm())
+                .grantType(OAuth2Constants.PASSWORD)
+                .clientId(keycloakConfig.getKeycloakClient())
+                .clientSecret(keycloakConfig.getKeycloakClientSecret())
+                .username(username)
+                .password(password)
+                .build()) {
+            return metadataMapper.accessTokenResponseToTokenDto(userKeycloak.tokenManager()
+                    .getAccessToken());
         }
-        return response.getBody();
     }
 
     @Override
-    public TokenDto refreshUserToken(String refreshToken) throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-        final HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
-        final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
-        payload.add("refresh_token", refreshToken);
-        payload.add("grant_type", "refresh_token");
-        payload.add("client_id", keycloakConfig.getKeycloakClient());
-        payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
-        final String path = "/realms/dbrepo/protocol/openid-connect/token";
-        log.trace("refresh user token at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<TokenDto> response;
-        try {
-            response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to refresh user token: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.Unauthorized e) {
-            log.error("Failed to refresh user token: invalid credentials");
-            throw new CredentialsInvalidException("Invalid credentials", e);
-        } catch (HttpClientErrorException.BadRequest e) {
-            if (e.getMessage() != null && e.getMessage().contains("Session not active")) {
-                log.error("Failed to refresh user token: inactive session", e);
-                throw new CredentialsInvalidException("Inactive session", e);
-            }
-            log.error("Failed to refresh user token: unexpected response: {}", e.getMessage(), e);
-            throw new CredentialsInvalidException("Unexpected response: " + e.getMessage(), e);
+    public UserRepresentation findByUsername(String username) throws UserNotFoundException {
+        final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .search(username);
+        if (users.isEmpty()) {
+            log.error("Failed to find user with username {}", username);
+            throw new UserNotFoundException("Failed to find user");
         }
-        return response.getBody();
+        return users.get(0);
     }
 
     @Override
-    public void createUser(UserCreateDto data) throws AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException, UserExistsException {
-        final String path = "/admin/realms/dbrepo/users";
-        log.trace("create user at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<Void> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to create user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.Conflict e) {
-            if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) {
-                final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
-                if (error != null && error.getErrorMessage().contains("same email")) {
-                    log.error("Failed to create user: email exists: {}", e.getMessage());
-                    throw new EmailExistsException("E-Mail exists", e);
-                }
+    public void deleteUser(UUID id) throws UserNotFoundException {
+        try (Response response = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .delete(String.valueOf(id))) {
+            if (response.getStatus() == 404) {
+                log.error("Failed to delete user: not found");
+                throw new UserNotFoundException("Failed to delete user: not found");
             }
-            log.error("Failed to create user: user exists: {}", e.getMessage());
-            throw new UserExistsException("User exists", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
-            log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value());
-            throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value());
-        }
-        log.debug("Created user {} at auth service", data.getUsername());
-    }
-
-    @Override
-    public void deleteUser(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException {
-        final String path = "/admin/realms/dbrepo/users/" + id;
-        log.trace("delete user at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<Void> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to delete user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to delete user: user not found: {}", e.getMessage());
-            throw new UserNotFoundException("User not found", e);
-        } catch (Exception e) {
-            log.error("Failed to delete user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
-            log.error("Failed to delete user: unexpected response");
-            throw new AuthServiceException("Unexpected result");
         }
         log.info("Deleted user {} at auth service", id);
     }
 
     @Override
-    public void updateUserCredentials(UUID id, UserPasswordDto data) throws AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException {
-        final UpdateCredentialsDto payload = metadataMapper.passwordToUpdateCredentialsDto(data.getPassword());
-        final String path = "/admin/realms/dbrepo/users/" + id;
-        log.trace("update user credentials at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<Void> response;
+    public void updateUserCredentials(UUID id, UserPasswordDto data) throws UserNotFoundException {
+        final CredentialRepresentation credential = new CredentialRepresentation();
+        credential.setTemporary(false);
+        credential.setValue(data.getPassword());
+        credential.setType(CredentialRepresentation.PASSWORD);
         try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(payload), Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to update user credentials: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to update user credentials: user not found: {}", e.getMessage());
-            throw new UserNotFoundException("User not found", e);
-        } catch (Exception e) {
-            log.error("Failed to update user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
-            log.error("Failed to update user: unexpected status: {}", response.getStatusCode().value());
-            throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value());
+            keycloak.realm(keycloakConfig.getRealm())
+                    .users()
+                    .get(String.valueOf(id))
+                    .resetPassword(credential);
+        } catch (NotFoundException e) {
+            log.error("Failed to update user password: not found");
+            throw new UserNotFoundException("Failed to update user password: not found", e);
         }
         log.info("Updated user {} password at auth service", id);
     }
 
     @Override
-    public UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
-        final String path = "/admin/realms/dbrepo/users/?username=" + username;
-        log.trace("find user by username at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<UserDto[]> response;
+    public void updateUser(UUID id, UserUpdateDto data) throws AuthServiceException, UserNotFoundException {
+        final UserResource resource = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .get(String.valueOf(id));
+        UserRepresentation user;
         try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto[].class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to find user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (Exception e) {
-            log.error("Failed to find user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
+            user = resource.toRepresentation();
+        } catch (NotFoundException e) {
+            log.error("Failed to update user: not found: {}", e.getMessage());
+            throw new UserNotFoundException("Failed to update user: not found", e);
         }
-        final UserDto[] body = response.getBody();
-        if (body == null || body.length != 1) {
-            log.error("Failed to find user with username {}", username);
-            throw new UserNotFoundException("Failed to find user with username " + username);
-        }
-        return body[0];
-    }
-
-    @Override
-    public UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
-        final String path = "/admin/realms/dbrepo/users/" + id;
-        log.trace("find user by id at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<UserDto> response;
+        user.setFirstName(data.getFirstname());
+        user.setLastName(data.getLastname());
+        user.singleAttribute("THEME", data.getTheme());
+        user.singleAttribute("ORCID", data.getOrcid());
+        user.singleAttribute("LANGUAGE", data.getLanguage());
+        user.singleAttribute("AFFILIATION", data.getAffiliation());
+        log.trace("update user: {}", data);
         try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to find user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to find user: not found: {}", e.getMessage());
-            throw new UserNotFoundException("User not found");
-        } catch (Exception e) {
-            log.error("Failed to find user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
+            resource.update(user);
+        } catch (ForbiddenException e) {
+            log.error("Failed to update user: forbidden: {}", e.getMessage());
+            throw new AuthServiceException("Failed to update user: forbidden", e);
         }
-        return response.getBody();
+        log.info("Updated user {} attributes at auth service", id);
     }
 
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java
index 0f14b8d34826fe94829146f53a0cc22fb9e97333..503cad47ec5d2a8abd7ec4e76757b2f8ddb48ecd 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java
@@ -1,6 +1,6 @@
 package at.tuwien.gateway.impl;
 
-import at.tuwien.api.database.DatabaseDto;
+import at.tuwien.api.database.DatabaseBriefDto;
 import at.tuwien.config.GatewayConfig;
 import at.tuwien.entities.database.Database;
 import at.tuwien.exception.DatabaseNotFoundException;
@@ -35,8 +35,8 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway {
     }
 
     @Override
-    public DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException {
-        final ResponseEntity<DatabaseDto> response;
+    public DatabaseBriefDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException {
+        final ResponseEntity<DatabaseBriefDto> response;
         final HttpHeaders headers = new HttpHeaders();
         headers.set("Accept", "application/json");
         headers.set("Content-Type", "application/json");
@@ -44,7 +44,7 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway {
         log.trace("update database at endpoint {} with path {}", gatewayConfig.getSearchEndpoint(), path);
         try {
             response = restTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(
-                    metadataMapper.databaseToPrivilegedDatabaseDto(database), headers), DatabaseDto.class);
+                    metadataMapper.databaseToDatabaseDto(database), headers), DatabaseBriefDto.class);
         } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable |
                  HttpServerErrorException.InternalServerError e) {
             log.error("Failed to update database: {}", e.getMessage());
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
index eb378290aaf0cec147292a4528efae7e3928811b..75b647bf954fd638dfde8ffa8b7f650d03ce7c49 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
@@ -1,30 +1,14 @@
 package at.tuwien.service;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.SignupRequestDto;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.*;
-
-import java.util.UUID;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.CredentialsInvalidException;
+import at.tuwien.exception.UserNotFoundException;
 
 public interface AuthenticationService {
 
-    /**
-     * Create a user at the Authentication Service with given credentials.
-     *
-     * @param data The credentials.
-     * @return The user, if successful.
-     * @throws UserExistsException        The user already exists at the auth database.
-     * @throws AuthServiceException           The auth service responded with unexpected behavior.
-     * @throws AuthServiceConnectionException The connection with the auth service could not be established.
-     * @throws EmailExistsException       The user email already exists in the metadata database.
-     */
-    UserDto create(SignupRequestDto data) throws UserExistsException, AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException, CredentialsInvalidException;
-
     /**
      * Deletes a user at the Authentication Service with given user id.
      *
@@ -35,31 +19,12 @@ public interface AuthenticationService {
      */
     void delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException;
 
-    /**
-     * Finds a user with given username.
-     *
-     * @param username The username.
-     * @return The user, if successful.
-     * @throws AuthServiceException           The auth service responded with unexpected behavior.
-     * @throws AuthServiceConnectionException The connection with the auth service could not be established.
-     * @throws UserNotFoundException      The user was not found in the auth database.
-     */
-    UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException;
-
-    UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException;
-
-    TokenDto obtainToken(LoginRequestDto data) throws AuthServiceConnectionException, CredentialsInvalidException, AccountNotSetupException;
-
-    TokenDto refreshToken(String refreshToken) throws AuthServiceConnectionException, CredentialsInvalidException;
-
     /**
      * Updates the password of a user with given id.
      *
      * @param user The user.
      * @param data The new password.
-     * @throws AuthServiceException           The auth service responded with unexpected behavior.
-     * @throws AuthServiceConnectionException The connection with the auth service could not be established.
+     * @throws UserNotFoundException      The user was not found after creation in the auth database.
      */
-    void updatePassword(User user, UserPasswordDto data) throws AuthServiceException, AuthServiceConnectionException,
-            CredentialsInvalidException, UserNotFoundException;
+    void updatePassword(User user, UserPasswordDto data) throws UserNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java
index aa5a3295c49688f91d47960f2e254f5a5721604f..9aa2dc6c89839999c255595d65deb7399e702feb 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java
@@ -1,11 +1,9 @@
 package at.tuwien.service;
 
-import at.tuwien.api.container.ContainerCreateDto;
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.entities.container.Container;
-import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 
-import java.security.Principal;
 import java.util.List;
 
 public interface ContainerService {
@@ -18,7 +16,7 @@ public interface ContainerService {
      * @throws ImageNotFoundException          The image of the container was not found in the metadata database.
      * @throws ContainerAlreadyExistsException A container with this name already exists.
      */
-    Container create(ContainerCreateDto createDto) throws ImageNotFoundException,
+    Container create(CreateContainerDto createDto) throws ImageNotFoundException,
             ContainerAlreadyExistsException;
 
     /**
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java
index 3000ece11e91cc2b58f2edcfac85f6a0f8a60528..4e3765fd6ec8231d8bcfdcdaae83c0c96bcb8788 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java
@@ -1,6 +1,6 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.DatabaseCreateDto;
+import at.tuwien.api.database.CreateDatabaseDto;
 import at.tuwien.api.database.DatabaseModifyVisibilityDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.database.Database;
@@ -68,7 +68,7 @@ public interface DatabaseService {
      * @throws DataServiceException           If the data service returned non-successfully.
      * @throws DataServiceConnectionException If failing to connect to the data service/search service.
      */
-    Database create(Container container, DatabaseCreateDto createDto, User user, List<User> internalUsers) throws UserNotFoundException,
+    Database create(Container container, CreateDatabaseDto createDto, User user, List<User> internalUsers) throws UserNotFoundException,
             ContainerNotFoundException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException,
             SearchServiceException, SearchServiceConnectionException;
 
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java
index ded8204f32b8b6f99af5553952dfa6f0c535c652..47183700f91df1b24194fef24d931992b6b8b932 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java
@@ -1,7 +1,7 @@
 package at.tuwien.service;
 
 import at.tuwien.api.identifier.BibliographyTypeDto;
-import at.tuwien.api.identifier.IdentifierCreateDto;
+import at.tuwien.api.identifier.CreateIdentifierDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.api.identifier.IdentifierTypeDto;
 import at.tuwien.entities.database.Database;
@@ -139,7 +139,7 @@ public interface IdentifierService {
      * @throws SearchServiceException
      * @throws SearchServiceConnectionException
      */
-    Identifier create(Database database, User user, IdentifierCreateDto data) throws DataServiceException,
+    Identifier create(Database database, User user, CreateIdentifierDto data) throws DataServiceException,
             DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
             DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException;
 
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java
index 299283e68bbf6bd07ddb6b042248ead6681a6970..c0880c07dc8230d803ad455093cbea17c3145f61 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java
@@ -1,6 +1,6 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableUpdateDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
 import at.tuwien.entities.database.Database;
@@ -39,7 +39,7 @@ public interface TableService {
      * @param principal The principal.
      * @return The created table.
      */
-    Table createTable(Database database, TableCreateDto createDto, Principal principal)
+    Table createTable(Database database, CreateTableDto createDto, Principal principal)
             throws TableNotFoundException, DataServiceException, DataServiceConnectionException, UserNotFoundException,
             DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException;
 
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 6416da9b803d93f633f13223127a978954dd6e5d..581641a93ab95927d63c5b4a5f6b069eb6f270b7 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
@@ -1,10 +1,11 @@
 package at.tuwien.service;
 
-import at.tuwien.api.auth.SignupRequestDto;
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.EmailExistsException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
 import at.tuwien.exception.UserExistsException;
 import at.tuwien.exception.UserNotFoundException;
 
@@ -44,10 +45,9 @@ public interface UserService {
      * Creates a user in the metadata database managed by Keycloak in the given realm.
      *
      * @param data The user data.
-     * @param id   The user id.
      * @return The user, if successful.
      */
-    User create(SignupRequestDto data, UUID id);
+    User create(CreateUserDto data) throws UserNotFoundException, AuthServiceException;
 
     /**
      * Updates the user information for a user with given id in the metadata database.
@@ -56,7 +56,7 @@ public interface UserService {
      * @param data The user information.
      * @return The user if successful. False otherwise.
      */
-    User modify(User user, UserUpdateDto data);
+    User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException;
 
     /**
      * Updates the user password for a user with given id in the metadata database.
@@ -74,13 +74,5 @@ public interface UserService {
      */
     void validateUsernameNotExists(String username) throws UserExistsException;
 
-    /**
-     * Validates if a user with the given email already exists in the metadata database.
-     *
-     * @param email The email.
-     * @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/ViewService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java
index 9ec30b74f2efd58886269f8e8994f4852ead827e..4d183f1cc467d070a51a89edca99850c81a9b2ed 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java
@@ -1,12 +1,11 @@
 package at.tuwien.service;
 
-import at.tuwien.api.database.ViewCreateDto;
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.api.database.ViewUpdateDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.View;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 
@@ -53,7 +52,7 @@ public interface ViewService {
      * @throws SearchServiceConnectionException
      * @throws ViewNotFoundException
      */
-    View create(Database database, User user, ViewCreateDto data) throws MalformedException, DataServiceException,
+    View create(Database database, User user, CreateViewDto data) throws MalformedException, DataServiceException,
             DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException;
 
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
index 52aa5048891102ae10494790992076f9375388f5..1159913039ef59227758006f28d678db99329386 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
@@ -1,81 +1,36 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.SignupRequestDto;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.*;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.CredentialsInvalidException;
+import at.tuwien.exception.UserNotFoundException;
 import at.tuwien.gateway.KeycloakGateway;
-import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.AuthenticationService;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.UUID;
-
 @Log4j2
 @Service
 public class AuthenticationServiceImpl implements AuthenticationService {
 
-    private final MetadataMapper metadataMapper;
     private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public AuthenticationServiceImpl(MetadataMapper metadataMapper, KeycloakGateway keycloakGateway) {
-        this.metadataMapper = metadataMapper;
+    public AuthenticationServiceImpl(KeycloakGateway keycloakGateway) {
         this.keycloakGateway = keycloakGateway;
     }
 
     @Override
-    public UserDto create(SignupRequestDto data) throws UserExistsException, AuthServiceException,
-            AuthServiceConnectionException, EmailExistsException, CredentialsInvalidException {
-        keycloakGateway.createUser(metadataMapper.signupRequestDtoToUserCreateDto(data));
-        try {
-            return findByUsername(data.getUsername());
-        } catch (UserNotFoundException e) {
-            throw new AuthServiceException("Failed to find user in auth service", e);
-        }
-    }
-
-    @Override
-    public void delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException,
-            CredentialsInvalidException {
-        final UserDto keycloakUser = findByUsername(user.getUsername());
-        keycloakGateway.deleteUser(keycloakUser.getId());
-    }
-
-    @Override
-    public UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException, CredentialsInvalidException {
-        return keycloakGateway.findByUsername(username);
-    }
-
-    @Override
-    public UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException,
-            CredentialsInvalidException {
-        return keycloakGateway.findById(id);
-    }
-
-    @Override
-    public TokenDto obtainToken(LoginRequestDto data) throws AuthServiceConnectionException,
-            CredentialsInvalidException, AccountNotSetupException {
-        return keycloakGateway.obtainUserToken(data.getUsername(), data.getPassword());
-    }
-
-    @Override
-    public TokenDto refreshToken(String refreshToken) throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-        return keycloakGateway.refreshUserToken(refreshToken);
+    public void delete(User user) throws AuthServiceException, UserNotFoundException {
+        keycloakGateway.deleteUser(user.getKeycloakId());
     }
 
     @Override
-    public void updatePassword(User user, UserPasswordDto data) throws AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException, UserNotFoundException {
-        final UserDto keycloakUser = findByUsername(user.getUsername());
-        keycloakGateway.updateUserCredentials(keycloakUser.getId(), data);
+    public void updatePassword(User user, UserPasswordDto data) throws UserNotFoundException {
+        keycloakGateway.updateUserCredentials(user.getKeycloakId(), data);
     }
 
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
index 91db7736db7d9a4a4e931c744a938e78d72308c9..2a3c3215367605b943a3a2701c47b139c20c1b5d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
@@ -1,6 +1,6 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.container.ContainerCreateDto;
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.exception.ContainerAlreadyExistsException;
@@ -38,7 +38,7 @@ public class ContainerServiceImpl implements ContainerService {
 
     @Override
     @Transactional
-    public Container create(ContainerCreateDto data) throws ImageNotFoundException,
+    public Container create(CreateContainerDto data) throws ImageNotFoundException,
             ContainerAlreadyExistsException {
         final String containerName = "dbrepo-userdb-" + metadataMapper.nameToInternalName(data.getName());
         /* check */
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
index 0151ea92f7c4e8110bda544b70b7d341381902c2..b4e42a67e15939c2b779fc0dbe9d392371588c76 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java
@@ -6,7 +6,7 @@ import at.tuwien.api.datacite.doi.DataCiteCreateDoi;
 import at.tuwien.api.datacite.doi.DataCiteDoi;
 import at.tuwien.api.datacite.doi.DataCiteDoiEvent;
 import at.tuwien.api.identifier.BibliographyTypeDto;
-import at.tuwien.api.identifier.IdentifierCreateDto;
+import at.tuwien.api.identifier.CreateIdentifierDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.api.identifier.IdentifierTypeDto;
 import at.tuwien.config.DataCiteConfig;
@@ -105,7 +105,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService {
 
     @Override
     @Transactional(rollbackFor = {Exception.class})
-    public Identifier create(Database database, User user, IdentifierCreateDto data) throws DataServiceException,
+    public Identifier create(Database database, User user, CreateIdentifierDto data) throws DataServiceException,
             DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException,
             DatabaseNotFoundException, QueryNotFoundException, SearchServiceException,
             SearchServiceConnectionException, ExternalServiceException {
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
index 7415ded56a8a2a926742ef3b44b025f7fb535baa..8b4c73fb2f063cfc779fa001b7982675d74cf447 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
@@ -1,10 +1,9 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.database.DatabaseCreateDto;
+import at.tuwien.api.database.CreateDatabaseDto;
 import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.DatabaseModifyVisibilityDto;
 import at.tuwien.api.database.ViewDto;
-import at.tuwien.api.database.internal.CreateDatabaseDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.entities.container.Container;
@@ -96,7 +95,7 @@ public class DatabaseServiceImpl implements DatabaseService {
 
     @Override
     @Transactional
-    public Database create(Container container, DatabaseCreateDto data, User user, List<User> internalUsers)
+    public Database create(Container container, CreateDatabaseDto data, User user, List<User> internalUsers)
             throws UserNotFoundException, ContainerNotFoundException, DataServiceException, SearchServiceException,
             DataServiceConnectionException, DatabaseNotFoundException, SearchServiceConnectionException {
         final Database entity = Database.builder()
@@ -116,7 +115,7 @@ public class DatabaseServiceImpl implements DatabaseService {
                 .identifiers(new LinkedList<>())
                 .build();
         /* create in data database */
-        final CreateDatabaseDto payload = CreateDatabaseDto.builder()
+        final at.tuwien.api.database.internal.CreateDatabaseDto payload = at.tuwien.api.database.internal.CreateDatabaseDto.builder()
                 .containerId(data.getCid())
                 .userId(user.getId())
                 .username(user.getUsername())
@@ -217,6 +216,8 @@ public class DatabaseServiceImpl implements DatabaseService {
             }
             log.debug("fetched unknown table from data service: {}.{}", database.getInternalName(), table.getInternalName());
             final Table tableEntity = metadataMapper.tableDtoToTable(table);
+            tableEntity.setIsPublic(database.getIsPublic());
+            tableEntity.setIsSchemaPublic(database.getIsSchemaPublic());
             tableEntity.setDatabase(database);
             tableEntity.getColumns()
                     .forEach(column -> {
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
index 39e4824706a6d89a3588c6748c46ee2c3935b63e..96b8bd83963cca91e4731812ee0812a54a4630dc 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
@@ -3,7 +3,7 @@ package at.tuwien.service.impl;
 import at.tuwien.ExportResourceDto;
 import at.tuwien.api.database.query.QueryDto;
 import at.tuwien.api.identifier.BibliographyTypeDto;
-import at.tuwien.api.identifier.IdentifierCreateDto;
+import at.tuwien.api.identifier.CreateIdentifierDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.api.identifier.IdentifierTypeDto;
 import at.tuwien.config.MetadataConfig;
@@ -228,7 +228,7 @@ public class IdentifierServiceImpl implements IdentifierService {
 
     @Override
     @Transactional
-    public Identifier create(Database database, User user, IdentifierCreateDto data) throws SearchServiceException,
+    public Identifier create(Database database, User user, CreateIdentifierDto data) throws SearchServiceException,
             DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException,
             SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException {
         final Identifier identifier = metadataMapper.identifierCreateDtoToIdentifier(data);
@@ -287,7 +287,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         /* save identifier */
         switch (identifier.getType()) {
             case SUBSET -> {
-                log.debug("identifier type: subset with id {} and database with id {}", identifier.getQueryId(), identifier.getDatabase().getId());
+                log.debug("identifier type: subset with id {}", identifier.getQueryId());
                 final QueryDto query = dataServiceGateway.findQuery(identifier.getDatabase().getId(), identifier.getQueryId());
                 identifier.setQuery(query.getQuery());
                 identifier.setQueryId(query.getId());
@@ -298,14 +298,14 @@ public class IdentifierServiceImpl implements IdentifierService {
                 identifier.setResultHash(query.getResultHash());
             }
             case VIEW -> {
-                log.debug("identifier type: view with id {} and database with id {}", identifier.getViewId(), identifier.getDatabase().getId());
+                log.debug("identifier type: view with id {}", identifier.getViewId());
                 final View view = viewService.findById(identifier.getDatabase(), identifier.getViewId());
                 identifier.setViewId(view.getId());
                 identifier.setQuery(view.getQuery());
                 identifier.setQueryNormalized(view.getQuery());
                 identifier.setQueryHash(view.getQueryHash());
             }
-            case DATABASE -> log.debug("identifier type: database with id {}", identifier.getDatabase());
+            case DATABASE -> log.debug("identifier type: database with id {}", identifier.getDatabase().getId());
             case TABLE -> log.debug("identifier type: table with id {}", identifier.getTableId());
         }
         /* save identifier in metadata database */
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 52a9a63667c8faa22bdd142d5161f04e85d70513..da92fb7ef59eac9af0df3cf1f779da150c2d437f 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
@@ -1,9 +1,9 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.database.table.TableCreateDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableStatisticDto;
 import at.tuwien.api.database.table.TableUpdateDto;
-import at.tuwien.api.database.table.columns.ColumnCreateDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnStatisticDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
 import at.tuwien.config.RabbitConfig;
@@ -90,7 +90,7 @@ public class TableServiceImpl implements TableService {
 
     @Override
     @Transactional
-    public Table createTable(Database database, TableCreateDto data, Principal principal) throws DataServiceException,
+    public Table createTable(Database database, CreateTableDto data, Principal principal) throws DataServiceException,
             DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException,
             TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException,
             OntologyNotFoundException, SemanticEntityNotFoundException {
@@ -117,7 +117,7 @@ public class TableServiceImpl implements TableService {
             /* set the ordinal position for the columns */
             final int[] idx = new int[]{0};
             for (int i = 0; i < data.getColumns().size(); i++) {
-                final ColumnCreateDto c = data.getColumns().get(i);
+                final CreateTableColumnDto c = data.getColumns().get(i);
                 final TableColumn column = metadataMapper.columnCreateDtoToTableColumn(c, database.getContainer().getImage());
                 column.setOrdinalPosition(idx[0]++);
                 column.setTable(table);
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 6f9f43aeda934ecd7065ead11077ad529597e118..cb550be1a5d408139b656f0d0619467f8f59fa26 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
@@ -1,17 +1,20 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.auth.SignupRequestDto;
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserUpdateDto;
-import at.tuwien.config.KeycloakConfig;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.EmailExistsException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
 import at.tuwien.exception.UserExistsException;
 import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.UserRepository;
 import at.tuwien.service.UserService;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -24,13 +27,16 @@ import java.util.UUID;
 @Service
 public class UserServiceImpl implements UserService {
 
-    private final KeycloakConfig keycloakConfig;
+    private final MetadataMapper metadataMapper;
     private final UserRepository userRepository;
+    private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public UserServiceImpl(KeycloakConfig keycloakConfig, UserRepository userRepository) {
-        this.keycloakConfig = keycloakConfig;
+    public UserServiceImpl(MetadataMapper metadataMapper, UserRepository userRepository,
+                           KeycloakGateway keycloakGateway) {
+        this.metadataMapper = metadataMapper;
         this.userRepository = userRepository;
+        this.keycloakGateway = keycloakGateway;
     }
 
     @Override
@@ -64,32 +70,36 @@ public class UserServiceImpl implements UserService {
     }
 
     @Override
-    public User create(SignupRequestDto data, UUID id) {
+    public User create(CreateUserDto data) throws UserNotFoundException, AuthServiceException {
         /* create at authentication service */
         final User entity = User.builder()
-                .id(id)
+                .id(data.getLdapId())
+                .keycloakId(data.getId())
                 .username(data.getUsername())
-                .email(data.getEmail())
                 .theme("light")
-                .mariadbPassword(getMariaDbPassword(data.getPassword()))
+                .mariadbPassword(getMariaDbPassword(RandomStringUtils.randomAlphabetic(10))) /* user needs to set it later to access */
                 .language("en")
+                .firstname(data.getGivenName())
+                .lastname(data.getFamilyName())
                 .isInternal(false)
                 .build();
-        /* create at metadata database */
+        /* save in metadata database */
         final User user = userRepository.save(entity);
         log.info("Created user with id: {}", user.getId());
         return user;
     }
 
     @Override
-    public User modify(User user, UserUpdateDto data) {
+    public User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException {
         user.setFirstname(data.getFirstname());
         user.setLastname(data.getLastname());
         user.setAffiliation(data.getAffiliation());
         user.setOrcid(data.getOrcid());
         user.setTheme(data.getTheme());
         user.setLanguage(data.getLanguage());
-        /* create at metadata database */
+        /* save in auth service */
+        keycloakGateway.updateUser(user.getKeycloakId(), data);
+        /* save in metadata database */
         user = userRepository.save(user);
         log.info("Modified user with id: {}", user.getId());
         return user;
@@ -110,13 +120,6 @@ public class UserServiceImpl implements UserService {
         }
     }
 
-    @Override
-    public void validateEmailNotExists(String email) throws EmailExistsException {
-        if (userRepository.existsByEmail(email)) {
-            throw new EmailExistsException("User with email " + email + " already exists");
-        }
-    }
-
     @Override
     public String getMariaDbPassword(String password) {
         final byte[] utf8 = password.getBytes(StandardCharsets.UTF_8);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
index b0a8f017962ccc808d8f3d1a37ae584fb1106316..8ca688b1edcc869be309561b4c9fef434e081285 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
@@ -1,6 +1,6 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.database.ViewCreateDto;
+import at.tuwien.api.database.CreateViewDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.database.ViewUpdateDto;
 import at.tuwien.entities.database.Database;
@@ -87,7 +87,7 @@ public class ViewServiceImpl implements ViewService {
 
     @Override
     @Transactional
-    public View create(Database database, User creator, ViewCreateDto data) throws MalformedException,
+    public View create(Database database, User creator, CreateViewDto data) throws MalformedException,
             DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
         /* create in metadata database */
diff --git a/dbrepo-metadata-service/test/pom.xml b/dbrepo-metadata-service/test/pom.xml
index c58104714adaebc14cfb1c3b5e268e807d8c8e29..d51ed22d4d84941f982296b18b4fcb9005db7dce 100644
--- a/dbrepo-metadata-service/test/pom.xml
+++ b/dbrepo-metadata-service/test/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.1</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-test</artifactId>
     <name>dbrepo-metadata-service-test</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
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 91936adaf8f27c87dbd4019b4ee6ce8a67e118a5..f78366fe89f6c631ae29da8020af629f71c528e6 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
@@ -12,7 +12,7 @@ public abstract class AbstractUnitTest extends BaseTest {
 
     public void genesis() {
         IMAGE_1_DTO.setOperators(IMAGE_1_OPERATORS_DTO);
-        CONTAINER_1_PRIVILEGED_DTO.setImage(IMAGE_1_DTO);
+        CONTAINER_1_DTO.setImage(IMAGE_1_DTO);
         IMAGE_1.setOperators(new LinkedList<>(IMAGE_1_OPERATORS));
         CONTAINER_1.setDatabases(new LinkedList<>(List.of(DATABASE_1, DATABASE_2, DATABASE_3)));
         CONTAINER_4.setDatabases(new LinkedList<>(List.of(DATABASE_4)));
@@ -36,13 +36,12 @@ public abstract class AbstractUnitTest extends BaseTest {
         DATABASE_1.setIsSchemaPublic(DATABASE_1_SCHEMA_PUBLIC);
         DATABASE_1_USER_1_READ_ACCESS.setType(AccessType.READ);
         DATABASE_1.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS, DATABASE_1_USER_2_WRITE_OWN_ACCESS, DATABASE_1_USER_3_WRITE_ALL_ACCESS)));
+        DATABASE_1_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO)));
         DATABASE_1_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO)));
-        TABLE_1.setDatabase(DATABASE_1);
         UNIT_1.setId(UNIT_1_ID);
+        TABLE_1.setDatabase(DATABASE_1);
         TABLE_1.setColumns(new LinkedList<>(TABLE_1_COLUMNS));
         TABLE_1.setConstraints(TABLE_1_CONSTRAINTS);
-        TABLE_1_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO));
-        TABLE_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO);
         VIEW_1_DTO.setIdentifiers(VIEW_1_DTO_IDENTIFIERS);
         DATABASE_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4)));
         IDENTIFIER_1.setDatabase(DATABASE_1);
@@ -51,20 +50,24 @@ public abstract class AbstractUnitTest extends BaseTest {
         IDENTIFIER_4.setDatabase(DATABASE_1);
         DATABASE_1.setTables(new LinkedList<>(List.of(TABLE_1, TABLE_2, TABLE_3, TABLE_4)));
         DATABASE_1.setViews(new LinkedList<>(List.of(VIEW_1, VIEW_2, VIEW_3)));
-        DATABASE_1_PRIVILEGED_DTO.setContainer(CONTAINER_1_PRIVILEGED_DTO);
-        DATABASE_1_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO)));
-        DATABASE_1_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO)));
-        DATABASE_1_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)));
+        DATABASE_1_DTO.setContainer(CONTAINER_1_DTO);
+        DATABASE_1_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO)));
+        DATABASE_1_DTO.setTables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO)));
+        DATABASE_1_DTO.setViews(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)));
         TABLE_1_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO));
         TABLE_1_DTO.setConstraints(TABLE_1_CONSTRAINTS_DTO);
+        TABLE_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO);
+        TABLE_1_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO));
+        TABLE_1_PRIVILEGED_DTO.setConstraints(TABLE_1_CONSTRAINTS_DTO);
         TABLE_2.setDatabase(DATABASE_1);
         TABLE_2.setColumns(new LinkedList<>(TABLE_2_COLUMNS));
         TABLE_2_CONSTRAINTS.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_2_CONSTRAINTS.getForeignKeys().get(0));
         TABLE_2.setConstraints(TABLE_2_CONSTRAINTS);
-        TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO));
-        TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO);
         TABLE_2_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO));
         TABLE_2_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO);
+        TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO);
+        TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO));
+        TABLE_2_PRIVILEGED_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO);
         TABLE_3.setDatabase(DATABASE_1);
         TABLE_3.setColumns(new LinkedList<>(TABLE_3_COLUMNS));
         TABLE_3.setConstraints(TABLE_3_CONSTRAINTS);
@@ -75,6 +78,9 @@ public abstract class AbstractUnitTest extends BaseTest {
         TABLE_4.setConstraints(TABLE_4_CONSTRAINTS);
         TABLE_4_DTO.setColumns(TABLE_4_COLUMNS_DTO);
         TABLE_4_DTO.setConstraints(TABLE_4_CONSTRAINTS_DTO);
+        TABLE_4_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO);
+        TABLE_4_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_4_COLUMNS_DTO));
+        TABLE_4_PRIVILEGED_DTO.setConstraints(TABLE_4_CONSTRAINTS_DTO);
         VIEW_1.setDatabase(DATABASE_1);
         VIEW_1.setColumns(new LinkedList<>(VIEW_1_COLUMNS));
         VIEW_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_3)));
@@ -92,22 +98,21 @@ public abstract class AbstractUnitTest extends BaseTest {
         /* DATABASE 2 */
         DATABASE_2.setSubsets(new LinkedList<>());
         DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS)));
+        DATABASE_2_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_DTO)));
         DATABASE_2_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_DTO)));
         DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7)));
         VIEW_4.setColumns(new LinkedList<>(VIEW_4_COLUMNS));
         DATABASE_2.setViews(new LinkedList<>(List.of(VIEW_4)));
         DATABASE_2.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5)));
-        DATABASE_2_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO)));
-        DATABASE_2_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_4_DTO)));
-        DATABASE_2_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO)));
+        DATABASE_2_DTO.setTables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO)));
+        DATABASE_2_DTO.setViews(new LinkedList<>(List.of(VIEW_4_DTO)));
+        DATABASE_2_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO)));
         TABLE_5.setDatabase(DATABASE_2);
         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.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO));
         TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO);
+        TABLE_5_PRIVILEGED_DTO.setDatabase(DATABASE_2_PRIVILEGED_DTO);
         TABLE_6.setDatabase(DATABASE_2);
         TABLE_6.setColumns(new LinkedList<>(TABLE_6_COLUMNS));
         TABLE_6.setConstraints(TABLE_6_CONSTRAINTS);
@@ -124,31 +129,37 @@ public abstract class AbstractUnitTest extends BaseTest {
         IDENTIFIER_5.setDatabase(DATABASE_2);
         /* DATABASE 3 */
         DATABASE_3.setSubsets(new LinkedList<>());
-        DATABASE_3.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS)));
         DATABASE_3.setTables(new LinkedList<>(List.of(TABLE_8)));
         DATABASE_3.setViews(new LinkedList<>(List.of(VIEW_5)));
         DATABASE_3.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_6)));
+        DATABASE_3.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS)));
+        DATABASE_3_DTO.setTables(new LinkedList<>(List.of(TABLE_8_DTO)));
+        DATABASE_3_DTO.setViews(new LinkedList<>(List.of(VIEW_5_DTO)));
+        DATABASE_3_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_6_DTO)));
+        DATABASE_3_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO)));
+        DATABASE_3_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO)));
         TABLE_8.setDatabase(DATABASE_3);
         TABLE_8.setColumns(new LinkedList<>(TABLE_8_COLUMNS));
         TABLE_8.setConstraints(TABLE_8_CONSTRAINTS);
         TABLE_8_DTO.setColumns(new LinkedList<>(TABLE_8_COLUMNS_DTO));
         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);
         VIEW_5_DTO.setColumns(VIEW_5_COLUMNS_DTO);
         IDENTIFIER_6.setDatabase(DATABASE_3);
         /* DATABASE 4 */
+        DATABASE_4.setSubsets(new LinkedList<>());
+        DATABASE_4.setAccesses(new LinkedList<>(List.of(DATABASE_4_USER_1_READ_ACCESS, DATABASE_4_USER_2_WRITE_OWN_ACCESS, DATABASE_4_USER_3_WRITE_ALL_ACCESS)));
+        DATABASE_4.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7)));
+        DATABASE_4_DTO.setTables(new LinkedList<>(List.of(TABLE_9_DTO)));
+        DATABASE_4_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7_DTO)));
         TABLE_9.setDatabase(DATABASE_4);
         TABLE_9.setColumns(TABLE_9_COLUMNS);
         TABLE_9.setConstraints(TABLE_9_CONSTRAINTS);
         TABLE_9_DTO.setColumns(TABLE_9_COLUMNS_DTO);
         TABLE_9_DTO.setConstraints(TABLE_9_CONSTRAINTS_DTO);
-        DATABASE_4.setSubsets(new LinkedList<>());
-        DATABASE_4.setAccesses(new LinkedList<>(List.of(DATABASE_4_USER_1_READ_ACCESS, DATABASE_4_USER_2_WRITE_OWN_ACCESS, DATABASE_4_USER_3_WRITE_ALL_ACCESS)));
-        DATABASE_4.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7)));
         IDENTIFIER_7.setStatus(IdentifierStatusType.DRAFT);
         IDENTIFIER_7.setDatabase(DATABASE_4);
     }
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 368b1d182c3b4d4289426673804bab23ccd8c0e1..0f07af9af968eae4e16f1f54a099312a20cabbb0 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
@@ -5,31 +5,26 @@ import at.tuwien.api.amqp.CreateVirtualHostDto;
 import at.tuwien.api.amqp.ExchangeDto;
 import at.tuwien.api.amqp.GrantVirtualHostPermissionsDto;
 import at.tuwien.api.amqp.QueueDto;
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.auth.LoginRequestDto;
 import at.tuwien.api.auth.RefreshTokenRequestDto;
-import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.container.ContainerBriefDto;
 import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.container.image.*;
-import at.tuwien.api.container.internal.PrivilegedContainerDto;
 import at.tuwien.api.database.*;
-import at.tuwien.api.database.internal.CreateDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedDatabaseDto;
-import at.tuwien.api.database.internal.PrivilegedViewDto;
 import at.tuwien.api.database.query.QueryBriefDto;
 import at.tuwien.api.database.query.QueryDto;
+import at.tuwien.api.database.table.CreateTableDto;
 import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableCreateDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.TableStatisticDto;
 import at.tuwien.api.database.table.columns.*;
 import at.tuwien.api.database.table.columns.concepts.*;
-import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
 import at.tuwien.api.database.table.constraints.ConstraintsDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import at.tuwien.api.database.table.constraints.foreign.*;
 import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
 import at.tuwien.api.database.table.constraints.unique.UniqueDto;
-import at.tuwien.api.database.table.internal.PrivilegedTableDto;
 import at.tuwien.api.datacite.DataCiteBody;
 import at.tuwien.api.datacite.DataCiteData;
 import at.tuwien.api.datacite.doi.DataCiteDoi;
@@ -51,9 +46,7 @@ import at.tuwien.api.orcid.person.name.OrcidNameDto;
 import at.tuwien.api.orcid.person.name.OrcidValueDto;
 import at.tuwien.api.semantics.*;
 import at.tuwien.api.user.UserAttributesDto;
-import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.*;
-import at.tuwien.api.user.internal.PrivilegedUserDto;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.container.image.ContainerImage;
@@ -105,12 +98,12 @@ import static java.time.temporal.ChronoUnit.MINUTES;
  * <ul>
  * <li>Table 1 (Private Data, Private Schema)</li>
  * <li>Table 2 (Private Data, Public Schema)</li>
- * <li>Table 3</li>
- * <li>Table 4</li>
+ * <li>Table 3 (Private Data, Private Schema)</li>
+ * <li>Table 4 (Public Data, Private Schema)</li>
  * <li>Query 1</li>
- * <li>View 1</li>
- * <li>View 2</li>
- * <li>View 3</li>
+ * <li>View 1 (Private Data, Private Schema)</li>
+ * <li>View 2 (Public Data, Public Schema)</li>
+ * <li>View 3 (Public Data, Private Schema)</li>
  * <li>Identifier 1 (Title=en, Description=en, type=database)</li>
  * <li>Identifier 2 (Title=en, Description=en, type=subset, queryId=1)</li>
  * <li>Identifier 3 (Title=en, Description=en, type=view, viewId=1)</li>
@@ -119,26 +112,26 @@ import static java.time.temporal.ChronoUnit.MINUTES;
  * <p>
  * Database 2 (Private Data, Public Schema, User 2) -> Container 1
  * <ul>
- * <li>Table 5</li>
- * <li>Table 6</li>
- * <li>Table 7</li>
+ * <li>Table 5 (Public Data, Public Schema)</li>
+ * <li>Table 6 (Public Data, Private Schema)</li>
+ * <li>Table 7 (Public Data, Public Schema)</li>
  * <li>Query 2</li>
  * <li>Query 6</li>
- * <li>View 4</li>
+ * <li>View 4 (Public Data, Private Schema)</li>
  * <li>Identifier 5 (Title=de, Description=de)</li>
  * </ul>
  * <p>
  * Database 3 (Public Data, Private Schema, User 3) -> Container 1
  * <ul>
- * <li>Table 8</li>
+ * <li>Table 8 (Private Data, Private Schema)</li>
  * <li>Query 3</li>
  * <li>Query 4</li>
  * <li>Query 5</li>
- * <li>View 5</li>
+ * <li>View 5 (Public Data, Public Schema)</li>
  * <li>Identifier 6 (Title=en, Description=en, Query=3)</li>
  * </ul>
  * <p>
- * Database 4 (Public Data, Public Schema, User 4) -> Container 4
+ * Database 4 (Public Data, Public Schema, User 4) -> Container 2
  * <li>Table 9</li>
  * <li>Identifier 7</li>
  * <li>Query 7</li>
@@ -157,7 +150,9 @@ public abstract class BaseTest {
 
     public final static String MARIADB_IMAGE = "mariadb:11.3.2";
 
-    public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:24.0";
+    public final static String RABBITMQ_IMAGE = "rabbitmq:3.13.7";
+
+    public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:26.0";
 
     public final static String[] DEFAULT_SEMANTICS_HANDLING = new String[]{"default-semantics-handling",
             "create-semantic-unit", "execute-semantic-query", "table-semantic-analyse", "create-semantic-concept"};
@@ -170,7 +165,7 @@ public abstract class BaseTest {
             "update-semantic-unit", "create-ontology", "update-ontology"};
 
     public final static String[] DEFAULT_CONTAINER_HANDLING = new String[]{"default-container-handling",
-            "create-container", "list-containers", "modify-container-state", "find-container"};
+            "create-container", "list-containers", "modify-container-state"};
 
     public final static String[] ESCALATED_CONTAINER_HANDLING = new String[]{"escalated-container-handling",
             "modify-foreign-container-state", "delete-container"};
@@ -190,9 +185,9 @@ public abstract class BaseTest {
             "modify-identifier-metadata", "update-foreign-identifier", "create-foreign-identifier"};
 
     public final static String[] DEFAULT_QUERY_HANDLING = new String[]{"default-query-handling", "view-table-data",
-            "execute-query", "view-table-history", "list-database-views", "view-database-view-data",
-            "export-query-data", "create-database-view", "delete-database-view", "delete-table-data",
-            "export-table-data", "persist-query", "re-execute-query", "insert-table-data", "find-database-view"};
+            "execute-query", "view-table-history", "list-database-views", "export-query-data", "create-database-view",
+            "delete-database-view", "delete-table-data", "export-table-data", "persist-query", "re-execute-query",
+            "insert-table-data", "find-database-view"};
 
     public final static String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"};
 
@@ -221,7 +216,7 @@ public abstract class BaseTest {
     public final static String[] DEFAULT_DATA_STEWARD_ROLES = ArrayUtils.merge(List.of(new String[]{"default-data-steward-roles"},
             ESCALATED_IDENTIFIER_HANDLING, DEFAULT_SEMANTICS_HANDLING, ESCALATED_SEMANTICS_HANDLING, DEFAULT_VIEW_HANDLING));
 
-    public final static String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"admin"};
+    public final static String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"system"};
 
     public final static List<GrantedAuthorityDto> AUTHORITY_LOCAL_ADMIN_ROLES = Arrays.stream(DEFAULT_LOCAL_ADMIN_ROLES)
             .map(GrantedAuthorityDto::new)
@@ -267,15 +262,15 @@ public abstract class BaseTest {
     public final static String ROLE_DEFAULT_RESEARCHER_ROLES_NAME = "default-researcher-roles";
     public final static UUID ROLE_DEFAULT_RESEARCHER_ROLES_REALM_ID = REALM_DBREPO_ID;
 
-    public final static UpdateDatabaseAccessDto UPDATE_DATABASE_ACCESS_READ_DTO = UpdateDatabaseAccessDto.builder()
+    public final static CreateAccessDto UPDATE_DATABASE_ACCESS_READ_DTO = CreateAccessDto.builder()
             .type(AccessTypeDto.READ)
             .build();
 
-    public final static UpdateDatabaseAccessDto UPDATE_DATABASE_ACCESS_WRITE_OWN_DTO = UpdateDatabaseAccessDto.builder()
+    public final static CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_OWN_DTO = CreateAccessDto.builder()
             .type(AccessTypeDto.WRITE_OWN)
             .build();
 
-    public final static UpdateDatabaseAccessDto UPDATE_DATABASE_ACCESS_WRITE_ALL_DTO = UpdateDatabaseAccessDto.builder()
+    public final static CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_ALL_DTO = CreateAccessDto.builder()
             .type(AccessTypeDto.WRITE_ALL)
             .build();
 
@@ -444,13 +439,13 @@ public abstract class BaseTest {
     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 UUID USER_LOCAL_ADMIN_KEYCLOAK_ID = UUID.fromString("703c2ca0-8fc3-4c03-9bc5-4dae6b211e78");
     public final static String USER_LOCAL_ADMIN_USERNAME = "admin";
     @SuppressWarnings("java:S2068")
     public final static String USER_LOCAL_ADMIN_PASSWORD = "admin";
     public final static String USER_LOCAL_ADMIN_THEME = "dark";
     public final static Boolean USER_LOCAL_ADMIN_IS_INTERNAL = true;
     public final static Boolean USER_LOCAL_ADMIN_ENABLED = true;
-    public final static String USER_LOCAL_ADMIN_EMAIL = "admin@local";
     @SuppressWarnings("java:S2068")
     public final static String USER_LOCAL_ADMIN_MARIADB_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA";
 
@@ -460,7 +455,7 @@ public abstract class BaseTest {
             .build();
 
     public final static UserDetails USER_LOCAL_ADMIN_DETAILS = UserDetailsDto.builder()
-            .id(String.valueOf(USER_LOCAL_ADMIN_ID))
+            .id(USER_LOCAL_ADMIN_ID.toString())
             .username(USER_LOCAL_ADMIN_USERNAME)
             .password(USER_LOCAL_ADMIN_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_LOCAL_ADMIN_AUTHORITIES)
@@ -468,8 +463,8 @@ public abstract class BaseTest {
 
     public final static User USER_LOCAL = User.builder()
             .id(USER_LOCAL_ADMIN_ID)
+            .keycloakId(USER_LOCAL_ADMIN_KEYCLOAK_ID)
             .username(USER_LOCAL_ADMIN_USERNAME)
-            .email(USER_LOCAL_ADMIN_EMAIL)
             .mariadbPassword(USER_LOCAL_ADMIN_MARIADB_PASSWORD)
             .theme(USER_LOCAL_ADMIN_THEME)
             .isInternal(USER_LOCAL_ADMIN_IS_INTERNAL)
@@ -479,8 +474,7 @@ public abstract class BaseTest {
             USER_LOCAL_ADMIN_PASSWORD, USER_LOCAL_ADMIN_DETAILS.getAuthorities());
 
     public final static UUID USER_1_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b");
-    public final static UUID USER_1_LDAP_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b");
-    public final static String USER_1_EMAIL = "john.doe@example.com";
+    public final static UUID USER_1_KEYCLOAK_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b");
     public final static String USER_1_USERNAME = "junit1";
     @SuppressWarnings("java:S2068")
     public final static String USER_1_PASSWORD = "junit1";
@@ -534,7 +528,6 @@ public abstract class BaseTest {
 
     public final static UserCreateDto USER_1_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder()
             .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
             .enabled(USER_1_ENABLED)
             .credentials(new LinkedList<>(List.of(USER_1_KEYCLOAK_CREDENTIAL_1)))
             .attributes(UserCreateAttributesDto.builder()
@@ -544,7 +537,6 @@ public abstract class BaseTest {
 
     public final static UserCreateDto USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder()
             .username(USER_LOCAL_ADMIN_USERNAME)
-            .email(USER_LOCAL_ADMIN_EMAIL)
             .enabled(USER_LOCAL_ADMIN_ENABLED)
             .credentials(new LinkedList<>(List.of(USER_LOCAL_KEYCLOAK_CREDENTIAL_1)))
             .groups(new LinkedList<>(List.of("system")))
@@ -553,21 +545,10 @@ public abstract class BaseTest {
                     .build())
             .build();
 
-    public final static PrivilegedUserDto USER_1_PRIVILEGED_DTO = PrivilegedUserDto.builder()
-            .id(USER_1_ID)
-            .username(USER_1_USERNAME)
-            .password(USER_1_PASSWORD)
-            .attributes(USER_1_ATTRIBUTES_DTO)
-            .firstname(USER_1_FIRSTNAME)
-            .lastname(USER_1_LASTNAME)
-            .qualifiedName(USER_1_QUALIFIED_NAME)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static User USER_1 = User.builder()
             .id(USER_1_ID)
+            .keycloakId(USER_1_KEYCLOAK_ID)
             .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
             .firstname(USER_1_FIRSTNAME)
             .lastname(USER_1_LASTNAME)
             .affiliation(USER_1_AFFILIATION)
@@ -601,19 +582,6 @@ public abstract class BaseTest {
             .password(USER_1_PASSWORD)
             .build();
 
-    public final static at.tuwien.api.keycloak.UserDto USER_1_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder()
-            .id(USER_1_ID)
-            .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
-            .emailVerified(USER_1_VERIFIED)
-            .notBefore(USER_1_NOT_BEFORE)
-            .totp(USER_1_TOTP)
-            .attributes(at.tuwien.api.keycloak.UserAttributesDto.builder()
-                    .ldapEntryDn(new String[]{"cn=" + USER_1_USERNAME + ",dn=dbrepo,dn=at"})
-                    .ldapId(new UUID[]{USER_1_LDAP_ID})
-                    .build())
-            .build();
-
     public final static UserBriefDto USER_1_BRIEF_DTO = UserBriefDto.builder()
             .id(USER_1_ID)
             .username(USER_1_USERNAME)
@@ -627,7 +595,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_1_DETAILS = UserDetailsDto.builder()
             .id(USER_1_ID.toString())
             .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
             .password(USER_1_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
@@ -635,10 +602,10 @@ public abstract class BaseTest {
     public final static Principal USER_1_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_1_DETAILS,
             USER_1_PASSWORD, USER_1_DETAILS.getAuthorities());
 
-    public final static SignupRequestDto USER_1_SIGNUP_REQUEST_DTO = SignupRequestDto.builder()
+    public final static CreateUserDto USER_1_SIGNUP_REQUEST_DTO = CreateUserDto.builder()
+            .id(USER_1_KEYCLOAK_ID)
+            .ldapId(USER_1_ID)
             .username(USER_1_USERNAME)
-            .password(USER_1_PASSWORD)
-            .email(USER_1_EMAIL)
             .build();
 
     public final static LoginRequestDto USER_1_LOGIN_REQUEST_DTO = LoginRequestDto.builder()
@@ -647,7 +614,7 @@ public abstract class BaseTest {
             .build();
 
     public final static UUID USER_2_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c");
-    public final static UUID USER_2_LDAP_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c");
+    public final static UUID USER_2_KEYCLOAK_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c");
     public final static String USER_2_EMAIL = "jane.doe@example.com";
     public final static String USER_2_USERNAME = "junit2";
     public final static String USER_2_FIRSTNAME = "Jane";
@@ -681,8 +648,8 @@ public abstract class BaseTest {
 
     public final static User USER_2 = User.builder()
             .id(USER_2_ID)
+            .keycloakId(USER_2_KEYCLOAK_ID)
             .username(USER_2_USERNAME)
-            .email(USER_2_EMAIL)
             .firstname(USER_2_FIRSTNAME)
             .lastname(USER_2_LASTNAME)
             .affiliation(USER_2_AFFILIATION)
@@ -713,50 +680,32 @@ public abstract class BaseTest {
             .qualifiedName(USER_2_QUALIFIED_NAME)
             .build();
 
-    public final static SignupRequestDto USER_2_SIGNUP_REQUEST_DTO = SignupRequestDto.builder()
+    public final static CreateUserDto USER_2_SIGNUP_REQUEST_DTO = CreateUserDto.builder()
+            .id(USER_2_KEYCLOAK_ID)
+            .ldapId(USER_2_ID)
             .username(USER_2_USERNAME)
-            .password(USER_2_PASSWORD)
             .email(USER_2_EMAIL)
+            .givenName(USER_2_FIRSTNAME)
+            .familyName(USER_2_LASTNAME)
             .build();
 
     public final static UserDetails USER_2_DETAILS = UserDetailsDto.builder()
             .id(USER_2_ID.toString())
             .username(USER_2_USERNAME)
-            .email(USER_2_EMAIL)
             .password(USER_2_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
 
-    public final static at.tuwien.api.keycloak.UserDto USER_2_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder()
-            .id(USER_2_ID)
-            .username(USER_2_USERNAME)
-            .email(USER_2_EMAIL)
-            .emailVerified(USER_2_VERIFIED)
-            .notBefore(USER_2_NOT_BEFORE)
-            .totp(USER_2_TOTP)
-            .build();
-
     public final static at.tuwien.api.amqp.UserDetailsDto USER_2_DETAILS_DTO = at.tuwien.api.amqp.UserDetailsDto.builder()
             .name(USER_2_USERNAME)
             .tags(new String[]{})
             .build();
 
-    public final static PrivilegedUserDto USER_2_PRIVILEGED_DTO = PrivilegedUserDto.builder()
-            .id(USER_2_ID)
-            .username(USER_2_USERNAME)
-            .password(USER_2_PASSWORD)
-            .attributes(USER_2_ATTRIBUTES_DTO)
-            .firstname(USER_2_FIRSTNAME)
-            .lastname(USER_2_LASTNAME)
-            .qualifiedName(USER_2_QUALIFIED_NAME)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static Principal USER_2_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_2_DETAILS,
             USER_2_PASSWORD, USER_2_DETAILS.getAuthorities());
 
     public final static UUID USER_3_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006");
-    public final static UUID USER_3_LDAP_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006");
+    public final static UUID USER_3_KEYCLOAK_ID = UUID.fromString("b0108bc3-95aa-4a3f-8868-dc301286aeca");
     public final static String USER_3_USERNAME = "junit3";
     public final static String USER_3_FIRSTNAME = "System";
     public final static String USER_3_LASTNAME = "System";
@@ -788,8 +737,8 @@ public abstract class BaseTest {
 
     public final static User USER_3 = User.builder()
             .id(USER_3_ID)
+            .keycloakId(USER_3_KEYCLOAK_ID)
             .username(USER_3_USERNAME)
-            .email(USER_3_EMAIL)
             .firstname(USER_3_FIRSTNAME)
             .lastname(USER_3_LASTNAME)
             .affiliation(USER_3_AFFILIATION)
@@ -821,18 +770,14 @@ public abstract class BaseTest {
     public final static UserDetails USER_3_DETAILS = UserDetailsDto.builder()
             .id(USER_3_ID.toString())
             .username(USER_3_USERNAME)
-            .email(USER_3_EMAIL)
             .password(USER_3_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
 
-    public final static at.tuwien.api.keycloak.UserDto USER_3_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder()
-            .id(USER_3_ID)
+    public final static CreateUserDto USER_3_SIGNUP_REQUEST_DTO = CreateUserDto.builder()
+            .id(USER_3_KEYCLOAK_ID)
+            .ldapId(USER_3_ID)
             .username(USER_3_USERNAME)
-            .email(USER_3_EMAIL)
-            .emailVerified(USER_3_VERIFIED)
-            .notBefore(USER_3_NOT_BEFORE)
-            .totp(USER_3_TOTP)
             .build();
 
     public final static Principal USER_3_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_3_DETAILS,
@@ -843,19 +788,8 @@ public abstract class BaseTest {
             .tags(new String[]{})
             .build();
 
-    public final static PrivilegedUserDto USER_3_PRIVILEGED_DTO = PrivilegedUserDto.builder()
-            .id(USER_3_ID)
-            .username(USER_3_USERNAME)
-            .password(USER_3_PASSWORD)
-            .attributes(USER_3_ATTRIBUTES_DTO)
-            .firstname(USER_3_FIRSTNAME)
-            .lastname(USER_3_LASTNAME)
-            .qualifiedName(USER_3_QUALIFIED_NAME)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static UUID USER_4_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0");
-    public final static UUID USER_4_LDAP_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0");
+    public final static UUID USER_4_KEYCLOAK_ID = UUID.fromString("25040ad3-6d57-4052-b357-6b4c8a6e7f4d");
     public final static String USER_4_USERNAME = "junit4";
     public final static String USER_4_FIRSTNAME = "JUnit";
     public final static String USER_4_LASTNAME = "4";
@@ -867,7 +801,6 @@ public abstract class BaseTest {
     @SuppressWarnings("java:S2068")
     public final static String USER_4_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit4 */;
     public final static String USER_4_QUALIFIED_NAME = USER_4_FIRSTNAME + " " + USER_4_LASTNAME + " — @" + USER_4_USERNAME;
-    public final static String USER_4_EMAIL = "junit4@ossdip.at";
     public final static Boolean USER_4_VERIFIED = true;
     public final static Boolean USER_4_ENABLED = true;
     public final static Boolean USER_4_IS_INTERNAL = false;
@@ -884,8 +817,8 @@ public abstract class BaseTest {
 
     public final static User USER_4 = User.builder()
             .id(USER_4_ID)
+            .keycloakId(USER_4_KEYCLOAK_ID)
             .username(USER_4_USERNAME)
-            .email(USER_4_EMAIL)
             .firstname(USER_4_FIRSTNAME)
             .lastname(USER_4_LASTNAME)
             .affiliation(USER_4_AFFILIATION)
@@ -917,7 +850,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_4_DETAILS = UserDetailsDto.builder()
             .id(USER_4_ID.toString())
             .username(USER_4_USERNAME)
-            .email(USER_4_EMAIL)
             .password(USER_4_PASSWORD)
             .authorities(new LinkedList<>())
             .build();
@@ -925,19 +857,8 @@ public abstract class BaseTest {
     public final static Principal USER_4_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_4_DETAILS,
             USER_4_PASSWORD, USER_4_DETAILS.getAuthorities());
 
-    public final static PrivilegedUserDto USER_4_PRIVILEGED_DTO = PrivilegedUserDto.builder()
-            .id(USER_4_ID)
-            .username(USER_4_USERNAME)
-            .password(USER_4_PASSWORD)
-            .attributes(USER_4_ATTRIBUTES_DTO)
-            .firstname(USER_4_FIRSTNAME)
-            .lastname(USER_4_LASTNAME)
-            .qualifiedName(USER_4_QUALIFIED_NAME)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static UUID USER_5_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630");
-    public final static UUID USER_5_LDAP_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630");
+    public final static UUID USER_5_KEYCLOAK_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630");
     public final static String USER_5_USERNAME = "nobody";
     public final static String USER_5_FIRSTNAME = "No";
     public final static String USER_5_LASTNAME = "Body";
@@ -949,7 +870,6 @@ public abstract class BaseTest {
     @SuppressWarnings("java:S2068")
     public final static String USER_5_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */;
     public final static String USER_5_QUALIFIED_NAME = USER_5_FIRSTNAME + " " + USER_5_LASTNAME + " — @" + USER_5_USERNAME;
-    public final static String USER_5_EMAIL = "system@ossdip.at";
     public final static Boolean USER_5_VERIFIED = true;
     public final static Boolean USER_5_ENABLED = true;
     public final static Boolean USER_5_IS_INTERNAL = false;
@@ -973,17 +893,6 @@ public abstract class BaseTest {
             .attributes(USER_5_ATTRIBUTES_DTO)
             .build();
 
-    public final static PrivilegedUserDto USER_5_PRIVILEGED_DTO = PrivilegedUserDto.builder()
-            .id(USER_5_ID)
-            .username(USER_5_USERNAME)
-            .firstname(USER_5_FIRSTNAME)
-            .lastname(USER_5_LASTNAME)
-            .qualifiedName(USER_5_QUALIFIED_NAME)
-            .password(USER_5_PASSWORD)
-            .attributes(USER_5_ATTRIBUTES_DTO)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static UserBriefDto USER_5_BRIEF_DTO = UserBriefDto.builder()
             .id(USER_5_ID)
             .username(USER_5_USERNAME)
@@ -995,7 +904,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_5_DETAILS = UserDetailsDto.builder()
             .id(USER_5_ID.toString())
             .username(USER_5_USERNAME)
-            .email(USER_5_EMAIL)
             .password(USER_5_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES)
             .build();
@@ -1005,8 +913,8 @@ public abstract class BaseTest {
 
     public final static User USER_5 = User.builder()
             .id(USER_5_ID)
+            .keycloakId(USER_5_KEYCLOAK_ID)
             .username(USER_5_USERNAME)
-            .email(USER_5_EMAIL)
             .firstname(USER_5_FIRSTNAME)
             .lastname(USER_5_LASTNAME)
             .affiliation(USER_5_AFFILIATION)
@@ -1026,7 +934,6 @@ public abstract class BaseTest {
     public final static String USER_6_PASSWORD = "junit5";
     @SuppressWarnings("java:S2068")
     public final static String USER_6_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */;
-    public final static String USER_6_EMAIL = "system@ossdip.at";
     public final static Boolean USER_6_VERIFIED = true;
     public final static Boolean USER_6_ENABLED = true;
     public final static Boolean USER_6_IS_INTERNAL = false;
@@ -1044,7 +951,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_6_DETAILS = UserDetailsDto.builder()
             .id(USER_6_ID.toString())
             .username(USER_6_USERNAME)
-            .email(USER_6_EMAIL)
             .password(USER_6_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
@@ -1137,8 +1043,6 @@ public abstract class BaseTest {
                     .build()));
 
     public final static Long CONTAINER_1_ID = 1L;
-    public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
-    public final static ImageDto CONTAINER_1_IMAGE_DTO = IMAGE_1_DTO;
     public final static String CONTAINER_1_NAME = "u01";
     public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01";
     public final static String CONTAINER_1_UI_HOST = "localhost";
@@ -1157,7 +1061,7 @@ public abstract class BaseTest {
             .id(CONTAINER_1_ID)
             .name(CONTAINER_1_NAME)
             .internalName(CONTAINER_1_INTERNALNAME)
-            .image(CONTAINER_1_IMAGE)
+            .image(IMAGE_1)
             .created(CONTAINER_1_CREATED)
             .host(CONTAINER_1_HOST)
             .port(CONTAINER_1_PORT)
@@ -1173,7 +1077,7 @@ public abstract class BaseTest {
             .id(CONTAINER_1_ID)
             .name(CONTAINER_1_NAME)
             .internalName(CONTAINER_1_INTERNALNAME)
-            .image(CONTAINER_1_IMAGE_DTO)
+            .image(IMAGE_1_DTO)
             .host(CONTAINER_1_HOST)
             .port(CONTAINER_1_PORT)
             .build();
@@ -1187,16 +1091,16 @@ public abstract class BaseTest {
             .image(IMAGE_1_BRIEF_DTO)
             .build();
 
-    public final static PrivilegedContainerDto CONTAINER_1_PRIVILEGED_DTO = PrivilegedContainerDto.builder()
+    public final static ContainerDto CONTAINER_1_PRIVILEGED_DTO = ContainerDto.builder()
             .id(CONTAINER_1_ID)
             .name(CONTAINER_1_NAME)
             .internalName(CONTAINER_1_INTERNALNAME)
-            .image(CONTAINER_1_IMAGE_DTO)
+            .image(IMAGE_1_DTO)
             .host(CONTAINER_1_HOST)
             .port(CONTAINER_1_PORT)
+            .lastRetrieved(Instant.now())
             .username(CONTAINER_1_PRIVILEGED_USERNAME)
             .password(CONTAINER_1_PRIVILEGED_PASSWORD)
-            .lastRetrieved(Instant.now())
             .build();
 
     public final static Long CONTAINER_2_ID = 2L;
@@ -1243,16 +1147,16 @@ public abstract class BaseTest {
             .quota(CONTAINER_2_QUOTA)
             .build();
 
-    public final static PrivilegedContainerDto CONTAINER_2_PRIVILEGED_DTO = PrivilegedContainerDto.builder()
+    public final static ContainerDto CONTAINER_2_PRIVILEGED_DTO = ContainerDto.builder()
             .id(CONTAINER_2_ID)
             .name(CONTAINER_2_NAME)
             .internalName(CONTAINER_2_INTERNALNAME)
             .image(CONTAINER_2_IMAGE_DTO)
             .host(CONTAINER_2_HOST)
             .port(CONTAINER_2_PORT)
+            .lastRetrieved(Instant.now())
             .username(CONTAINER_2_PRIVILEGED_USERNAME)
             .password(CONTAINER_2_PRIVILEGED_PASSWORD)
-            .lastRetrieved(Instant.now())
             .build();
 
     public final static Long CONTAINER_3_ID = 3L;
@@ -1331,18 +1235,15 @@ public abstract class BaseTest {
     public final static String DATABASE_1_EXCHANGE = "dbrepo";
     public final static Instant DATABASE_1_CREATED = Instant.ofEpochSecond(1677399741L) /* 2023-02-26 08:22:21 (UTC) */;
     public final static Instant DATABASE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399741L) /* 2023-02-26 08:22:21 (UTC) */;
-    public final static UUID DATABASE_1_OWNER = USER_1_ID;
     public final static UUID DATABASE_1_CREATED_BY = USER_1_ID;
-    public final static UserDto DATABASE_1_CREATOR_DTO = USER_1_DTO;
-    public final static UserDto DATABASE_1_OWNER_DTO = USER_1_DTO;
 
-    public final static DatabaseCreateDto DATABASE_1_CREATE = DatabaseCreateDto.builder()
+    public final static CreateDatabaseDto DATABASE_1_CREATE = CreateDatabaseDto.builder()
             .name(DATABASE_1_NAME)
             .isPublic(DATABASE_1_PUBLIC)
             .cid(CONTAINER_1_ID)
             .build();
 
-    public final static CreateDatabaseDto DATABASE_1_CREATE_INTERNAL = CreateDatabaseDto.builder()
+    public final static at.tuwien.api.database.internal.CreateDatabaseDto DATABASE_1_CREATE_INTERNAL = at.tuwien.api.database.internal.CreateDatabaseDto.builder()
             .internalName(DATABASE_1_INTERNALNAME)
             .containerId(CONTAINER_1_ID)
             .username(USER_1_USERNAME)
@@ -1364,7 +1265,7 @@ public abstract class BaseTest {
     public final static UUID DATABASE_2_OWNER = USER_2_ID;
     public final static UUID DATABASE_2_CREATOR = USER_2_ID;
 
-    public final static DatabaseCreateDto DATABASE_2_CREATE = DatabaseCreateDto.builder()
+    public final static CreateDatabaseDto DATABASE_2_CREATE = CreateDatabaseDto.builder()
             .name(DATABASE_2_NAME)
             .isPublic(DATABASE_2_PUBLIC)
             .cid(CONTAINER_1_ID)
@@ -1384,16 +1285,43 @@ public abstract class BaseTest {
     public final static DatabaseDto DATABASE_3_DTO = DatabaseDto.builder()
             .id(DATABASE_3_ID)
             .isPublic(DATABASE_3_PUBLIC)
+            .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC)
             .name(DATABASE_3_NAME)
-            .container(CONTAINER_1_BRIEF_DTO)
             .internalName(DATABASE_3_INTERNALNAME)
+            .owner(USER_3_BRIEF_DTO)
+            .container(CONTAINER_1_DTO)
             .exchangeName(DATABASE_3_EXCHANGE)
-            .tables(new LinkedList<>()) /* TABLE_3, TABLE_3, TABLE_3 */
-            .views(new LinkedList<>())
+            .tables(new LinkedList<>()) /* TABLE_8_DTO */
+            .views(new LinkedList<>()) /* VIEW_5_DTO */
+            .identifiers(new LinkedList<>()) /* IDENTIFIER_6_DTO */
+            .build();
+
+    public final static DatabaseDto DATABASE_3_PRIVILEGED_DTO = DatabaseDto.builder()
+            .id(DATABASE_3_ID)
+            .isPublic(DATABASE_3_PUBLIC)
+            .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC)
+            .name(DATABASE_3_NAME)
+            .internalName(DATABASE_3_INTERNALNAME)
+            .owner(USER_3_BRIEF_DTO)
+            .container(CONTAINER_1_PRIVILEGED_DTO)
+            .exchangeName(DATABASE_3_EXCHANGE)
+            .tables(new LinkedList<>()) /* TABLE_8_DTO */
+            .views(new LinkedList<>()) /* VIEW_5_DTO */
+            .identifiers(new LinkedList<>()) /* IDENTIFIER_6_DTO */
+            .lastRetrieved(Instant.now())
+            .build();
+
+    public final static DatabaseBriefDto DATABASE_3_BRIEF_DTO = DatabaseBriefDto.builder()
+            .id(DATABASE_3_ID)
+            .isPublic(DATABASE_3_PUBLIC)
+            .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC)
+            .name(DATABASE_3_NAME)
+            .internalName(DATABASE_3_INTERNALNAME)
+            .ownerId(USER_3_ID)
             .identifiers(new LinkedList<>())
             .build();
 
-    public final static DatabaseCreateDto DATABASE_3_CREATE = DatabaseCreateDto.builder()
+    public final static CreateDatabaseDto DATABASE_3_CREATE = CreateDatabaseDto.builder()
             .name(DATABASE_3_NAME)
             .isPublic(DATABASE_3_PUBLIC)
             .cid(CONTAINER_1_ID)
@@ -1411,183 +1339,211 @@ public abstract class BaseTest {
     public final static UUID DATABASE_4_OWNER = USER_4_ID;
     public final static UUID DATABASE_4_CREATOR = USER_4_ID;
 
+    public final static DatabaseBriefDto DATABASE_4_BRIEF_DTO = DatabaseBriefDto.builder()
+            .id(DATABASE_4_ID)
+            .isPublic(DATABASE_4_PUBLIC)
+            .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC)
+            .name(DATABASE_4_NAME)
+            .description(DATABASE_4_DESCRIPTION)
+            .internalName(DATABASE_4_INTERNALNAME)
+            .ownerId(USER_4_ID)
+            .identifiers(new LinkedList<>())
+            .build();
+
     public final static DatabaseDto DATABASE_4_DTO = DatabaseDto.builder()
             .id(DATABASE_4_ID)
             .isPublic(DATABASE_4_PUBLIC)
             .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC)
             .name(DATABASE_4_NAME)
+            .container(CONTAINER_2_DTO)
             .description(DATABASE_4_DESCRIPTION)
             .internalName(DATABASE_4_INTERNALNAME)
             .exchangeName(DATABASE_4_EXCHANGE)
             .owner(USER_4_BRIEF_DTO)
-            .tables(new LinkedList<>())
+            .tables(new LinkedList<>()) /* TABLE_9_DTO */
             .views(new LinkedList<>())
-            .identifiers(new LinkedList<>())
+            .identifiers(new LinkedList<>()) /* IDENTIFIER_7_DTO */
             .build();
 
-    public final static TableCreateDto TABLE_0_CREATE_DTO = TableCreateDto.builder()
+    public final static DatabaseDto DATABASE_4_PRIVILEGED_DTO = DatabaseDto.builder()
+            .id(DATABASE_4_ID)
+            .isPublic(DATABASE_4_PUBLIC)
+            .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC)
+            .name(DATABASE_4_NAME)
+            .container(CONTAINER_2_PRIVILEGED_DTO)
+            .description(DATABASE_4_DESCRIPTION)
+            .internalName(DATABASE_4_INTERNALNAME)
+            .exchangeName(DATABASE_4_EXCHANGE)
+            .owner(USER_4_BRIEF_DTO)
+            .tables(new LinkedList<>()) /* TABLE_9_DTO */
+            .views(new LinkedList<>())
+            .identifiers(new LinkedList<>()) /* IDENTIFIER_7_DTO */
+            .lastRetrieved(Instant.now())
+            .build();
+
+    public final static CreateTableDto TABLE_0_CREATE_DTO = CreateTableDto.builder()
             .name("full")
             .description("full example")
-            .constraints(ConstraintsCreateDto.builder()
+            .constraints(CreateTableConstraintsDto.builder()
                     .uniques(new LinkedList<>())
                     .foreignKeys(new LinkedList<>())
                     .build())
-            .columns(List.of(ColumnCreateDto.builder()
+            .columns(List.of(CreateTableColumnDto.builder()
                             .name("col1a")
                             .type(ColumnTypeDto.CHAR)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col1b")
                             .type(ColumnTypeDto.CHAR)
                             .nullAllowed(true)
                             .size(50L)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col2a")
                             .type(ColumnTypeDto.VARCHAR)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col2b")
                             .type(ColumnTypeDto.VARCHAR)
                             .nullAllowed(true)
                             .size(1024L)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col3")
                             .type(ColumnTypeDto.BINARY)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col4")
                             .type(ColumnTypeDto.VARBINARY)
                             .nullAllowed(true)
                             .size(200L)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col5")
                             .type(ColumnTypeDto.TINYBLOB)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col6")
                             .type(ColumnTypeDto.TINYTEXT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col7")
                             .type(ColumnTypeDto.TEXT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col8")
                             .type(ColumnTypeDto.BLOB)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col9")
                             .type(ColumnTypeDto.MEDIUMTEXT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col10")
                             .type(ColumnTypeDto.MEDIUMBLOB)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col11")
                             .type(ColumnTypeDto.LONGTEXT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col12")
                             .type(ColumnTypeDto.LONGBLOB)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col13")
                             .type(ColumnTypeDto.ENUM)
                             .nullAllowed(true)
                             .enums(new LinkedList<>(List.of("val1", "val2")))
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col14")
                             .type(ColumnTypeDto.SET)
                             .nullAllowed(true)
                             .sets(new LinkedList<>(List.of("val1", "val2")))
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col15")
                             .type(ColumnTypeDto.BIT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col16")
                             .type(ColumnTypeDto.TINYINT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col17")
                             .type(ColumnTypeDto.BOOL)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col18")
                             .type(ColumnTypeDto.SMALLINT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col19")
                             .type(ColumnTypeDto.MEDIUMINT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col20")
                             .type(ColumnTypeDto.INT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col21")
                             .type(ColumnTypeDto.BIGINT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col22")
                             .type(ColumnTypeDto.FLOAT)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col23")
                             .type(ColumnTypeDto.DOUBLE)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col24")
                             .type(ColumnTypeDto.DECIMAL)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col25")
                             .type(ColumnTypeDto.DATE)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col26")
                             .type(ColumnTypeDto.DATETIME)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col27")
                             .type(ColumnTypeDto.TIMESTAMP)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col28")
                             .type(ColumnTypeDto.TIME)
                             .nullAllowed(true)
                             .build(),
-                    ColumnCreateDto.builder()
+                    CreateTableColumnDto.builder()
                             .name("col29")
                             .type(ColumnTypeDto.YEAR)
                             .nullAllowed(true)
@@ -1612,10 +1568,9 @@ public abstract class BaseTest {
     public final static Instant TABLE_1_CREATED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */;
     public final static Instant TABLE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */;
 
-    public final static PrivilegedTableDto TABLE_1_PRIVILEGED_DTO = PrivilegedTableDto.builder()
+    public final static TableDto TABLE_1_PRIVILEGED_DTO = TableDto.builder()
             .id(TABLE_1_ID)
             .tdbid(DATABASE_1_ID)
-            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .internalName(TABLE_1_INTERNAL_NAME)
             .isVersioned(TABLE_1_VERSIONED)
             .isPublic(TABLE_1_SCHEMA_PUBLIC)
@@ -1633,6 +1588,7 @@ public abstract class BaseTest {
             .dataLength(TABLE_1_DATA_LENGTH)
             .maxDataLength(TABLE_1_MAX_DATA_LENGTH)
             .lastRetrieved(Instant.now())
+            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .build();
 
     public final static Table TABLE_1 = Table.builder()
@@ -1672,7 +1628,7 @@ public abstract class BaseTest {
             .routingKey(TABLE_1_ROUTING_KEY)
             .identifiers(new LinkedList<>())
             .columns(new LinkedList<>() /* TABLE_1_COLUMNS_DTO */)
-            .constraints(null) /* TABLE_1_CONSTRAINT_DTO */
+            .constraints(null) /* TABLE_1_CONSTRAINTS_DTO */
             .owner(USER_1_BRIEF_DTO)
             .avgRowLength(TABLE_1_AVG_ROW_LENGTH)
             .numRows(TABLE_1_NUM_ROWS)
@@ -1826,10 +1782,9 @@ public abstract class BaseTest {
             .maxDataLength(TABLE_2_MAX_DATA_LENGTH)
             .build();
 
-    public final static PrivilegedTableDto TABLE_2_PRIVILEGED_DTO = PrivilegedTableDto.builder()
+    public final static TableDto TABLE_2_PRIVILEGED_DTO = TableDto.builder()
             .id(TABLE_2_ID)
             .tdbid(DATABASE_1_ID)
-            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .internalName(TABLE_2_INTERNALNAME)
             .isVersioned(TABLE_2_VERSIONED)
             .isPublic(TABLE_2_IS_PUBLIC)
@@ -1847,6 +1802,7 @@ public abstract class BaseTest {
             .dataLength(TABLE_2_DATA_LENGTH)
             .maxDataLength(TABLE_2_MAX_DATA_LENGTH)
             .lastRetrieved(Instant.now())
+            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .build();
 
     public final static TableDto TABLE_2_DTO = TableDto.builder()
@@ -1953,32 +1909,32 @@ public abstract class BaseTest {
             .ownedBy(USER_3_ID)
             .build();
 
-    public final static ConstraintsCreateDto TABLE_3_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_3_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder()
             .checks(new LinkedHashSet<>())
             .primaryKey(new LinkedHashSet<>())
             .foreignKeys(new LinkedList<>())
             .uniques(new LinkedList<>())
             .build();
 
-    public final static ConstraintsCreateDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = CreateTableConstraintsDto.builder()
             .checks(new LinkedHashSet<>())
             .primaryKey(new LinkedHashSet<>()) // <<<<
             .uniques(new LinkedList<>())
-            .foreignKeys(List.of(ForeignKeyCreateDto.builder()
+            .foreignKeys(List.of(CreateForeignKeyDto.builder()
                     .referencedTable("weather_location")
                     .columns(new LinkedList<>(List.of("fahrzeug")))
                     .referencedColumns(new LinkedList<>(List.of("doesnotexist")))
                     .build()))
             .build();
 
-    public final static TableCreateDto TABLE_3_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_3_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_3_NAME)
             .description(TABLE_3_DESCRIPTION)
             .columns(new LinkedList<>())
             .constraints(TABLE_3_CONSTRAINTS_CREATE_DTO)
             .build();
 
-    public final static TableCreateDto TABLE_3_INVALID_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_3_INVALID_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_3_NAME)
             .description(TABLE_3_DESCRIPTION)
             .columns(new LinkedList<>())
@@ -2036,10 +1992,9 @@ public abstract class BaseTest {
             .owner(USER_1_BRIEF_DTO)
             .build();
 
-    public final static PrivilegedTableDto TABLE_5_PRIVILEGED_DTO = PrivilegedTableDto.builder()
+    public final static TableDto TABLE_5_PRIVILEGED_DTO = TableDto.builder()
             .id(TABLE_5_ID)
             .tdbid(DATABASE_2_ID)
-            .database(null) /* DATABASE_2_PRIVILEGED_DTO */
             .internalName(TABLE_5_INTERNALNAME)
             .isVersioned(TABLE_5_VERSIONED)
             .isPublic(TABLE_5_IS_PUBLIC)
@@ -2077,7 +2032,7 @@ public abstract class BaseTest {
     public final static String TABLE_6_INTERNALNAME = "names";
     public final static Boolean TABLE_6_VERSIONED = true;
     public final static Boolean TABLE_6_IS_PUBLIC = true;
-    public final static Boolean TABLE_6_SCHEMA_PUBLIC = true;
+    public final static Boolean TABLE_6_SCHEMA_PUBLIC = false;
     public final static Boolean TABLE_6_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_6_DESCRIPTION = "Some names dataset";
     public final static String TABLE_6_QUEUE_NAME = TABLE_6_INTERNALNAME;
@@ -2196,9 +2151,8 @@ public abstract class BaseTest {
     public final static String TABLE_4_NAME = "Sensor 2";
     public final static String TABLE_4_INTERNALNAME = "sensor_2";
     public final static Boolean TABLE_4_VERSIONED = true;
-    public final static Boolean TABLE_4_IS_PUBLIC = false;
+    public final static Boolean TABLE_4_IS_PUBLIC = true;
     public final static Boolean TABLE_4_SCHEMA_PUBLIC = false;
-    public final static Boolean TABLE_4_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_4_DESCRIPTION = "Hello sensor";
     public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNALNAME;
     public final static String TABLE_4_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_4_ID;
@@ -2252,6 +2206,28 @@ public abstract class BaseTest {
             .maxDataLength(TABLE_4_MAX_DATA_LENGTH)
             .build();
 
+    public final static TableDto TABLE_4_PRIVILEGED_DTO = TableDto.builder()
+            .id(TABLE_4_ID)
+            .tdbid(DATABASE_1_ID)
+            .internalName(TABLE_4_INTERNALNAME)
+            .description(TABLE_4_DESCRIPTION)
+            .name(TABLE_4_NAME)
+            .queueName(TABLE_4_QUEUE_NAME)
+            .routingKey(TABLE_4_ROUTING_KEY)
+            .database(null) /* DATABASE_1_DTO */
+            .columns(new LinkedList<>()) /* TABLE_4_COLUMNS_DTO */
+            .constraints(null) /* TABLE_4_CONSTRAINTS_DTO */
+            .isVersioned(TABLE_4_VERSIONED)
+            .isPublic(TABLE_4_IS_PUBLIC)
+            .isSchemaPublic(TABLE_4_SCHEMA_PUBLIC)
+            .owner(USER_1_BRIEF_DTO)
+            .avgRowLength(TABLE_4_AVG_ROW_LENGTH)
+            .numRows(TABLE_4_NUM_ROWS)
+            .dataLength(TABLE_4_DATA_LENGTH)
+            .maxDataLength(TABLE_4_MAX_DATA_LENGTH)
+            .lastRetrieved(Instant.now())
+            .build();
+
     public final static TableBriefDto TABLE_4_BRIEF_DTO = TableBriefDto.builder()
             .id(TABLE_4_ID)
             .databaseId(DATABASE_1_ID)
@@ -2294,12 +2270,12 @@ public abstract class BaseTest {
                     .isNullAllowed(true)
                     .build());
 
-    public final static List<ColumnCreateDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder()
+    public final static List<CreateTableColumnDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder()
                     .name("Timestamp")
                     .type(ColumnTypeDto.TIMESTAMP)
                     .nullAllowed(false)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Value")
                     .type(ColumnTypeDto.DECIMAL)
                     .nullAllowed(true)
@@ -2307,14 +2283,14 @@ public abstract class BaseTest {
                     .d(10L)
                     .build());
 
-    public final static ConstraintsCreateDto TABLE_4_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_4_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder()
             .checks(new LinkedHashSet<>())
             .primaryKey(new LinkedHashSet<>(Set.of("Timestamp")))
             .foreignKeys(new LinkedList<>())
             .uniques(new LinkedList<>(List.of(List.of("Timestamp"))))
             .build();
 
-    public final static TableCreateDto TABLE_4_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_4_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_4_NAME)
             .description(TABLE_4_DESCRIPTION)
             .columns(TABLE_4_COLUMNS_CREATE_DTO)
@@ -2354,7 +2330,6 @@ public abstract class BaseTest {
     public final static Boolean TABLE_8_VERSIONED = true;
     public final static Boolean TABLE_8_IS_PUBLIC = false;
     public final static Boolean TABLE_8_SCHEMA_PUBLIC = false;
-    public final static Boolean TABLE_8_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_8_DESCRIPTION = "Hello mfcc";
     public final static String TABLE_8_QUEUE_NAME = TABLE_8_INTERNAL_NAME;
     public final static String TABLE_8_ROUTING_KEY = "dbrepo\\." + DATABASE_3_ID + "\\." + TABLE_8_ID;
@@ -2407,7 +2382,7 @@ public abstract class BaseTest {
             .ownedBy(USER_1_ID)
             .build();
 
-    public final static PrivilegedTableDto TABLE_8_PRIVILEGED_DTO = PrivilegedTableDto.builder()
+    public final static TableDto TABLE_8_PRIVILEGED_DTO = TableDto.builder()
             .id(TABLE_8_ID)
             .tdbid(TABLE_8_DATABASE_ID)
             .internalName(TABLE_8_INTERNAL_NAME)
@@ -2483,7 +2458,7 @@ public abstract class BaseTest {
             .ownedBy(USER_1_ID)
             .build();
 
-    public final static PrivilegedTableDto TABLE_9_PRIVILEGED_DTO = PrivilegedTableDto.builder()
+    public final static TableDto TABLE_9_PRIVILEGED_DTO = TableDto.builder()
             .id(TABLE_9_ID)
             .tdbid(TABLE_9_DATABASE_ID)
             .internalName(TABLE_9_INTERNAL_NAME)
@@ -2918,6 +2893,33 @@ public abstract class BaseTest {
             .resultNumber(3L)
             .build();
 
+    public final static ViewDto QUERY_1_VIEW_DTO = ViewDto.builder()
+            .vdbid(QUERY_1_DATABASE_ID)
+            .query(QUERY_1_STATEMENT)
+            .queryHash(QUERY_1_QUERY_HASH)
+            .owner(USER_1_BRIEF_DTO)
+            .columns(new LinkedList<>(List.of(ViewColumnDto.builder()
+                            .name("id")
+                            .internalName("id")
+                            .build(),
+                    ViewColumnDto.builder()
+                            .name("date")
+                            .internalName("date")
+                            .build(),
+                    ViewColumnDto.builder()
+                            .name("location")
+                            .internalName("location")
+                            .build(),
+                    ViewColumnDto.builder()
+                            .name("mintemp")
+                            .internalName("mintemp")
+                            .build(),
+                    ViewColumnDto.builder()
+                            .name("rainfall")
+                            .internalName("rainfall")
+                            .build())))
+            .build();
+
     public final static QueryBriefDto QUERY_1_BRIEF_DTO = QueryBriefDto.builder()
             .id(QUERY_1_ID)
             .databaseId(QUERY_1_DATABASE_ID)
@@ -2979,7 +2981,7 @@ public abstract class BaseTest {
             .isPersisted(QUERY_3_PERSISTED)
             .resultNumber(2L)
             .build();
-    
+
     public final static Long QUERY_7_ID = 7L;
     public final static String QUERY_7_STATEMENT = "SELECT id, date, a.location, lat, lng FROM weather_aus a JOIN weather_location l on a.location = l.location WHERE date = '2008-12-01'";
     public final static String QUERY_7_QUERY_HASH = "df7da3801dfb5c191ff6711d79ce6455f3c09ec8323ce1ff7208ab85387263f5";
@@ -3089,6 +3091,21 @@ public abstract class BaseTest {
             .owner(USER_1_BRIEF_DTO)
             .build();
 
+    public final static ViewDto QUERY_5_VIEW_DTO = ViewDto.builder()
+            .vdbid(DATABASE_3_ID)
+            .query(QUERY_5_STATEMENT)
+            .queryHash(QUERY_5_QUERY_HASH)
+            .owner(USER_1_BRIEF_DTO)
+            .columns(new LinkedList<>(List.of(ViewColumnDto.builder()
+                            .name("id")
+                            .internalName("id")
+                            .build(),
+                    ViewColumnDto.builder()
+                            .name("value")
+                            .internalName("value")
+                            .build())))
+            .build();
+
     public final static List<Map<String, Object>> QUERY_5_RESULT_DTO = new LinkedList<>(List.of(
             Map.of("id", BigInteger.valueOf(1L), "value", 11.2),
             Map.of("id", BigInteger.valueOf(2L), "value", 11.3),
@@ -3191,32 +3208,32 @@ public abstract class BaseTest {
                     .isNullAllowed(true)
                     .build());
 
-    public final static List<ColumnCreateDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder()
+    public final static List<CreateTableColumnDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder()
                     .name("id")
                     .type(ColumnTypeDto.BIGINT)
                     .nullAllowed(false)
                     .enums(null)
                     .sets(null)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Date")
                     .type(ColumnTypeDto.DATE)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Location")
                     .type(ColumnTypeDto.VARCHAR)
                     .size(255L)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("MinTemp")
                     .type(ColumnTypeDto.DECIMAL)
                     .size(10L)
                     .d(0L)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Rainfall")
                     .type(ColumnTypeDto.DECIMAL)
                     .size(10L)
@@ -3226,21 +3243,21 @@ public abstract class BaseTest {
                     .unitUri(UNIT_1_URI)
                     .build());
 
-    public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_1_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder()
             .checks(new LinkedHashSet<>())
             .primaryKey(new LinkedHashSet<>(List.of("id")))
             .foreignKeys(new LinkedList<>())
             .uniques(new LinkedList<>(List.of(List.of("date"))))
             .build();
 
-    public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = CreateTableConstraintsDto.builder()
             .checks(new LinkedHashSet<>())
             .primaryKey(new LinkedHashSet<>())
             .foreignKeys(new LinkedList<>())
             .uniques(new LinkedList<>(List.of(List.of("date"))))
             .build();
 
-    public final static TableCreateDto TABLE_1_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_1_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_1_NAME)
             .description(TABLE_1_DESCRIPTION)
             .columns(TABLE_1_COLUMNS_CREATE_DTO)
@@ -3360,6 +3377,31 @@ public abstract class BaseTest {
                     .sets(null)
                     .build());
 
+    public final static List<ColumnBriefDto> TABLE_2_COLUMNS_BRIEF_DTO = List.of(ColumnBriefDto.builder()
+                    .id(COLUMN_2_1_ID)
+                    .tableId(TABLE_2_ID)
+                    .databaseId(DATABASE_1_ID)
+                    .name("location")
+                    .internalName("location")
+                    .columnType(ColumnTypeDto.VARCHAR)
+                    .build(),
+            ColumnBriefDto.builder()
+                    .id(COLUMN_2_2_ID)
+                    .tableId(TABLE_2_ID)
+                    .databaseId(DATABASE_1_ID)
+                    .name("lat")
+                    .internalName("lat")
+                    .columnType(ColumnTypeDto.DOUBLE)
+                    .build(),
+            ColumnBriefDto.builder()
+                    .id(COLUMN_2_3_ID)
+                    .tableId(TABLE_2_ID)
+                    .databaseId(DATABASE_1_ID)
+                    .name("lng")
+                    .internalName("lng")
+                    .columnType(ColumnTypeDto.DOUBLE)
+                    .build());
+
     public final static Long COLUMN_3_1_ID = 9L;
 
     public final static Long COLUMN_3_2_ID = 10L;
@@ -4638,137 +4680,137 @@ public abstract class BaseTest {
                     .isNullAllowed(true)
                     .build());
 
-    public final static List<ForeignKeyCreateDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(ForeignKeyCreateDto.builder()
+    public final static List<CreateForeignKeyDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(CreateForeignKeyDto.builder()
             .columns(new LinkedList<>(List.of("somecolumn")))
             .referencedTable("sometable")
             .referencedColumns(new LinkedList<>(List.of("someothercolumn")))
             .build());
 
-    public final static ConstraintsCreateDto TABLE_5_CONSTRAINTS_INVALID_CREATE = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_5_CONSTRAINTS_INVALID_CREATE = CreateTableConstraintsDto.builder()
             .foreignKeys(TABLE_5_FOREIGN_KEYS_INVALID_CREATE)
             .build();
 
-    public final static List<ColumnCreateDto> TABLE_5_COLUMNS_CREATE = List.of(ColumnCreateDto.builder()
+    public final static List<CreateTableColumnDto> TABLE_5_COLUMNS_CREATE = List.of(CreateTableColumnDto.builder()
                     .name("id")
                     .type(ColumnTypeDto.BIGINT)
                     .nullAllowed(false)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Animal Name")
                     .type(ColumnTypeDto.VARCHAR)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Hair")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Feathers")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Bread")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Eggs")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Milk")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Water")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Airborne")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Waterborne")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Aquantic")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Predator")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Backbone")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Breathes")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Venomous")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Fin")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Legs")
                     .type(ColumnTypeDto.INT)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Tail")
                     .type(ColumnTypeDto.DECIMAL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Domestic")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Catsize")
                     .type(ColumnTypeDto.BOOL)
                     .nullAllowed(true)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("Class Type")
                     .type(ColumnTypeDto.DECIMAL)
                     .nullAllowed(true)
                     .build());
 
-    public final static ConstraintsCreateDto TABLE_5_CREATE_CONSTRAINTS_DTO = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_5_CREATE_CONSTRAINTS_DTO = CreateTableConstraintsDto.builder()
             .primaryKey(Set.of("id"))
             .uniques(new LinkedList<>(List.of(List.of("id"))))
             .checks(new LinkedHashSet<>())
             .foreignKeys(new LinkedList<>())
             .build();
 
-    public final static TableCreateDto TABLE_5_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_5_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_5_NAME)
             .description(TABLE_5_DESCRIPTION)
             .columns(TABLE_5_COLUMNS_CREATE)
             .constraints(TABLE_5_CREATE_CONSTRAINTS_DTO)
             .build();
 
-    public final static TableCreateDto TABLE_5_INVALID_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_5_INVALID_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_5_NAME)
             .description(TABLE_5_DESCRIPTION)
             .columns(TABLE_5_COLUMNS_CREATE)
@@ -4895,7 +4937,7 @@ public abstract class BaseTest {
     public final static List<List<String>> TABLE_6_UNIQUES_CREATE = List.of(
             List.of("firstname", "lastname"));
 
-    public final static List<ForeignKeyCreateDto> TABLE_6_FOREIGN_KEYS_CREATE = List.of(ForeignKeyCreateDto.builder()
+    public final static List<CreateForeignKeyDto> TABLE_6_FOREIGN_KEYS_CREATE = List.of(CreateForeignKeyDto.builder()
             .columns(new LinkedList<>(List.of("ref_id")))
             .referencedTable("zoo")
             .referencedColumns(new LinkedList<>(List.of("id")))
@@ -4903,27 +4945,27 @@ public abstract class BaseTest {
 
     public final static Set<String> TABLE_6_CHECKS_CREATE = Set.of("firstname != lastname");
 
-    public final static ConstraintsCreateDto TABLE_6_CONSTRAINTS_CREATE = ConstraintsCreateDto.builder()
+    public final static CreateTableConstraintsDto TABLE_6_CONSTRAINTS_CREATE = CreateTableConstraintsDto.builder()
             .uniques(TABLE_6_UNIQUES_CREATE)
             .foreignKeys(TABLE_6_FOREIGN_KEYS_CREATE)
             .checks(TABLE_6_CHECKS_CREATE)
             .primaryKey(Set.of("id"))
             .build();
 
-    public final static List<ColumnCreateDto> TABLE_6_COLUMNS_CREATE = List.of(
-            ColumnCreateDto.builder()
+    public final static List<CreateTableColumnDto> TABLE_6_COLUMNS_CREATE = List.of(
+            CreateTableColumnDto.builder()
                     .name("name_id")
                     .type(ColumnTypeDto.BIGINT)
                     .nullAllowed(false)
                     .build(),
-            ColumnCreateDto.builder()
+            CreateTableColumnDto.builder()
                     .name("zoo_id")
                     .type(ColumnTypeDto.BIGINT)
                     .size(255L)
                     .nullAllowed(false)
                     .build());
 
-    public final static TableCreateDto TABLE_6_CREATE_DTO = TableCreateDto.builder()
+    public final static CreateTableDto TABLE_6_CREATE_DTO = CreateTableDto.builder()
             .name(TABLE_6_NAME)
             .description(TABLE_6_DESCRIPTION)
             .columns(TABLE_6_COLUMNS_CREATE)
@@ -4992,8 +5034,8 @@ public abstract class BaseTest {
     public final static String VIEW_1_INTERNAL_NAME = "junit";
     public final static Long VIEW_1_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_1_DATABASE_ID = DATABASE_1_ID;
-    public final static Boolean VIEW_1_PUBLIC = true;
-    public final static Boolean VIEW_1_SCHEMA_PUBLIC = true;
+    public final static Boolean VIEW_1_PUBLIC = false;
+    public final static Boolean VIEW_1_SCHEMA_PUBLIC = false;
     public final static String VIEW_1_QUERY = "select `location`, `lat`, `lng` from `weather_location`";
     public final static String VIEW_1_QUERY_HASH = "dc81a6877c7c51a6a6f406e1fc2a255e44a0d49a20548596e0d583c3eb849c23";
 
@@ -5117,10 +5159,9 @@ public abstract class BaseTest {
             .columns(VIEW_1_COLUMNS_DTO)
             .build();
 
-    public final static PrivilegedViewDto VIEW_1_PRIVILEGED_DTO = PrivilegedViewDto.builder()
+    public final static ViewDto VIEW_1_PRIVILEGED_DTO = ViewDto.builder()
             .id(VIEW_1_ID)
             .isInitialView(VIEW_1_INITIAL_VIEW)
-            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .name(VIEW_1_NAME)
             .internalName(VIEW_1_INTERNAL_NAME)
             .vdbid(VIEW_1_DATABASE_ID)
@@ -5130,6 +5171,7 @@ public abstract class BaseTest {
             .queryHash(VIEW_1_QUERY_HASH)
             .columns(VIEW_1_COLUMNS_DTO)
             .lastRetrieved(Instant.now())
+            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .build();
 
     public final static ViewBriefDto VIEW_1_BRIEF_DTO = ViewBriefDto.builder()
@@ -5145,7 +5187,7 @@ public abstract class BaseTest {
             .queryHash(VIEW_1_QUERY_HASH)
             .build();
 
-    public final static ViewCreateDto VIEW_1_CREATE_DTO = ViewCreateDto.builder()
+    public final static CreateViewDto VIEW_1_CREATE_DTO = CreateViewDto.builder()
             .isPublic(VIEW_1_PUBLIC)
             .name(VIEW_1_NAME)
             .query(VIEW_1_QUERY)
@@ -5279,10 +5321,9 @@ public abstract class BaseTest {
             .owner(USER_1_BRIEF_DTO)
             .build();
 
-    public final static PrivilegedViewDto VIEW_2_PRIVILEGED_DTO = PrivilegedViewDto.builder()
+    public final static ViewDto VIEW_2_PRIVILEGED_DTO = ViewDto.builder()
             .id(VIEW_2_ID)
             .isInitialView(VIEW_2_INITIAL_VIEW)
-            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .name(VIEW_2_NAME)
             .internalName(VIEW_2_INTERNAL_NAME)
             .vdbid(VIEW_2_DATABASE_ID)
@@ -5293,6 +5334,7 @@ public abstract class BaseTest {
             .queryHash(VIEW_2_QUERY_HASH)
             .columns(VIEW_2_COLUMNS_DTO)
             .lastRetrieved(Instant.now())
+            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .build();
 
     public final static ViewBriefDto VIEW_2_BRIEF_DTO = ViewBriefDto.builder()
@@ -5314,7 +5356,7 @@ public abstract class BaseTest {
     public final static String VIEW_3_INTERNAL_NAME = "junit3";
     public final static Long VIEW_3_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_3_DATABASE_ID = DATABASE_1_ID;
-    public final static Boolean VIEW_3_PUBLIC = false;
+    public final static Boolean VIEW_3_PUBLIC = true;
     public final static Boolean VIEW_3_SCHEMA_PUBLIC = false;
     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";
@@ -5380,10 +5422,9 @@ public abstract class BaseTest {
             .owner(USER_1)
             .build();
 
-    public final static PrivilegedViewDto VIEW_3_PRIVILEGED_DTO = PrivilegedViewDto.builder()
+    public final static ViewDto VIEW_3_PRIVILEGED_DTO = ViewDto.builder()
             .id(VIEW_3_ID)
             .isInitialView(VIEW_3_INITIAL_VIEW)
-            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .name(VIEW_3_NAME)
             .internalName(VIEW_3_INTERNAL_NAME)
             .vdbid(VIEW_3_DATABASE_ID)
@@ -5394,6 +5435,7 @@ public abstract class BaseTest {
             .queryHash(VIEW_3_QUERY_HASH)
             .columns(VIEW_3_COLUMNS_DTO)
             .lastRetrieved(Instant.now())
+            .database(null) /* DATABASE_1_PRIVILEGED_DTO */
             .build();
 
     public final static List<ViewColumn> VIEW_3_COLUMNS = List.of(
@@ -5476,7 +5518,7 @@ public abstract class BaseTest {
     public final static Long VIEW_4_TABLE_ID = TABLE_5_ID;
     public final static Table VIEW_4_TABLE = TABLE_5;
     public final static Boolean VIEW_4_PUBLIC = true;
-    public final static Boolean VIEW_4_SCHEMA_PUBLIC = true;
+    public final static Boolean VIEW_4_SCHEMA_PUBLIC = false;
     public final static String VIEW_4_QUERY = "SELECT `animal_name`, `hair`, `feathers`, `eggs`, `milk`, `airborne`, `aquatic`, `predator`, `backbone`, `breathes`, `venomous`, `fins`, `legs`, `tail`, `domestic`, `catsize`, `class_type` FROM `zoo` WHERE `class_type` = 1";
     public final static String VIEW_4_QUERY_HASH = "3561cd0bb0b0e94d6f15ae602134252a5760d09d660a71a4fb015b6991c8ba0b";
 
@@ -6111,13 +6153,13 @@ public abstract class BaseTest {
             .language(IDENTIFIER_1_TITLE_1_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_1_CREATE_DTO = IdentifierSaveTitleDto.builder()
+    public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder()
             .title(IDENTIFIER_1_TITLE_1_TITLE)
             .titleType(IDENTIFIER_1_TITLE_1_TYPE_DTO)
             .language(IDENTIFIER_1_TITLE_1_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_1_UPDATE_DTO = IdentifierSaveTitleDto.builder()
+    public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_1_UPDATE_DTO = SaveIdentifierTitleDto.builder()
             .title(IDENTIFIER_1_TITLE_1_TITLE_MODIFY)
             .titleType(IDENTIFIER_1_TITLE_1_TYPE_DTO)
             .language(IDENTIFIER_1_TITLE_1_LANG_DTO)
@@ -6153,13 +6195,13 @@ public abstract class BaseTest {
             .language(IDENTIFIER_1_TITLE_2_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_2_CREATE_DTO = IdentifierSaveTitleDto.builder()
+    public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_2_CREATE_DTO = SaveIdentifierTitleDto.builder()
             .title(IDENTIFIER_1_TITLE_2_TITLE)
             .titleType(IDENTIFIER_1_TITLE_2_TYPE_DTO)
             .language(IDENTIFIER_1_TITLE_2_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_2_UPDATE_DTO = IdentifierSaveTitleDto.builder()
+    public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_2_UPDATE_DTO = SaveIdentifierTitleDto.builder()
             .title(IDENTIFIER_1_TITLE_2_TITLE_MODIFY)
             .titleType(IDENTIFIER_1_TITLE_2_TYPE_DTO)
             .language(IDENTIFIER_1_TITLE_2_LANG_DTO)
@@ -6195,7 +6237,7 @@ public abstract class BaseTest {
             .language(IDENTIFIER_1_DESCRIPTION_1_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder()
+    public final static SaveIdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder()
             .id(null)
             .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION)
             .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO)
@@ -6243,7 +6285,7 @@ public abstract class BaseTest {
             .affiliationIdentifierSchemeUri(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder()
             .id(null)
             .firstname(IDENTIFIER_1_CREATOR_1_FIRSTNAME)
             .lastname(IDENTIFIER_1_CREATOR_1_LASTNAME)
@@ -6280,7 +6322,7 @@ public abstract class BaseTest {
             .awardTitle(FUNDER_1_AWARD_TITLE)
             .build();
 
-    public final static IdentifierFunderSaveDto IDENTIFIER_1_FUNDER_1_CREATE_DTO = IdentifierFunderSaveDto.builder()
+    public final static SaveIdentifierFunderDto IDENTIFIER_1_FUNDER_1_CREATE_DTO = SaveIdentifierFunderDto.builder()
             .funderName(FUNDER_1_NAME)
             .funderIdentifier(FUNDER_1_IDENTIFIER)
             .funderIdentifierType(FUNDER_1_IDENTIFIER_TYPE_DTO)
@@ -6385,7 +6427,7 @@ public abstract class BaseTest {
             .status(IDENTIFIER_1_STATUS_TYPE_DTO)
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_1_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_1_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_1_DATABASE_ID)
             .type(IDENTIFIER_1_TYPE_DTO)
             .publicationYear(IDENTIFIER_1_PUBLICATION_YEAR)
@@ -6402,7 +6444,7 @@ public abstract class BaseTest {
             .funders(new LinkedList<>(List.of(IDENTIFIER_1_FUNDER_1_CREATE_DTO)))
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_1_CREATE_WITH_DOI_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_1_CREATE_WITH_DOI_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_1_DATABASE_ID)
             .type(IDENTIFIER_1_TYPE_DTO)
             .doi(IDENTIFIER_1_DOI)
@@ -6494,7 +6536,7 @@ public abstract class BaseTest {
             .titleType(IDENTIFIER_5_TITLE_1_TYPE_DTO)
             .build();
 
-    public final static IdentifierSaveTitleDto IDENTIFIER_5_TITLE_1_CREATE_DTO = IdentifierSaveTitleDto.builder()
+    public final static SaveIdentifierTitleDto IDENTIFIER_5_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder()
             .title(IDENTIFIER_5_TITLE_1_TITLE)
             .language(IDENTIFIER_5_TITLE_1_LANG_DTO)
             .titleType(IDENTIFIER_5_TITLE_1_TYPE_DTO)
@@ -6522,7 +6564,7 @@ public abstract class BaseTest {
             .descriptionType(IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO)
             .build();
 
-    public final static IdentifierSaveDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder()
+    public final static SaveIdentifierDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder()
             .id(null)
             .description(IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION)
             .language(IDENTIFIER_5_DESCRIPTION_1_LANG_DTO)
@@ -6557,7 +6599,7 @@ public abstract class BaseTest {
             .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_5_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_1_FIRSTNAME)
             .lastname(CREATOR_1_LASTNAME)
             .creatorName(CREATOR_1_NAME)
@@ -6566,7 +6608,7 @@ public abstract class BaseTest {
             .affiliation(CREATOR_1_AFFIL)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_5_CREATOR_1_MODIFY_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_1_FIRSTNAME)
             .lastname(CREATOR_1_LASTNAME)
             .creatorName(CREATOR_1_NAME)
@@ -6597,7 +6639,7 @@ public abstract class BaseTest {
             .affiliation(CREATOR_2_AFFIL)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_5_CREATOR_2_CREATE_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_CREATE_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_2_FIRSTNAME)
             .lastname(CREATOR_2_LASTNAME)
             .creatorName(CREATOR_2_NAME)
@@ -6606,7 +6648,7 @@ public abstract class BaseTest {
             .affiliation(CREATOR_2_AFFIL)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_5_CREATOR_2_MODIFY_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_MODIFY_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_2_FIRSTNAME)
             .lastname(CREATOR_2_LASTNAME)
             .creatorName(CREATOR_2_NAME)
@@ -6690,13 +6732,13 @@ public abstract class BaseTest {
             .value(RELATED_IDENTIFIER_5_VALUE)
             .build();
 
-    public final static RelatedIdentifierSaveDto IDENTIFIER_1_RELATED_IDENTIFIER_5_CREATE_DTO = RelatedIdentifierSaveDto.builder()
+    public final static SaveRelatedIdentifierDto IDENTIFIER_1_RELATED_IDENTIFIER_5_CREATE_DTO = SaveRelatedIdentifierDto.builder()
             .value(RELATED_IDENTIFIER_5_VALUE)
             .type(RELATED_IDENTIFIER_5_TYPE_DTO)
             .relation(RELATED_IDENTIFIER_5_RELATION_TYPE_DTO)
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_5_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_5_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_5_DATABASE_ID)
             .publicationYear(IDENTIFIER_5_PUBLICATION_YEAR)
             .publisher(IDENTIFIER_5_PUBLISHER)
@@ -6765,7 +6807,7 @@ public abstract class BaseTest {
             .language(IDENTIFIER_6_TITLE_1_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveTitleDto IDENTIFIER_6_TITLE_1_CREATE_DTO = IdentifierSaveTitleDto.builder()
+    public final static SaveIdentifierTitleDto IDENTIFIER_6_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder()
             .title(IDENTIFIER_6_TITLE_1_TITLE_MODIFY)
             .language(IDENTIFIER_6_TITLE_1_LANG_DTO)
             .build();
@@ -6795,7 +6837,7 @@ public abstract class BaseTest {
             .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO)
             .build();
 
-    public final static IdentifierSaveDescriptionDto IDENTIFIER_6_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder()
+    public final static SaveIdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder()
             .id(null)
             .description(IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION_MODIFY)
             .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO)
@@ -6829,7 +6871,7 @@ public abstract class BaseTest {
             .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_6_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_1_FIRSTNAME)
             .lastname(CREATOR_1_LASTNAME)
             .creatorName(CREATOR_1_NAME)
@@ -6840,7 +6882,7 @@ public abstract class BaseTest {
             .affiliationIdentifierScheme(CREATOR_1_AFFIL_TYPE_DTO)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_6_CREATOR_1_MODIFY_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_1_FIRSTNAME)
             .lastname(CREATOR_1_LASTNAME)
             .creatorName(CREATOR_1_NAME)
@@ -6964,7 +7006,7 @@ public abstract class BaseTest {
             .status(IDENTIFIER_6_STATUS_TYPE_DTO)
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_6_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_6_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_6_DATABASE_ID)
             .publicationYear(IDENTIFIER_6_PUBLICATION_YEAR)
             .publisher(IDENTIFIER_6_PUBLISHER)
@@ -7059,7 +7101,7 @@ public abstract class BaseTest {
             .status(IDENTIFIER_7_STATUS_TYPE_DTO)
             .build();
 
-    public final static CreatorSaveDto IDENTIFIER_7_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder()
+    public final static SaveIdentifierCreatorDto IDENTIFIER_7_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder()
             .firstname(CREATOR_1_FIRSTNAME)
             .lastname(CREATOR_1_LASTNAME)
             .creatorName(CREATOR_1_NAME)
@@ -7069,7 +7111,7 @@ public abstract class BaseTest {
             .affiliationIdentifier(CREATOR_1_AFFIL_ROR)
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_7_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_7_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_7_DATABASE_ID)
             .publicationYear(IDENTIFIER_7_PUBLICATION_YEAR)
             .publisher(IDENTIFIER_7_PUBLISHER)
@@ -7112,7 +7154,7 @@ public abstract class BaseTest {
     public final static IdentifierStatusTypeDto IDENTIFIER_2_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED;
     public final static UUID IDENTIFIER_2_CREATED_BY = USER_1_ID;
 
-    public final static IdentifierCreateDto IDENTIFIER_2_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_2_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_2_DATABASE_ID)
             .queryId(IDENTIFIER_2_QUERY_ID)
             .type(IDENTIFIER_2_TYPE_DTO)
@@ -7284,7 +7326,7 @@ public abstract class BaseTest {
             .status(IDENTIFIER_3_STATUS_TYPE_DTO)
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_3_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_3_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_3_DATABASE_ID)
             .viewId(IDENTIFIER_3_VIEW_ID)
             .type(IDENTIFIER_3_TYPE_DTO)
@@ -7383,7 +7425,7 @@ public abstract class BaseTest {
             .status(IDENTIFIER_4_STATUS_TYPE_DTO)
             .build();
 
-    public final static IdentifierCreateDto IDENTIFIER_4_CREATE_DTO = IdentifierCreateDto.builder()
+    public final static CreateIdentifierDto IDENTIFIER_4_CREATE_DTO = CreateIdentifierDto.builder()
             .databaseId(IDENTIFIER_4_DATABASE_ID)
             .publicationYear(IDENTIFIER_4_PUBLICATION_YEAR)
             .publisher(IDENTIFIER_4_PUBLISHER)
@@ -7502,7 +7544,7 @@ public abstract class BaseTest {
             .lastModified(DATABASE_1_LAST_MODIFIED)
             .ownedBy(DATABASE_1_CREATED_BY)
             .owner(USER_1)
-            .ownedBy(DATABASE_1_OWNER)
+            .ownedBy(USER_1_ID)
             .owner(USER_1)
             .image(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
             .contactPerson(USER_1_ID)
@@ -7517,16 +7559,18 @@ public abstract class BaseTest {
     public final static DatabaseDto DATABASE_1_DTO = DatabaseDto.builder()
             .id(DATABASE_1_ID)
             .isPublic(DATABASE_1_PUBLIC)
+            .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC)
             .name(DATABASE_1_NAME)
-            .container(CONTAINER_1_BRIEF_DTO)
+            .container(CONTAINER_1_DTO)
             .internalName(DATABASE_1_INTERNALNAME)
             .exchangeName(DATABASE_1_EXCHANGE)
-            .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO, IDENTIFIER_3_BRIEF_DTO, IDENTIFIER_4_BRIEF_DTO)))
-            .tables(new LinkedList<>(List.of(TABLE_1_BRIEF_DTO, TABLE_2_BRIEF_DTO, TABLE_3_BRIEF_DTO, TABLE_4_BRIEF_DTO)))
-            .views(new LinkedList<>(List.of(VIEW_1_BRIEF_DTO, VIEW_2_BRIEF_DTO, VIEW_3_BRIEF_DTO)))
+            .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO)))
+            .tables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO)))
+            .views(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)))
+            .owner(USER_1_BRIEF_DTO)
             .build();
 
-    public final static PrivilegedDatabaseDto DATABASE_1_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder()
+    public final static DatabaseDto DATABASE_1_PRIVILEGED_DTO = DatabaseDto.builder()
             .id(DATABASE_1_ID)
             .isPublic(DATABASE_1_PUBLIC)
             .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC)
@@ -7534,6 +7578,7 @@ public abstract class BaseTest {
             .container(CONTAINER_1_PRIVILEGED_DTO)
             .internalName(DATABASE_1_INTERNALNAME)
             .exchangeName(DATABASE_1_EXCHANGE)
+            .accesses(new LinkedList<>(List.of())) /* DATABASE_1_USER_1_READ_ACCESS_DTO */
             .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO)))
             .tables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO)))
             .views(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)))
@@ -7541,6 +7586,15 @@ public abstract class BaseTest {
             .lastRetrieved(Instant.now())
             .build();
 
+    public final static DatabaseBriefDto DATABASE_1_BRIEF_DTO = DatabaseBriefDto.builder()
+            .id(DATABASE_1_ID)
+            .isPublic(DATABASE_1_PUBLIC)
+            .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC)
+            .name(DATABASE_1_NAME)
+            .internalName(DATABASE_1_INTERNALNAME)
+            .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO, IDENTIFIER_3_BRIEF_DTO, IDENTIFIER_4_BRIEF_DTO)))
+            .build();
+
     public final static DatabaseAccess DATABASE_1_USER_1_READ_ACCESS = DatabaseAccess.builder()
             .type(AccessType.READ)
             .hdbid(DATABASE_1_ID)
@@ -7672,12 +7726,12 @@ public abstract class BaseTest {
             .identifiers(new LinkedList<>())
             .build();
 
-    public final static PrivilegedDatabaseDto DATABASE_2_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder()
+    public final static DatabaseDto DATABASE_2_DTO = DatabaseDto.builder()
             .id(DATABASE_2_ID)
             .isPublic(DATABASE_2_PUBLIC)
             .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC)
             .name(DATABASE_2_NAME)
-            .container(CONTAINER_1_PRIVILEGED_DTO)
+            .container(CONTAINER_1_DTO)
             .internalName(DATABASE_2_INTERNALNAME)
             .exchangeName(DATABASE_2_EXCHANGE)
             .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO)))
@@ -7687,18 +7741,29 @@ public abstract class BaseTest {
             .lastRetrieved(Instant.now())
             .build();
 
-    public final static DatabaseDto DATABASE_2_DTO = DatabaseDto.builder()
+    public final static DatabaseDto DATABASE_2_PRIVILEGED_DTO = DatabaseDto.builder()
             .id(DATABASE_2_ID)
             .isPublic(DATABASE_2_PUBLIC)
+            .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC)
             .name(DATABASE_2_NAME)
-            .container(CONTAINER_1_BRIEF_DTO)
+            .container(CONTAINER_1_PRIVILEGED_DTO)
             .internalName(DATABASE_2_INTERNALNAME)
             .exchangeName(DATABASE_2_EXCHANGE)
-            .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_BRIEF_DTO)))
-            .tables(new LinkedList<>(List.of(TABLE_5_BRIEF_DTO, TABLE_6_BRIEF_DTO, TABLE_7_BRIEF_DTO)))
-            .views(new LinkedList<>(List.of(VIEW_4_BRIEF_DTO)))
-            .identifiers(new LinkedList<>())
+            .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO)))
+            .tables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO)))
+            .views(new LinkedList<>(List.of(VIEW_4_DTO)))
             .owner(USER_2_BRIEF_DTO)
+            .lastRetrieved(Instant.now())
+            .build();
+
+    public final static DatabaseBriefDto DATABASE_2_BRIEF_DTO = DatabaseBriefDto.builder()
+            .id(DATABASE_2_ID)
+            .isPublic(DATABASE_2_PUBLIC)
+            .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC)
+            .name(DATABASE_2_NAME)
+            .internalName(DATABASE_2_INTERNALNAME)
+            .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_BRIEF_DTO)))
+            .ownerId(USER_2_ID)
             .build();
 
     public final static DatabaseAccess DATABASE_2_USER_1_READ_ACCESS = DatabaseAccess.builder()
@@ -7855,6 +7920,13 @@ public abstract class BaseTest {
             .user(USER_1)
             .build();
 
+    public final static DatabaseAccessDto DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder()
+            .type(AccessTypeDto.WRITE_ALL)
+            .hdbid(DATABASE_3_ID)
+            .huserid(USER_1_ID)
+            .user(USER_1_BRIEF_DTO)
+            .build();
+
     public final static DatabaseAccess DATABASE_3_USER_2_READ_ACCESS = DatabaseAccess.builder()
             .type(AccessType.READ)
             .hdbid(DATABASE_3_ID)
@@ -7924,21 +7996,6 @@ public abstract class BaseTest {
             .user(USER_3_BRIEF_DTO)
             .build();
 
-    public final static PrivilegedDatabaseDto DATABASE_3_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder()
-            .id(DATABASE_3_ID)
-            .isPublic(DATABASE_3_PUBLIC)
-            .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC)
-            .name(DATABASE_3_NAME)
-            .container(CONTAINER_1_PRIVILEGED_DTO)
-            .internalName(DATABASE_3_INTERNALNAME)
-            .exchangeName(DATABASE_3_EXCHANGE)
-            .identifiers(new LinkedList<>(List.of(IDENTIFIER_6_DTO)))
-            .tables(new LinkedList<>(List.of(TABLE_8_DTO)))
-            .views(new LinkedList<>(List.of(VIEW_5_DTO)))
-            .owner(USER_3_BRIEF_DTO)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static Identifier IDENTIFIER_7 = Identifier.builder()
             .id(IDENTIFIER_7_ID)
             .descriptions(new LinkedList<>())
@@ -7985,21 +8042,6 @@ public abstract class BaseTest {
             .identifiers(new LinkedList<>())
             .build();
 
-    public final static PrivilegedDatabaseDto DATABASE_4_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder()
-            .id(DATABASE_4_ID)
-            .isPublic(DATABASE_4_PUBLIC)
-            .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC)
-            .name(DATABASE_4_NAME)
-            .container(CONTAINER_1_PRIVILEGED_DTO)
-            .internalName(DATABASE_4_INTERNALNAME)
-            .exchangeName(DATABASE_4_EXCHANGE)
-            .identifiers(new LinkedList<>(List.of(IDENTIFIER_7_DTO)))
-            .tables(new LinkedList<>(List.of(TABLE_9_DTO)))
-            .views(new LinkedList<>(List.of()))
-            .owner(USER_3_BRIEF_DTO)
-            .lastRetrieved(Instant.now())
-            .build();
-
     public final static DatabaseAccess DATABASE_4_USER_1_READ_ACCESS = DatabaseAccess.builder()
             .type(AccessType.READ)
             .hdbid(DATABASE_4_ID)
@@ -8081,9 +8123,9 @@ public abstract class BaseTest {
             .foreignKeys(new LinkedList<>())
             .uniques(new LinkedList<>())
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
+                    .id(1L)
                     .table(TABLE_1_BRIEF_DTO)
                     .column(TABLE_1_COLUMNS_BRIEF_0_DTO)
-                    .id(1L)
                     .build())))
             .build();
 
@@ -8136,7 +8178,7 @@ public abstract class BaseTest {
                     .id(1L)
                     .table(TABLE_2_BRIEF_DTO)
                     .name("uk_1")
-                    .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_DTO.get(1))))
+                    .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_BRIEF_DTO.get(1))))
                     .build())))
             .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder()
                     .table(TABLE_2_BRIEF_DTO)
diff --git a/dbrepo-search-service/Pipfile b/dbrepo-search-service/Pipfile
index ec74a381be4f01297cf01d2f638182ba2a8a1d9d..3ae299480180796fb640802d582aaf2745f876ca 100644
--- a/dbrepo-search-service/Pipfile
+++ b/dbrepo-search-service/Pipfile
@@ -18,7 +18,7 @@ jwt = "~=1.3"
 testcontainers-opensearch = "*"
 pytest = "*"
 rdflib = "*"
-dbrepo = {path = "./lib/dbrepo-1.6.1.tar.gz"}
+dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"}
 gunicorn = "*"
 
 [dev-packages]
diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock
index c0508dd3daf66ff03c848411ae47f1698da81014..6c62e03b928bcd62b443395c39dcdef902fe488d 100644
--- a/dbrepo-search-service/Pipfile.lock
+++ b/dbrepo-search-service/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "a0682b0583cfc91d643a307a7dce7a524e7f7c29dbf2c9c5e9a6f16eb5f5ee91"
+            "sha256": "2ff9fc673f1fb1e5dc272aa711f4e730088fa0188b44449db042abf99b6c4db7"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -124,11 +124,11 @@
         },
         "attrs": {
             "hashes": [
-                "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff",
-                "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"
+                "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e",
+                "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==24.3.0"
+            "version": "==25.1.0"
         },
         "blinker": {
             "hashes": [
@@ -360,9 +360,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:a08b6eb49c108466b231c1b2cae5be501043fe4208a782899ce103105e22e3c6"
+                "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d"
             ],
-            "path": "./lib/dbrepo-1.6.1.tar.gz"
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
         },
         "docker": {
             "hashes": [
@@ -739,11 +739,11 @@
         },
         "mistune": {
             "hashes": [
-                "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1",
-                "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667"
+                "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a",
+                "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==3.1.0"
+            "version": "==3.1.1"
         },
         "multidict": {
             "hashes": [
@@ -845,64 +845,64 @@
         },
         "numpy": {
             "hashes": [
-                "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2",
-                "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5",
-                "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60",
-                "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71",
-                "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631",
-                "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8",
-                "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2",
-                "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16",
-                "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa",
-                "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591",
-                "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964",
-                "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821",
-                "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484",
-                "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957",
-                "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800",
-                "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918",
-                "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95",
-                "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0",
-                "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e",
-                "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d",
-                "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73",
-                "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59",
-                "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51",
-                "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355",
-                "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348",
-                "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e",
-                "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440",
-                "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675",
-                "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84",
-                "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046",
-                "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab",
-                "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712",
-                "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308",
-                "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315",
-                "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3",
-                "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008",
-                "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5",
-                "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2",
-                "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e",
-                "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7",
-                "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf",
-                "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab",
-                "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd",
-                "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf",
-                "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8",
-                "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb",
-                "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268",
-                "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d",
-                "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780",
-                "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716",
-                "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e",
-                "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528",
-                "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af",
-                "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7",
-                "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51"
+                "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f",
+                "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0",
+                "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd",
+                "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2",
+                "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4",
+                "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648",
+                "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be",
+                "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb",
+                "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160",
+                "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd",
+                "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a",
+                "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84",
+                "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e",
+                "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748",
+                "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825",
+                "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60",
+                "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957",
+                "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715",
+                "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317",
+                "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e",
+                "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283",
+                "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278",
+                "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9",
+                "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de",
+                "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369",
+                "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb",
+                "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189",
+                "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014",
+                "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323",
+                "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e",
+                "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49",
+                "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50",
+                "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d",
+                "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37",
+                "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39",
+                "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576",
+                "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a",
+                "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba",
+                "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7",
+                "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826",
+                "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467",
+                "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495",
+                "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc",
+                "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391",
+                "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0",
+                "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97",
+                "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c",
+                "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac",
+                "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369",
+                "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8",
+                "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2",
+                "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff",
+                "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a",
+                "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df",
+                "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f"
             ],
             "markers": "python_version == '3.11'",
-            "version": "==2.2.1"
+            "version": "==2.2.2"
         },
         "opensearch-py": {
             "hashes": [
@@ -1099,11 +1099,11 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
-                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
+                "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584",
+                "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.10.5"
+            "version": "==2.10.6"
         },
         "pydantic-core": {
             "hashes": [
@@ -1321,20 +1321,20 @@
         },
         "rdflib": {
             "hashes": [
-                "sha256:4fc8f6d50b199dc38fbc5256370f038c1cedca6102ccbde4e37c0fd2b7f36e65",
-                "sha256:5a694a64f48a751079999c37dccf91a6210077d845d09adf7c3ce23a876265a7"
+                "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673",
+                "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee"
             ],
             "index": "pypi",
-            "markers": "python_version >= '3.9' and python_version < '4'",
-            "version": "==7.1.2"
+            "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'",
+            "version": "==7.1.3"
         },
         "referencing": {
             "hashes": [
-                "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794",
-                "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade"
+                "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa",
+                "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"
             ],
             "markers": "python_version >= '3.9'",
-            "version": "==0.36.1"
+            "version": "==0.36.2"
         },
         "requests": {
             "hashes": [
@@ -1574,11 +1574,11 @@
         },
         "tzdata": {
             "hashes": [
-                "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc",
-                "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"
+                "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694",
+                "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"
             ],
             "markers": "python_version >= '2'",
-            "version": "==2024.2"
+            "version": "==2025.1"
         },
         "urllib3": {
             "hashes": [
diff --git a/dbrepo-search-service/init/Pipfile b/dbrepo-search-service/init/Pipfile
index 77bab3e84c036d88689f0431bf63dc2f5fe4d099..b74ed7bc40da1da1c51c401b53a1da2676fb739e 100644
--- a/dbrepo-search-service/init/Pipfile
+++ b/dbrepo-search-service/init/Pipfile
@@ -9,7 +9,7 @@ opensearch-py = "~=2.2"
 python-dotenv = "~=1.0"
 testcontainers-opensearch = "*"
 pytest = "*"
-dbrepo = {path = "./lib/dbrepo-1.6.1.tar.gz"}
+dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"}
 rdflib = "*"
 
 [dev-packages]
diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock
index bf53ace7e7551b8e0961373d6ab23e49ff53f300..039873e7c5ffd4b2e5c6352027f7f501254ce5c6 100644
--- a/dbrepo-search-service/init/Pipfile.lock
+++ b/dbrepo-search-service/init/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "9edba52503b8604b267d52e41954beba012143b1e47f56aaae553cdcaf054e55"
+            "sha256": "dac534d1eb6a0942c0e296c8a58491847c65d3ca23315039a3725591c86f694f"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -124,11 +124,11 @@
         },
         "attrs": {
             "hashes": [
-                "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff",
-                "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"
+                "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e",
+                "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==24.3.0"
+            "version": "==25.1.0"
         },
         "blinker": {
             "hashes": [
@@ -254,10 +254,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:251f3c2088bbd289cee86d5394b1e62e29aa081f994dd0845d895e3330f6a106"
+                "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d"
             ],
-            "path": "./lib/dbrepo-1.6.1.tar.gz",
-            "version": "==1.6.1"
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
         },
         "docker": {
             "hashes": [
@@ -279,6 +278,7 @@
                 "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==2.3.3"
         },
         "frozenlist": {
@@ -578,64 +578,64 @@
         },
         "numpy": {
             "hashes": [
-                "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2",
-                "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5",
-                "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60",
-                "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71",
-                "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631",
-                "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8",
-                "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2",
-                "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16",
-                "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa",
-                "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591",
-                "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964",
-                "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821",
-                "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484",
-                "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957",
-                "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800",
-                "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918",
-                "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95",
-                "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0",
-                "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e",
-                "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d",
-                "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73",
-                "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59",
-                "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51",
-                "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355",
-                "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348",
-                "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e",
-                "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440",
-                "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675",
-                "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84",
-                "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046",
-                "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab",
-                "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712",
-                "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308",
-                "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315",
-                "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3",
-                "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008",
-                "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5",
-                "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2",
-                "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e",
-                "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7",
-                "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf",
-                "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab",
-                "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd",
-                "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf",
-                "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8",
-                "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb",
-                "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268",
-                "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d",
-                "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780",
-                "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716",
-                "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e",
-                "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528",
-                "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af",
-                "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7",
-                "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51"
+                "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f",
+                "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0",
+                "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd",
+                "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2",
+                "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4",
+                "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648",
+                "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be",
+                "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb",
+                "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160",
+                "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd",
+                "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a",
+                "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84",
+                "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e",
+                "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748",
+                "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825",
+                "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60",
+                "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957",
+                "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715",
+                "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317",
+                "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e",
+                "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283",
+                "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278",
+                "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9",
+                "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de",
+                "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369",
+                "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb",
+                "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189",
+                "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014",
+                "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323",
+                "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e",
+                "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49",
+                "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50",
+                "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d",
+                "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37",
+                "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39",
+                "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576",
+                "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a",
+                "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba",
+                "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7",
+                "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826",
+                "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467",
+                "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495",
+                "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc",
+                "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391",
+                "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0",
+                "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97",
+                "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c",
+                "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac",
+                "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369",
+                "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8",
+                "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2",
+                "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff",
+                "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a",
+                "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df",
+                "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f"
             ],
             "markers": "python_version == '3.11'",
-            "version": "==2.2.1"
+            "version": "==2.2.2"
         },
         "opensearch-py": {
             "hashes": [
@@ -643,6 +643,7 @@
                 "sha256:6598df0bc7a003294edd0ba88a331e0793acbb8c910c43edf398791e3b2eccda"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8' and python_version < '4'",
             "version": "==2.8.0"
         },
         "packaging": {
@@ -807,11 +808,11 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
-                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
+                "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584",
+                "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.10.5"
+            "version": "==2.10.6"
         },
         "pydantic-core": {
             "hashes": [
@@ -933,6 +934,7 @@
                 "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==8.3.4"
         },
         "python-dateutil": {
@@ -949,6 +951,7 @@
                 "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==1.0.1"
         },
         "pytz": {
@@ -960,11 +963,12 @@
         },
         "rdflib": {
             "hashes": [
-                "sha256:4fc8f6d50b199dc38fbc5256370f038c1cedca6102ccbde4e37c0fd2b7f36e65",
-                "sha256:5a694a64f48a751079999c37dccf91a6210077d845d09adf7c3ce23a876265a7"
+                "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673",
+                "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee"
             ],
             "index": "pypi",
-            "version": "==7.1.2"
+            "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'",
+            "version": "==7.1.3"
         },
         "requests": {
             "hashes": [
@@ -994,6 +998,7 @@
                 "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.7'",
             "version": "==0.0.1rc1"
         },
         "tinydb": {
@@ -1022,11 +1027,11 @@
         },
         "tzdata": {
             "hashes": [
-                "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc",
-                "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"
+                "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694",
+                "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"
             ],
             "markers": "python_version >= '2'",
-            "version": "==2024.2"
+            "version": "==2025.1"
         },
         "urllib3": {
             "hashes": [
@@ -1285,6 +1290,7 @@
                 "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.9'",
             "version": "==7.6.10"
         },
         "iniconfig": {
@@ -1317,6 +1323,7 @@
                 "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"
             ],
             "index": "pypi",
+            "markers": "python_version >= '3.8'",
             "version": "==8.3.4"
         }
     }
diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.0.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.0.tar.gz
deleted file mode 100644
index 80c2ba74f662e7b02895122a37e301fde2157b82..0000000000000000000000000000000000000000
Binary files a/dbrepo-search-service/init/lib/dbrepo-1.6.0.tar.gz and /dev/null differ
diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz
deleted file mode 100644
index 7914db1bb84dddf85611cda3b766c0c0cdc094c7..0000000000000000000000000000000000000000
Binary files a/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz and /dev/null differ
diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1
Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl differ
diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253
Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.6.0.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.0.tar.gz
deleted file mode 100644
index 80c2ba74f662e7b02895122a37e301fde2157b82..0000000000000000000000000000000000000000
Binary files a/dbrepo-search-service/lib/dbrepo-1.6.0.tar.gz and /dev/null differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz
deleted file mode 100644
index 7914db1bb84dddf85611cda3b766c0c0cdc094c7..0000000000000000000000000000000000000000
Binary files a/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz and /dev/null differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1
Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253
Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py
index 9da77adfde53e155dddc36f364bea9d974964125..edbdff683dff0f66319d87fb064fdeab6931bca0 100644
--- a/dbrepo-search-service/test/test_opensearch_client.py
+++ b/dbrepo-search-service/test/test_opensearch_client.py
@@ -2,7 +2,7 @@ import unittest
 
 import opensearchpy
 from dbrepo.api.dto import Database, Table, Column, ColumnType, Constraints, PrimaryKey, \
-    TableMinimal, ColumnMinimal, ConceptBrief, UnitBrief, UserBrief, ContainerBrief, ImageBrief
+    ConceptBrief, UnitBrief, UserBrief, ContainerBrief, ImageBrief, TableBrief, ColumnBrief
 from opensearchpy import NotFoundError
 
 from app import app
@@ -57,10 +57,6 @@ class OpenSearchClientTest(unittest.TestCase):
 
     def test_update_database_succeeds(self):
         with app.app_context():
-            # mock
-            OpenSearchClient().update_database(database_id=req.id, data=req)
-
-            # test
             req.tables = [Table(id=1,
                                 name="Test Table",
                                 internal_name="test_table",
@@ -71,10 +67,20 @@ class OpenSearchClientTest(unittest.TestCase):
                                 database_id=req.id,
                                 constraints=Constraints(uniques=[], foreign_keys=[], checks=[],
                                                         primary_key=[PrimaryKey(id=1,
-                                                                                table=TableMinimal(id=1,
-                                                                                                   database_id=req.id),
-                                                                                column=ColumnMinimal(id=1, table_id=1,
-                                                                                                     database_id=req.id))]),
+                                                                                table=TableBrief(id=1,
+                                                                                                 database_id=req.id,
+                                                                                                 name="Test Table",
+                                                                                                 internal_name="test_table",
+                                                                                                 is_public=True,
+                                                                                                 is_schema_public=True,
+                                                                                                 is_versioned=True,
+                                                                                                 owned_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502"),
+                                                                                column=ColumnBrief(id=1,
+                                                                                                   name="ID",
+                                                                                                   database_id=req.id,
+                                                                                                   table_id=1,
+                                                                                                   internal_name="id",
+                                                                                                   type=ColumnType.BIGINT))]),
                                 is_versioned=True,
                                 owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"),
                                 columns=[Column(id=1,
@@ -85,6 +91,10 @@ class OpenSearchClientTest(unittest.TestCase):
                                                 internal_name="id",
                                                 type=ColumnType.BIGINT,
                                                 is_null_allowed=False)])]
+            # mock
+            OpenSearchClient().update_database(database_id=req.id, data=req)
+
+            # test
             database = OpenSearchClient().update_database(database_id=req.id, data=req)
             self.assertEqual(1, database.id)
             self.assertEqual("Test", database.name)
diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb
index 45a8c51c621dab127458d68a4493b23d2df9f88d..7ee1d3897245ee94212d8bfb6a6b97556b64f1d2 100755
Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ
diff --git a/dbrepo-ui/components/JumboBox.vue b/dbrepo-ui/components/JumboBox.vue
index d2b804f819f22782ba4895c601c8b2ea118ce4e3..5a26ec6139bff1a1b816c2acce1dc3fb08cd7207 100644
--- a/dbrepo-ui/components/JumboBox.vue
+++ b/dbrepo-ui/components/JumboBox.vue
@@ -21,6 +21,7 @@
     </v-row>
   </div>
 </template>
+
 <script>
 export default {
   props: {
diff --git a/dbrepo-ui/components/Loading.vue b/dbrepo-ui/components/Loading.vue
index 743701ab6724dba40d6baa0cb0cfafcb26061556..84094bfef8773aa306d977e6f0f7cbb4cca1dde9 100644
--- a/dbrepo-ui/components/Loading.vue
+++ b/dbrepo-ui/components/Loading.vue
@@ -7,6 +7,7 @@
       indeterminate />
   </v-list-item-title>
 </template>
+
 <script>
 export default {
   props: {
diff --git a/dbrepo-ui/components/OntologiesList.vue b/dbrepo-ui/components/OntologiesList.vue
deleted file mode 100644
index c7120cac4a1e58e4a1f22c651f77aebcaf002584..0000000000000000000000000000000000000000
--- a/dbrepo-ui/components/OntologiesList.vue
+++ /dev/null
@@ -1,73 +0,0 @@
-<template>
-  <div>
-    <v-card
-      v-for="(ontology, idx) in ontologies"
-      :key="idx"
-      :to="`/semantic/ontology/${ontology.id}`"
-      variant="flat"
-      rounded="0">
-      <v-divider
-        class="mx-4" />
-      <v-card-title>
-        {{ ontology.prefix }}
-      </v-card-title>
-      <v-card-subtitle>
-        {{ ontology.uri }}
-      </v-card-subtitle>
-      <v-card-text>
-        <div
-          class="db-tags">
-          <v-chip
-            v-if="ontology.sparql"
-            size="small"
-            color="success"
-            text="SPARQL"
-            variant="outlined" />
-          <v-chip
-            v-if="ontology.rdf"
-            size="small"
-            text="RDF"
-            variant="outlined" />
-        </div>
-      </v-card-text>
-    </v-card>
-  </div>
-</template>
-
-<script>
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  data () {
-    return {
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    }
-  },
-  mounted () {
-  },
-  methods: {
-  }
-}
-</script>
-
-<style>
-.db-tags .v-chip:not(:first-child) {
-  margin-left: 4px;
-}
-</style>
diff --git a/dbrepo-ui/components/ResourceStatus.vue b/dbrepo-ui/components/ResourceStatus.vue
index 5167d899ea6e73c150db478f8fc3b063a3ba1e12..6db6d25385359ee82086b510537107fb3d0d0f31 100644
--- a/dbrepo-ui/components/ResourceStatus.vue
+++ b/dbrepo-ui/components/ResourceStatus.vue
@@ -5,7 +5,7 @@
       v-if="!inline"
       :size="size"
       :color="color"
-      variant="outlined">
+      :variant="chipVariant">
       {{ status }}
     </v-chip>
     <span
@@ -14,6 +14,7 @@
     </span>
   </span>
 </template>
+
 <script>
 export default {
   props: {
@@ -38,6 +39,9 @@ export default {
       if (!this.resource) {
         return null
       }
+      if (this.hasIdentifier) {
+        return 'pid'
+      }
       if (!this.resource.is_public && !this.resource.is_schema_public) {
         return 'draft'
       } else if(!this.resource.is_public && this.resource.is_schema_public) {
@@ -53,7 +57,19 @@ export default {
       }
       return this.$t(`pages.database.status.${this.mode}`)
     },
+    hasIdentifier () {
+      return this.resource.identifiers?.length > 0
+    },
+    chipVariant () {
+      if (this.hasIdentifier) {
+        return 'tonal'
+      }
+      return 'outlined'
+    },
     color () {
+      if (this.hasIdentifier) {
+        return 'info'
+      }
       switch (this.mode) {
         case 'schema':
         case 'data':
diff --git a/dbrepo-ui/components/TimeDrift.vue b/dbrepo-ui/components/TimeDrift.vue
deleted file mode 100644
index 2f2555f9f84f107dff1ffd12ad75533d388c1f62..0000000000000000000000000000000000000000
--- a/dbrepo-ui/components/TimeDrift.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-<template>
-  <v-alert
-    v-cloak
-    v-if="timestamp && offSeconds > 3"
-    class="banner"
-    border="start"
-    type="warning">
-    {{ $t('error.data.drift') + ' ' + offSeconds + 's' }}
-  </v-alert>
-</template>
-
-<script>
-import { formatTimestamp, timestampsToHumanDifference } from '@/utils'
-
-export default {
-  data () {
-    return {
-      timestamp: null
-    }
-  },
-  computed: {
-    drift () {
-      return this.timestampsToHumanDifference(Date.now(), this.timestamp)
-    },
-    offSeconds () {
-      if (!this.timestamp) {
-        return null
-      }
-      return (Date.now().valueOf() - Date.parse(this.timestamp)) / 1000
-    }
-  },
-  mounted() {
-    const databaseService = useDatabaseService()
-    databaseService.getServerTime()
-      .then((timestamp) => {
-        this.timestamp = timestamp
-      })
-  },
-  methods: {
-    formatTimestamp,
-    timestampsToHumanDifference
-  }
-}
-</script>
diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue
index 4177ae592cbae97090d0b109c576137b0ee74cbc..3e661cd754b98ca94519bda6a7f4ad49d4ff0378 100644
--- a/dbrepo-ui/components/database/DatabaseToolbar.vue
+++ b/dbrepo-ui/components/database/DatabaseToolbar.vue
@@ -83,7 +83,6 @@
 
 <script>
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import ResourceStatus from '@/components/ResourceStatus.vue'
 
 export default {
@@ -94,8 +93,7 @@ export default {
     return {
       tab: null,
       error: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -103,13 +101,13 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    user () {
-      return this.userStore.getUser
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     isContrastTheme () {
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast')
@@ -141,12 +139,6 @@ export default {
       }
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
-    canImportCsv () {
-      if (!this.user || !this.hasWriteAccess) {
-        return false
-      }
-      return this.roles.includes('insert-table-data')
-    },
     canCreateSubset () {
       if (!this.database) {
         return false
@@ -157,22 +149,22 @@ export default {
       return this.hasReadAccess
     },
     canCreateView () {
-      if (!this.user || !this.isOwner) {
+      if (!this.cacheUser || !this.isOwner || !this.roles) {
         return false
       }
       return this.roles.includes('create-database-view')
     },
     canCreateTable () {
-      if (!this.user || !this.hasWriteAccess) {
+      if (!this.cacheUser || !this.hasWriteAccess || !this.roles) {
         return false
       }
       return this.roles.includes('create-table')
     },
     isOwner () {
-      if (!this.database || !this.user) {
+      if (!this.database || !this.cacheUser) {
         return false
       }
-      return this.database.owner.username === this.user.username
+      return this.database.owner.id === this.cacheUser.uid
     },
     buttonVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/components/dialogs/EditTuple.vue b/dbrepo-ui/components/dialogs/EditTuple.vue
index 3290d230d1bf216bd2f212c4fbe9c683901e4b96..75e824ed4316bad96843a57694b245d4caf01682 100644
--- a/dbrepo-ui/components/dialogs/EditTuple.vue
+++ b/dbrepo-ui/components/dialogs/EditTuple.vue
@@ -3,7 +3,7 @@
     <v-form
       ref="form"
       v-model="valid"
-      @submit.prevent="submit">
+      @submit.prevent="validate">
       <v-card
         :title="title"
         :subtitle="this.$t('toolbars.table.data.subtitle')"
@@ -17,12 +17,10 @@
               <v-text-field
                 v-if="isNumber(column)"
                 v-model.number="tuple[column.internal_name]"
-                :disabled="!edit"
                 persistent-hint
                 :variant="inputVariant"
                 :label="column.internal_name"
                 :hint="hint(column)"
-                :rules="rules(column)"
                 :required="required(column)"
                 type="number">
                 <template
@@ -48,11 +46,9 @@
               <v-text-field
                 v-if="isTextField(column)"
                 v-model="tuple[column.internal_name]"
-                :disabled="disabled(column)"
                 :clearable="!required(column)"
                 :counter="maxLength(column) !== null"
                 :maxlength="maxLength(column)"
-                :rules="rules(column)"
                 :required="required(column)"
                 persistent-hint
                 :variant="inputVariant"
@@ -82,10 +78,8 @@
               <v-text-field
                 v-if="isFloatingPoint(column)"
                 v-model="tuple[column.internal_name]"
-                :disabled="disabled(column)"
                 step=".1"
                 :clearable="!required(column)"
-                :rules="rules(column)"
                 :required="required(column)"
                 persistent-hint
                 :variant="inputVariant"
@@ -115,10 +109,8 @@
               <v-textarea
                 v-if="isTextArea(column)"
                 v-model="tuple[column.internal_name]"
-                :disabled="disabled(column)"
                 rows="3"
                 :clearable="!required(column)"
-                :rules="rules(column)"
                 :required="required(column)"
                 persistent-hint
                 :variant="inputVariant"
@@ -155,7 +147,6 @@
                 :variant="inputVariant"
                 :label="column.internal_name"
                 :hint="hint(column)"
-                :rules="rules(column)"
                 :required="required(column)"
                 :clearable="!required(column)"
                 :items="isSet(column) ? column.sets : column.enums">
@@ -186,7 +177,6 @@
                 :variant="inputVariant"
                 :label="column.internal_name"
                 :hint="hint(column)"
-                :rules="rules(column)"
                 :required="required(column)"
                 :items="bools"
                 :clearable="!required(column)">
@@ -322,10 +312,10 @@ export default {
       cacheStore: useCacheStore()
     }
   },
-  mounted() {
+  mounted () {
     this.fetchContainer()
-    this.$refs.form.validate()
     this.oldTuple = Object.assign({}, this.tuple)
+    this.validate()
   },
   computed: {
     database () {
@@ -358,8 +348,17 @@ export default {
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal
     }
   },
+  watch: {
+    tuple: {
+      handler () {
+        this.validate()
+      },
+      deep: true
+    }
+  },
   methods: {
-    submit () {
+    validate () {
+      console.debug('validate form')
       this.$refs.form.validate()
     },
     cancel () {
@@ -425,18 +424,6 @@ export default {
     isTimeField (column) {
       return ['date', 'datetime', 'timestamp', 'time', 'year'].includes(column.type)
     },
-    rules (column) {
-      if (column.is_null_allowed) {
-        return []
-      }
-      const rules = []
-      rules.push(v => v !== null || this.$t('validation.required'))
-      if (column.type === 'decimal' || column.type === 'double') {
-        rules.push(v => !(!v || v.split('.')[0].length > column.size) || `${this.$t('pages.table.subpages.data.float.max')} ${column.size} ${this.$t('pages.table.subpages.data.float.before')}`)
-        rules.push(v => !(!v || (column.d && v.split('.')[1].length > column.d)) || `${this.$t('pages.table.subpages.data.float.max')} ${column.d} ${this.$t('pages.table.subpages.data.float.after')}`)
-      }
-      return rules
-    },
     maxLength (column) {
       if (!this.isTextField(column) || column.size === null) {
         return null
@@ -446,9 +433,6 @@ export default {
     required (column) {
       return column.is_null_allowed === false
     },
-    disabled (column) {
-      return (this.edit && column.is_primary_key) || !this.edit
-    },
     updateTuple () {
       const constraints = {}
       this.primaryKeyColumns
diff --git a/dbrepo-ui/components/identifier/Banner.vue b/dbrepo-ui/components/identifier/Banner.vue
index 1450347c412727830e07f4fc1e11b857ab22c346..63c2a7153a03d4dd6742920e2e32d0813bbd9036 100644
--- a/dbrepo-ui/components/identifier/Banner.vue
+++ b/dbrepo-ui/components/identifier/Banner.vue
@@ -3,6 +3,7 @@
     {{ prefix }}: <a :href="href">{{ displayName }}</a>
   </div>
 </template>
+
 <script>
 export default {
   props: {
@@ -23,7 +24,7 @@ export default {
       return identifierService.identifierToDisplayName(this.identifier)
     },
     href () {
-      if (!this.identifier || (this.identifier.status && this.identifier.status !== 'published')) {
+      if (!this.identifier) {
         return null
       }
       const identifierService = useIdentifierService()
diff --git a/dbrepo-ui/components/identifier/Citation.vue b/dbrepo-ui/components/identifier/Citation.vue
index 5722351f0ab1d3697783f3f0f82c54c5452981d4..9ee434c943da8c011e0bfece1c88c06b525845a9 100644
--- a/dbrepo-ui/components/identifier/Citation.vue
+++ b/dbrepo-ui/components/identifier/Citation.vue
@@ -4,7 +4,7 @@
     <v-col
       v-if="!loading"
       md="10">
-      <pre>{{ citation }}</pre>
+      {{ citation }}
     </v-col>
     <v-col
       v-if="!$vuetify.display.mdAndDown"
diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue
index 3dba450e634c6db374ccd28bd327ff2823756f3e..f37c5c6d7d9893562d94393fe6aa19ab3b448d79 100644
--- a/dbrepo-ui/components/identifier/Persist.vue
+++ b/dbrepo-ui/components/identifier/Persist.vue
@@ -12,6 +12,7 @@
       <v-spacer />
       <v-btn
         v-if="canSave"
+        class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null"
         color="secondary"
         variant="flat"
@@ -22,7 +23,7 @@
         @click="createOrSave"/>
       <v-btn
         v-if="canRemove"
-        class="ml-2"
+        class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-delete' : null"
         color="error"
         variant="flat"
@@ -32,7 +33,7 @@
         @click="remove" />
       <v-btn
         v-if="canPublish"
-        class="ml-2"
+        class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null"
         color="primary"
         variant="flat"
@@ -138,14 +139,6 @@
                       :color="canShiftUp(creator, i) ? 'tertiary' : ''"
                       :variant="buttonVariant"
                       @click="shiftDown(i)" />
-                    <v-btn
-                      v-if="canInsertSelf"
-                      class="mr-2"
-                      size="small"
-                      color="secondary"
-                      variant="flat"
-                      :text="$t('pages.identifier.subpages.create.creators.insert.text')"
-                      @click="insertSelf(creator)" />
                     <v-btn
                       v-if="i > 0"
                       size="small"
@@ -830,7 +823,6 @@
 <script>
 import { formatYearUTC, formatMonthUTC, formatDayUTC, languages } from '@/utils'
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import { MerkleJson } from 'merkle-json'
 
 export default {
@@ -962,16 +954,15 @@ export default {
         { value: 'IsObsoletedBy' },
         { value: 'Obsoletes' }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     isSubset () {
       return this.type === 'subset'
@@ -1045,23 +1036,14 @@ export default {
           }
       }
     },
-    isUpdate () {
-      return 'id' in this.identifier && this.identifier.id
-    },
-    canInsertSelf () {
-      if (!this.user) {
-        return false
-      }
-      return this.user.given_name || this.user.family_name || this.user.attributes.affiliation || this.user.attributes.orcid
-    },
     isCreator () {
-      if (!this.user || !this.identifier) {
+      if (!this.cacheUser || !this.identifier) {
         return false
       }
-      if (!this.identifier.creator) {
+      if (!this.identifier.owner) {
         return true
       }
-      return this.identifier.creator.id === this.user.id
+      return this.identifier.owner.id === this.cacheUser.uid
     },
     formValid () {
       /* somehow Vue3/Vuetify3 validation form is broken for arrays */
@@ -1123,10 +1105,10 @@ export default {
       return this.roles.includes('create-identifier') && !this.isPublished
     },
     canRemove () {
-      if (!this.roles || !this.identifier || !this.identifier.creator || !this.user) {
+      if (!this.roles || !this.identifier || !this.identifier.owner || !this.cacheUser) {
         return false
       }
-      return this.roles.includes('delete-identifier') && this.identifier.creator.id === this.user.id && !this.isPublished
+      return this.roles.includes('delete-identifier') && this.identifier.owner.id === this.cacheUser.uid && !this.isPublished
     },
     canPublish () {
       if (!this.roles || !this.identifier || !this.roles.includes('publish-identifier') || this.isPublished || !this.identifier.id) {
@@ -1494,15 +1476,15 @@ export default {
       if (this.isPublished) {
         return false
       }
-      if (this.user.attributes.orcid) {
-        creator.name_identifier = this.user.attributes.orcid
+      if (this.cacheUser.attributes.orcid) {
+        creator.name_identifier = this.cacheUser.attributes.orcid
         this.retrieveCreator(creator)
         return
       }
-      creator.firstname = this.user.given_name
-      creator.lastname = this.user.family_name
+      creator.firstname = this.cacheUser.given_name
+      creator.lastname = this.cacheUser.family_name
       creator.creator_name = (creator.lastname ? creator.lastname + ', ' : '') + creator.firstname
-      creator.affiliation = this.user.attributes.affiliation
+      creator.affiliation = this.cacheUser.attributes.affiliation
     },
     canShiftUp (creator, idx) {
       if (this.isPublished) {
diff --git a/dbrepo-ui/components/identifier/Select.vue b/dbrepo-ui/components/identifier/Select.vue
index 4404a09635c6833e609f74c4f685988550dc97c8..e5572866140858970c5141d40591af3dda5c389a 100644
--- a/dbrepo-ui/components/identifier/Select.vue
+++ b/dbrepo-ui/components/identifier/Select.vue
@@ -8,7 +8,7 @@
       :color="color(identifier)"
       :variant="listVariant"
       :href="href(identifier)"
-      :title="formatTimestampUTCLabel(identifier.created)"
+      :title="title(identifier)"
       lines="two">
       <v-list-item-subtitle>
         <Banner
@@ -43,8 +43,6 @@
 
 <script>
 import Banner from '@/components/identifier/Banner.vue'
-import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -61,32 +59,31 @@ export default {
     identifier: {
       type: Object,
       default () {
-        return {}
+        return null
       }
     }
   },
   data () {
     return {
       idx: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     displayIdentifiers () {
-      if (!this.identifiers) {
-        return []
+      if (!this.identifiers || this.identifiers.length === 0) {
+        if (!this.identifier) {
+          return []
+        }
+        return [this.identifier]
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return this.identifiers.filter(i => i.status === 'published')
       }
-      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id)
+      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.cacheUser.uid)
     },
     listVariant () {
       const runtimeConfig = useRuntimeConfig()
@@ -105,8 +102,10 @@ export default {
     this.init()
   },
   methods: {
-    formatTimestampUTCLabel,
     href (identifier) {
+      if (!identifier) {
+        return null
+      }
       if (identifier.status === 'published') {
         return `/pid/${identifier.id}`
       }
@@ -121,6 +120,13 @@ export default {
           return `/database/${identifier.database_id}/view/${identifier.view_id}/persist/${identifier.id}`
       }
     },
+    title (identifier) {
+      if (!identifier) {
+        return null
+      }
+      const identifierService = useIdentifierService()
+      return identifierService.identifierPreferEnglishTitle(identifier)
+    },
     isActive (identifier) {
       if (!identifier) {
         return false
diff --git a/dbrepo-ui/components/identifier/Summary.vue b/dbrepo-ui/components/identifier/Summary.vue
index 655a7bb907c9f8a6b868e280097033b157cd893c..6ef120599b515fece88870ad832ed23a508e4ebe 100644
--- a/dbrepo-ui/components/identifier/Summary.vue
+++ b/dbrepo-ui/components/identifier/Summary.vue
@@ -170,10 +170,10 @@ export default {
   },
   computed: {
     access () {
-      return this.userStore.getAccess.value
+      return this.cacheStore.getAccess
     },
     database () {
-      return this.cacheStore.getDatabase.value
+      return this.cacheStore.getDatabase
     },
     pid () {
       return `/pid/${this.database.identifier.id}`
diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue
index b45881479cb5243861ab8137a99999def787e551..f670700f2f23aa2a08a6ecf8004fecfb899c6c00 100644
--- a/dbrepo-ui/components/subset/Builder.vue
+++ b/dbrepo-ui/components/subset/Builder.vue
@@ -31,14 +31,12 @@
           :text="$t('pages.subset.subpages.create.expert.text')" />
       </v-tabs>
     </v-toolbar>
-    <TimeDrift />
     <v-card
       rounded="0"
       variant="flat">
       <v-card-text>
         <v-form
           ref="form"
-          v-model="valid"
           @submit.prevent>
           <v-row
             v-if="isView"
@@ -74,7 +72,7 @@
                 required
                 clearable
                 :rules="[
-                  v => !!v || $t('validation.required')
+                  v => v !== null || $t('validation.required')
                 ]"
                 :label="$t('pages.database.resource.data.label')"
                 :hint="$t('pages.database.resource.data.hint')" />
@@ -89,7 +87,7 @@
                 required
                 clearable
                 :rules="[
-                  v => !!v || $t('validation.required')
+                  v => v !== null || $t('validation.required')
                 ]"
                 :label="$t('pages.database.resource.schema.label')"
                 :hint="$t('pages.database.resource.schema.hint', { resource: 'subset', schema: 'query' })" />
@@ -304,18 +302,15 @@
 </template>
 
 <script>
-import TimeDrift from '@/components/TimeDrift.vue'
 import Raw from '@/components/subset/Raw.vue'
 import Results from '@/components/subset/Results.vue'
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import { format } from 'sql-formatter'
 
 export default {
   components: {
     Raw,
     Results,
-    TimeDrift
   },
   props: {
     mode: {
@@ -359,8 +354,7 @@ export default {
       tabs: 0,
       loadingQuery: false,
       loadingColumns: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -388,9 +382,6 @@ export default {
       }
       return this.database.container.image.data_types
     },
-    user () {
-      return this.userStore.getUser
-    },
     viewNames () {
       if (!this.database) {
         return []
@@ -449,7 +440,7 @@ export default {
       if (this.isView) {
         return this.view.name !== null && this.view.is_public !== null && this.view.query !== null
       }
-      return this.sql !== null && !this.sql.includes(';')
+      return this.sql !== null && this.sql !== '' && !this.sql.includes(';')
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
@@ -473,7 +464,7 @@ export default {
       if (!this.table) {
         return
       }
-      this.fetchTableColumns(this.table.id)
+      this.fetchTableColumns(this.table?.id)
     }
   },
   mounted () {
@@ -550,13 +541,24 @@ export default {
       this.view.query = this.sql
       const viewService = useViewService()
       viewService.create(this.$route.params.database_id, this.view)
-        .then(async (view) => {
-          this.resultId = view.id
-          this.cacheStore.reloadDatabase()
-          const toast = useToastInstance()
-          toast.success(this.$t('success.view.create'))
-          await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`)
-          this.loadingQuery = false
+        .then((simpleView) => {
+          this.resultId = simpleView.id
+          viewService.findOne(this.$route.params.database_id, simpleView.id)
+            .then(async (view) => {
+              this.cacheStore.setView(view)
+              const toast = useToastInstance()
+              toast.success(this.$t('success.view.create'))
+              await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`)
+              this.loadingQuery = false
+            })
+            .catch(({code}) => {
+              this.loadingQuery = false
+              const toast = useToastInstance()
+              if (typeof code !== 'string') {
+                return
+              }
+              toast.error(this.$t(code))
+            })
         })
         .catch(({code}) => {
           this.loadingQuery = false
diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue
index e558186daf15c186dfdc085a844799815e3756a4..661c7d1a3d6e7502cf349a63cc695cf7d593f427 100644
--- a/dbrepo-ui/components/subset/Results.vue
+++ b/dbrepo-ui/components/subset/Results.vue
@@ -80,23 +80,6 @@ export default {
     }
   },
   methods: {
-    executeFirstTime (parent, sql, timestamp) {
-      this.loading++
-      const payload = {
-        statement: sql,
-        timestamp
-      }
-      const queryService = useQueryService()
-      queryService.execute(this.$route.params.database_id, payload, this.options.page - 1, this.options.itemsPerPage)
-        .then((result) => {
-          this.mapResults(result)
-          parent.resultId = result.id
-          this.id = result.id
-        })
-        .finally(() => {
-          this.loading--
-        })
-    },
     reExecute (id) {
       if (id === null) {
         return
@@ -110,9 +93,13 @@ export default {
             this.id = id
             this.loadingExecute = false
           })
-          .catch(({code}) => {
+          .catch(({code, message}) => {
             this.loadingExecute = false
             const toast = useToastInstance()
+            if (message) {
+              toast.error(message)
+              return
+            }
             if (typeof code !== 'string') {
               return
             }
@@ -129,9 +116,13 @@ export default {
             this.id = id
             this.loadingExecute = false
           })
-          .catch(({code}) => {
+          .catch(({code, message}) => {
             this.loadingExecute = false
             const toast = useToastInstance()
+            if (message) {
+              toast.error(message)
+              return
+            }
             if (typeof code !== 'string') {
               return
             }
@@ -148,9 +139,13 @@ export default {
             this.id = id
             this.loadingExecute = false
           })
-          .catch(({code}) => {
+          .catch(({code, message}) => {
             this.loadingExecute = false
             const toast = useToastInstance()
+            if (message) {
+              toast.error(message)
+              return
+            }
             if (typeof code !== 'string') {
               return
             }
diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue
index 6908b2b4381d88d7b5a7a19ce540b4c88c633e0e..df0948372eed1dbf60260b6f3bd835e51dd93d2a 100644
--- a/dbrepo-ui/components/subset/SubsetList.vue
+++ b/dbrepo-ui/components/subset/SubsetList.vue
@@ -14,28 +14,20 @@
         <Loading />
       </v-list-item>
       <div
-        v-for="(item, i) in subsets"
+        v-for="(subset, i) in subsets"
         :key="`q-${i}`">
         <v-divider v-if="i !== 0" class="mx-4" />
         <v-list>
           <v-list-item
             lines="two"
-            :title="title(item)"
-            :subtitle="subtitle(item)"
-            :class="clazz(item)"
-            :to="link(item)"
-            :href="link(item)">
+            :title="title(subset)"
+            :subtitle="subtitle(subset)"
+            :class="clazz(subset)"
+            :to="link(subset)"
+            :href="link(subset)">
             <template v-slot:append>
-              <v-tooltip
-                v-if="hasPublishedIdentifier(item)"
-                :text="$t('pages.identifier.pid.title')"
-                left>
-                <template v-slot:activator="{ props }">
-                  <v-icon
-                    color="primary"
-                    v-bind="props">mdi-identifier</v-icon>
-                </template>
-              </v-tooltip>
+              <ResourceStatus
+                :resource="subset" />
             </template>
           </v-list-item>
         </v-list>
@@ -45,8 +37,6 @@
 </template>
 
 <script>
-import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -55,14 +45,10 @@ export default {
       loadingSubsets: false,
       loadingIdentifiers: false,
       subsets: [],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -130,7 +116,6 @@ export default {
   }
 }
 </script>
-
 <style lang="scss" scoped>
 .pid-icon {
   flex: 0 !important;
diff --git a/dbrepo-ui/components/subset/SubsetToolbar.vue b/dbrepo-ui/components/subset/SubsetToolbar.vue
index 874e691c5f15766d7b4a0fb4809eb19058418c9c..e6026090978a3745af50b7e9a3e7a559ae5363a5 100644
--- a/dbrepo-ui/components/subset/SubsetToolbar.vue
+++ b/dbrepo-ui/components/subset/SubsetToolbar.vue
@@ -35,7 +35,6 @@
         variant="flat"
         class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null"
-        :disabled="!executionUTC"
         :to="`/database/${$route.params.database_id}/subset/${$route.params.subset_id}/persist`">
         {{ ($vuetify.display.lgAndUp ? $t('toolbars.subset.pid.xl') + ' ' : '') + $t('toolbars.subset.pid.permanent') }}
       </v-btn>
@@ -59,7 +58,6 @@
 <script>
 import DownloadButton from '@/components/identifier/DownloadButton.vue'
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -72,7 +70,6 @@ export default {
       loading: false,
       loadingSave: false,
       downloadLoading: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -87,17 +84,14 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getAccess
     },
     subset () {
       return this.cacheStore.getSubset
     },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
     identifiers () {
       if (!this.subset) {
         return []
@@ -118,9 +112,7 @@ export default {
       if (this.pid) {
         const filter = this.identifiers.filter(i => i.id === Number(this.pid))
         if (filter.length > 0) {
-          const identifier = filter[0]
-          console.debug('identifier set according to route pid', identifier)
-          return identifier
+          return filter[0]
         }
       }
       return this.identifiers[0]
@@ -155,10 +147,10 @@ export default {
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
     canGetPid () {
-      if (!this.user || !this.subset || !this.database) {
+      if (!this.cacheUser || !this.subset || !this.database) {
         return false
       }
-      return this.database.owner.id === this.user.id || (this.subset.owner.id === this.user.id && this.hasReadAccess)
+      return this.database.owner.id === this.cacheUser.uid || (this.subset.owner.id === this.cacheUser.uid && this.hasReadAccess)
     },
     title () {
       if (!this.identifier) {
@@ -177,8 +169,9 @@ export default {
       this.loadingSave = true
       const queryService = useQueryService()
       queryService.update(this.$route.params.database_id, this.$route.params.subset_id, { persist: true })
-        .then((subset) => {
-          this.subset = subset
+        .then(() => {
+          const cacheStore = useCacheStore()
+          cacheStore.reloadSubset()
           this.loadingSave = false
         })
         .catch(() => {
@@ -192,8 +185,10 @@ export default {
       this.loadingSave = true
       const queryService = useQueryService()
       queryService.update(this.$route.params.database_id, this.$route.params.subset_id, { persist: false })
-        .then((subset) => {
-          this.subset = subset
+        .then(() => {
+          const cacheStore = useCacheStore()
+          cacheStore.reloadSubset()
+          this.loadingSave = false
         })
         .catch(() => {
           this.loadingSave = false
diff --git a/dbrepo-ui/components/table/TableList.vue b/dbrepo-ui/components/table/TableList.vue
index b78e20ae3a6d423a90a636f119d96e4b406ea45d..5f87090b85855cdc7d6113a9de97bbea18106484 100644
--- a/dbrepo-ui/components/table/TableList.vue
+++ b/dbrepo-ui/components/table/TableList.vue
@@ -21,16 +21,6 @@
           <template v-slot:append>
             <ResourceStatus
               :resource="table" />
-            <v-tooltip
-              v-if="hasPublishedIdentifier(table)"
-              :text="$t('pages.identifier.pid.title')"
-              left>
-              <template v-slot:activator="{ props }">
-                <v-icon
-                  color="primary"
-                  v-bind="props">mdi-identifier</v-icon>
-              </template>
-            </v-tooltip>
           </template>
         </v-list-item>
       </v-list>
@@ -40,7 +30,6 @@
 
 <script>
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -74,19 +63,15 @@ export default {
         { value: 'string', title: 'Character Varying' },
         { value: 'text', title: 'Text' }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     tables () {
       if (!this.database) {
diff --git a/dbrepo-ui/components/table/TableToolbar.vue b/dbrepo-ui/components/table/TableToolbar.vue
index d6fd4868eae0e65a52d932339ba5bbab6e3ad56f..e09cd67cba31e8d3aaec7e9055078fa354bd4ded 100644
--- a/dbrepo-ui/components/table/TableToolbar.vue
+++ b/dbrepo-ui/components/table/TableToolbar.vue
@@ -80,7 +80,6 @@
 <script>
 import EditTuple from '@/components/dialogs/EditTuple.vue'
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -93,8 +92,7 @@ export default {
       error: false,
       edit: false,
       dropTableDialog: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -105,39 +103,42 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
     },
     hasReadAccess () {
       if (!this.access) {
         return false
       }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     canUpdateTable () {
-      if (!this.roles || !this.user || !this.table) {
+      if (!this.roles || !this.cacheUser || !this.table) {
         return false
       }
-      return this.roles.includes('update-table') && this.table.owner.id === this.user.id
+      return this.roles.includes('update-table') && this.table.owner.id === this.cacheUser.uid
     },
     canExecuteQuery () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
-      const userService = useUserService()
-      return userService.hasReadAccess(this.access) && this.roles.includes('execute-query')
+      return this.hasReadAccess && this.roles.includes('execute-query')
+    },
+    isOwner () {
+      const databaseService = useDatabaseService()
+      return databaseService.isOwner(this.database, this.cacheUser)
     },
     canCreateView () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
-      const databaseService = useDatabaseService()
-      return databaseService.isOwner(this.database, this.user) && this.roles.includes('create-database-view')
+      return this.isOwner && this.roles.includes('create-database-view')
     },
     canViewData () {
       if (!this.table) {
@@ -146,10 +147,10 @@ export default {
       if (this.table.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.table.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canViewSchema () {
       if (!this.table) {
@@ -158,22 +159,22 @@ export default {
       if (this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.table.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canImportCsv () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
       return this.roles.includes('insert-table-data')
     },
     canGetPid () {
-      if (!this.user || !this.table || !this.database) {
+      if (!this.cacheUser || !this.table || !this.database) {
         return false
       }
-      return this.database.owner.id === this.user.id || this.table.owner.id === this.user.id
+      return this.hasReadAccess && this.database.owner.id === this.cacheUser.uid || this.table.owner.id === this.cacheUser.uid
     },
     buttonVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/components/user/UserToolbar.vue b/dbrepo-ui/components/user/UserToolbar.vue
index e5a20c75a3230d80dc3e6f63c27c5bb6a743a463..54210130d32f9c1cbe73378138e6c0db28c8cc88 100644
--- a/dbrepo-ui/components/user/UserToolbar.vue
+++ b/dbrepo-ui/components/user/UserToolbar.vue
@@ -1,6 +1,9 @@
 <template>
-  <div>
-    <v-toolbar title="Settings" flat>
+  <div
+    v-if="loggedIn">
+    <v-toolbar
+      title="Settings"
+      flat>
       <template v-slot:extension>
         <v-tabs
           v-model="tab"
@@ -11,31 +14,20 @@
           <v-tab
             :text="$t('toolbars.user.authentication')"
             to="/user/authentication" />
-          <v-tab
-            :text="$t('toolbars.user.developer')"
-            to="/user/developer" />
         </v-tabs>
       </template>
     </v-toolbar>
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
-import { useUserStore } from '@/stores/user.js'
-
 export default {
   data () {
     return {
       tab: null,
-      userStore: useUserStore()
-    }
-  },
-  computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
     }
   }
 }
diff --git a/dbrepo-ui/components/view/ViewList.vue b/dbrepo-ui/components/view/ViewList.vue
index d6539bd253cb7ef40c202633db53d564ec1e6269..afa3067921b10d1c1f2fe6d78cac4e9c7781bebe 100644
--- a/dbrepo-ui/components/view/ViewList.vue
+++ b/dbrepo-ui/components/view/ViewList.vue
@@ -16,16 +16,6 @@
           <template v-slot:append>
             <ResourceStatus
               :resource="view" />
-            <v-tooltip
-              v-if="hasPublishedIdentifier(view)"
-              :text="$t('pages.identifier.pid.title')"
-              left>
-              <template v-slot:activator="{ props }">
-                <v-icon
-                  color="primary"
-                  v-bind="props">mdi-identifier</v-icon>
-              </template>
-            </v-tooltip>
           </template>
         </v-list-item>
       </v-list>
@@ -34,7 +24,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -43,14 +32,10 @@ export default {
       loading: false,
       loadingDetails: false,
       error: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue
index 4ed83ff43fa777f9f8f663cf020d89d5d58456cd..d9e0bfb6bf6740c19aac53f6b3ac8cc374be7011 100644
--- a/dbrepo-ui/components/view/ViewToolbar.vue
+++ b/dbrepo-ui/components/view/ViewToolbar.vue
@@ -57,7 +57,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import CreateOntology from '@/components/dialogs/CreateOntology.vue'
 import ViewVisibility from '@/components/dialogs/ViewVisibility.vue'
@@ -73,7 +72,6 @@ export default {
       loading: false,
       loadingDelete: false,
       updateViewDialog: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -91,6 +89,12 @@ export default {
     view () {
       return this.cacheStore.getView
     },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
     canViewData () {
       if (!this.view) {
         return false
@@ -98,10 +102,10 @@ export default {
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.view.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canViewSchema () {
       if (!this.view) {
@@ -110,32 +114,26 @@ export default {
       if (this.view.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.view.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canViewSettings () {
-      if (!this.user || !this.view) {
+      if (!this.cacheUser || !this.view) {
         return false
       }
-      return this.view.owner.id === this.user.id
+      return this.view.owner.id === this.cacheUser.uid
     },
     canCreatePid () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.cacheUser || !this.view) {
         return false
       }
-      const userService = useUserService()
-      return this.roles.includes('create-identifier') && userService.hasReadAccess(this.access)
+      const cacheUserService = useUserService()
+      return cacheUserService.hasReadAccess(this.access) && this.roles.includes('create-identifier')
     },
     access () {
-      return this.userStore.getAccess
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
diff --git a/dbrepo-ui/composables/axios-instance.ts b/dbrepo-ui/composables/axios-instance.ts
index 95edea3c28d5c12f1f2422ccf8b457e409c5b459..ca7a7b111cf70cf92524f5459808277e4b14144e 100644
--- a/dbrepo-ui/composables/axios-instance.ts
+++ b/dbrepo-ui/composables/axios-instance.ts
@@ -1,11 +1,9 @@
 import axios, {type AxiosInstance} from 'axios'
-import {useUserStore} from '@/stores/user'
 
 let instance: AxiosInstance | null = null;
 
 export const useAxiosInstance = () => {
   const config = useRuntimeConfig()
-  const userStore = useUserStore()
   if (!instance) {
     instance = axios.create({
       timeout: 90_000,
@@ -18,38 +16,16 @@ export const useAxiosInstance = () => {
       baseURL: config.public.api.client
     });
     instance.interceptors.request.use((config) => {
-      const token = userStore.getToken
-      const refreshToken = userStore.getRefreshToken
-      if (!token || !refreshToken) {
+      const { loggedIn, user, login, logout } = useOidcAuth()
+      if (!loggedIn) {
         return config
       }
-      const authenticationService = useAuthenticationService()
-      if (authenticationService.isExpiredToken(refreshToken)) {
-        console.warn('Refresh token is expired: trigger logout of user')
-        userStore.logout()
+      const { accessToken } = user.value
+      if (!accessToken) {
         return config
       }
-      if (!authenticationService.isExpiredToken(token)) {
-        config.headers.Authorization = `Bearer ${token}`
-        return config
-      }
-      console.warn('Access token expired: request a new one')
-      const userService = useUserService()
-      return userService.refreshToken(refreshToken)
-        .then((response: KeycloakOpenIdTokenDto) => {
-          userStore.setToken(response.access_token)
-          userStore.setRefreshToken(response.refresh_token)
-          console.debug('new access token expires:', authenticationService.tokenToExpiryDate(response.access_token))
-          config.headers.Authorization = `Bearer ${response.access_token}`
-          return config
-        })
-        .catch((error: ApiErrorDto) => {
-          if (error.code === 'error.user.credentials') {
-            console.warn('User session expired.')
-            userStore.logout()
-          }
-          return config
-        });
+      config.headers.Authorization = `Bearer ${accessToken}`
+      return config
     })
   }
   return instance;
diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts
index 7956f7b4dff6cb748733fd381275dd6d0622b60c..f318e073054d6a4283b654bbae985b4f903aec00 100644
--- a/dbrepo-ui/composables/database-service.ts
+++ b/dbrepo-ui/composables/database-service.ts
@@ -66,23 +66,6 @@ export const useDatabaseService = (): any => {
     });
   }
 
-  async function getServerTime(): Promise<Date> {
-    const axios = useAxiosInstance();
-    console.debug('find server time');
-    return new Promise<Date>((resolve, reject) => {
-      axios.head<Date>('/api/database')
-        .then((response) => {
-          const date: Date = new Date(response.headers['Date'])
-          console.info(`Found ${date} server time`);
-          resolve(date);
-        })
-        .catch((error) => {
-          console.error('Failed to find server time', error);
-          reject(axiosErrorToApiError(error));
-        });
-    });
-  }
-
   async function findOne(id: number, rawError: boolean = false): Promise<DatabaseDto | null> {
     const axios = useAxiosInstance();
     console.debug('find database with id', id);
@@ -239,16 +222,12 @@ export const useDatabaseService = (): any => {
     refreshTablesMetadata,
     refreshViewsMetadata,
     findOne,
-    findPreviewImage,
-    findCount,
-    getServerTime,
     updateVisibility,
     updateImage,
     updateOwner,
     create,
     databaseToOwner,
     databaseToContact,
-    databaseToJsonLd,
     isOwner
   }
 }
diff --git a/dbrepo-ui/composables/identifier-service.ts b/dbrepo-ui/composables/identifier-service.ts
index 3853d9df751aef86b62e2cb30394cf0be1896efb..6875a7cb7b2c168ecfb7357cc314219792930bf8 100644
--- a/dbrepo-ui/composables/identifier-service.ts
+++ b/dbrepo-ui/composables/identifier-service.ts
@@ -24,7 +24,7 @@ export const useIdentifierService = (): any => {
   }
 
   async function create(data: IdentifierSaveDto): Promise<IdentifierDto> {
-    const axios= useAxiosInstance()
+    const axios = useAxiosInstance()
     console.debug('create identifier')
     return new Promise<IdentifierDto>((resolve, reject) => {
       axios.post<IdentifierDto>('/api/identifier', data)
@@ -40,7 +40,7 @@ export const useIdentifierService = (): any => {
   }
 
   async function save(data: IdentifierSaveDto): Promise<IdentifierDto> {
-    const axios= useAxiosInstance()
+    const axios = useAxiosInstance()
     console.debug('save identifier', data.id)
     return new Promise<IdentifierDto>((resolve, reject) => {
       axios.put<IdentifierDto>(`/api/identifier/${data.id}`, data)
@@ -103,7 +103,7 @@ export const useIdentifierService = (): any => {
     })
   }
 
-  function identifierToCreators(identifier: IdentifierDto) {
+  function identifierToCreators(identifier: IdentifierDto): string | null {
     if (!identifier) {
       return null
     }
@@ -241,13 +241,28 @@ export const useIdentifierService = (): any => {
     if (!data || !data.titles || data.titles.length === 0) {
       return null
     }
-    const filtered = data.titles.filter(d => d.language && d.language === 'en')
+    const filtered = data.titles.filter((d) => d.language && d.language === 'en')
     if (filtered.length === 0) {
-      return data.titles[0].title
+      const title = data.titles[0]
+      return title.title
     }
     return filtered[0].title
   }
 
+  function identifierToResourceUrl(identifier: IdentifierDto): string | null {
+    const config = useRuntimeConfig()
+    switch (identifier.type) {
+      case 1:
+        return `${config.public.api.client}/api/database/${identifier.database_id}/subset/${identifier.subset_id}/data`
+      case 2:
+        return `${config.public.api.client}/api/database/${identifier.database_id}/table/${identifier.table_id}/data`
+      case 3:
+        return `${config.public.api.client}/api/database/${identifier.database_id}/view/${identifier.view_id}/data`
+      default:
+        return null
+    }
+  }
+
   function identifierToUrl(data: IdentifierDto): string | null {
     if (!data) {
       return null
@@ -315,244 +330,48 @@ export const useIdentifierService = (): any => {
     return jsonLd
   }
 
-  function identifierToHasPartJsonLd(identifier: IdentifierDto) {
-    return {
-      '@type': 'Dataset',
-      name: identifierPreferEnglishTitle(identifier),
-      description: identifierPreferEnglishDescription(identifier),
-      identifier: identifierToUrl(identifier),
-      citation: identifierToUrl(identifier),
-      temporalCoverage: identifier.publication_year,
-      version: identifier.created
-    }
-  }
-
-  function databaseToServerHead(database: DatabaseDto) {
-    if (!database) {
-      return
+  function identifiersToServerHead(identifiers: IdentifierBriefDto[]): any {
+    if (!identifiers || !identifiers[0]) {
+      return null
     }
-    const config = useRuntimeConfig()
+    const identifier = identifiers[0]
     /* Google Rich Results */
     const json: any = {
       '@context': 'https://schema.org/',
       '@type': 'Dataset',
-      url: `${config.public.api.client}/database/${database.id}/info`,
-      citation: `${config.public.api.client}/database/${database.id}/info`,
+      url: identifierToUrl(identifier),
+      citation: identifierToUrl(identifier),
       hasPart: [],
-      version: database.created
+      identifier: identifiers.map(i => identifierToUrl(i)),
+      creator: identifier.creators.map((c) => creatorToCreatorJsonLd(c)),
+      temporalCoverage: identifier.publication_year
     }
-    /* FAIR Signposting */
-    const meta: any [] = []
-    if (database.identifiers.length > 0) {
-      const identifier = database.identifiers[0]
-      const partIdentifiers: IdentifierDto[] = []
-      if (database.subsets.length > 0) {
-        database.subsets.forEach((s) => {
-          partIdentifiers.push(s)
-        })
-      }
-      if (database.tables.length > 0) {
-        database.tables.forEach((t) => {
-          if (t.identifiers.length > 0) {
-            t.identifiers.forEach(i => partIdentifiers.push(i))
-          }
-        })
-      }
-      if (database.views.length > 0) {
-        database.views.forEach((v) => {
-          if (v.identifiers.length > 0) {
-            v.identifiers.forEach(i => partIdentifiers.push(i))
-          }
-        })
-      }
+    if (identifier.titles.length > 0) {
       json['name'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = database.identifiers.map(i => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['hasPart'] = partIdentifiers.map(i => identifierToHasPartJsonLd(i))
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto) => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
-      }
-    }
-    return {
-      script: [
-        {
-          type: 'application/ld+json',
-          innerHTML: json
-        }
-      ],
-      link: meta
     }
-  }
-
-  function subsetToServerHead(subset: QueryDto) {
-    const config = useRuntimeConfig()
-    /* Google Rich Results */
-    const json: any = {
-      '@context': 'https://schema.org/',
-      '@type': 'Dataset',
-      description: subset.query,
-      url: `${config.public.api.client}/database/${subset.database_id}/info`,
-      citation: `${config.public.api.client}/database/${subset.database_id}/info`,
-      hasPart: [],
-      version: subset.created
-    }
-    /* FAIR Signposting */
-    const meta: any[] = []
-    if (subset.identifiers.length > 0) {
-      const identifier = subset.identifiers[0]
-      json['name'] = identifierPreferEnglishTitle(identifier)
+    if (identifier.descriptions.length > 0) {
       json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = subset.identifiers.map(i => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto) => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
-      }
-      meta.push({
-        rel: 'item',
-        type: 'application/json',
-        href: `${config.public.api.client}/api/database/${subset.database_id}/subset/${subset.id}/data`
-      })
-      meta.push({
-        rel: 'item',
-        type: 'text/csv',
-        href: `${config.public.api.client}/api/database/${subset.database_id}/subset/${subset.id}/data`
-      })
-    }
-    return {
-      script: [
-        {
-          type: 'application/ld+json',
-          innerHTML: json
-        }
-      ],
-      link: meta
-    }
-  }
-
-  function tableToServerHead(table: TableDto) {
-    const config = useRuntimeConfig()
-    /* Google Rich Results */
-    const json: any = {
-      '@context': 'https://schema.org/',
-      '@type': 'Dataset',
-      description: table.description,
-      url: `${config.public.api.client}/database/${table.database_id}/table/${table.id}/info`,
-      citation: `${config.public.api.client}/database/${table.database_id}/table/${table.id}/info`,
-      hasPart: [],
-      version: table.created
     }
     /* FAIR Signposting */
     const meta: any[] = []
-    if (table.identifiers.length > 0) {
-      const identifier: IdentifierDto = table.identifiers[0]
-      json['name'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = table.identifiers.map((i: IdentifierDto) => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map((c: CreatorDto) => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto): void => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
+    meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
+    identifier.creators.forEach((c: CreatorDto) => {
+      if (c.name_identifier) {
+        meta.push({rel: 'author', href: c.name_identifier})
       }
-      meta.push({
-        rel: 'item',
-        type: 'application/json',
-        href: `${config.public.api.client}/api/database/${table.database_id}/table/${table.id}/data`
-      })
-      meta.push({
-        rel: 'item',
-        type: 'text/csv',
-        href: `${config.public.api.client}/api/database/${table.database_id}/table/${table.id}/data`
-      })
-    }
-    return {
-      script: [
-        {
-          type: 'application/ld+json',
-          innerHTML: json
-        }
-      ],
-      link: meta
-    }
-  }
-
-  function viewToServerHead(view: ViewDto) {
-    const config = useRuntimeConfig()
-    /* Google Rich Results */
-    const json: any = {
-      '@context': 'https://schema.org/',
-      '@type': 'Dataset',
-      description: view.query,
-      url: `${config.public.api.client}/database/${view.database_id}/table/${view.id}/info`,
-      citation: `${config.public.api.client}/database/${view.database_id}/table/${view.id}/info`,
-      hasPart: [],
-      version: view.created
-    }
-    /* FAIR Signposting */
-    const meta: any[] = []
-    if (view.identifiers.length > 0) {
-      const identifier = view.identifiers[0]
-      json['name'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = view.identifiers.map(i => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto) => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
-      }
-      meta.push({
-        rel: 'item',
-        type: 'application/json',
-        href: `${config.public.api.client}/api/database/${view.database_id}/view/${view.id}/data`
-      })
-      meta.push({
-        rel: 'item',
-        type: 'text/csv',
-        href: `${config.public.api.client}/api/database/${view.database_id}/view/${view.id}/data`
-      })
-    }
+    })
+    meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
+    meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
+    meta.push({
+      rel: 'item',
+      type: 'application/json',
+      href: identifierToResourceUrl(identifier)
+    })
+    meta.push({
+      rel: 'item',
+      type: 'text/csv',
+      href: identifierToResourceUrl(identifier)
+    })
     return {
       script: [
         {
@@ -564,56 +383,15 @@ export const useIdentifierService = (): any => {
     }
   }
 
-  function databaseToServerSeoMeta(database: DatabaseDto) {
-    const json: any = {
-      ogTitle: database.name
-    }
-    if (database.identifiers.length > 0) {
-      const identifier = database.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
-    }
-    return json
-  }
-
-  function subsetToServerSeoMeta(subset: QueryDto) {
-    const json: any = {
-      description: subset.query
-    }
-    if (subset.identifiers.length > 0) {
-      const identifier = subset.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
-    }
-    return json
-  }
-
-  function tableToServerSeoMeta(table: TableDto) {
-    const json: any = {
-      ogTitle: table.name,
-      description: table.description
-    }
-    if (table.identifiers.length > 0) {
-      const identifier = table.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
+  function identifiersToServerSeoMeta(identifiers: IdentifierBriefDto[]): any | null {
+    if (!identifiers|| !identifiers[0]) {
+      return null
     }
-    return json
-  }
-
-  function viewToServerSeoMeta(view: ViewDto) {
+    const identifier = identifiers[0]
     const json: any = {
-      ogTitle: view.name,
-      description: view.query
-    }
-    if (view.identifiers.length > 0) {
-      const identifier = view.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
+      ogTitle: identifierPreferEnglishTitle(identifier),
+      ogDescription: identifierPreferEnglishDescription(identifier),
+      description: identifierPreferEnglishDescription(identifier)
     }
     return json
   }
@@ -633,13 +411,7 @@ export const useIdentifierService = (): any => {
     identifierToUrl,
     identifierToDisplayName,
     identifierToDisplayAcronym,
-    databaseToServerHead,
-    subsetToServerHead,
-    tableToServerHead,
-    viewToServerHead,
-    databaseToServerSeoMeta,
-    subsetToServerSeoMeta,
-    tableToServerSeoMeta,
-    viewToServerSeoMeta,
+    identifiersToServerHead,
+    identifiersToServerSeoMeta
   }
 }
diff --git a/dbrepo-ui/composables/query-service.ts b/dbrepo-ui/composables/query-service.ts
index 119915de2785763d549bdf3bf2d97379811f8fed..e314993ecd233c486198f7995dff4da5389eb06f 100644
--- a/dbrepo-ui/composables/query-service.ts
+++ b/dbrepo-ui/composables/query-service.ts
@@ -161,12 +161,12 @@ export const useQueryService = (): any => {
           }
         }
         sql += ` \`${clause.params[0]}\` ${clause.params[1]} `
-        const filteredType = types.filter(t => t.value === filteredColumn[0].column_type)
+        const filteredType = types.filter(t => t.value === filteredColumn[0].type)
         if (filteredType.length === 0) {
           return {
             error: true,
             reason: 'exists',
-            column: filteredColumn[0].column_type,
+            column: filteredColumn[0].type,
             raw: null,
             formatted: null
           }
@@ -175,7 +175,7 @@ export const useQueryService = (): any => {
           return {
             error: true,
             reason: 'build',
-            column: filteredColumn[0].column_type,
+            column: filteredColumn[0].type,
             raw: null,
             formatted: null
           }
diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts
index ca757c7451d70c4bd1fffc36b72c6a23d7fdde58..5f290745245b46a8ce395a489f62aa9171800d5a 100644
--- a/dbrepo-ui/composables/table-service.ts
+++ b/dbrepo-ui/composables/table-service.ts
@@ -9,7 +9,7 @@ export const useTableService = (): any => {
     return new Promise<TableBriefDto>((resolve, reject) => {
       axios.get<TableBriefDto>(`/api/database/${databaseId}/table`)
         .then((response) => {
-          console.info('Found tables(s)')
+          console.info(`Found ${response.data.length} tables(s)`)
           resolve(response.data)
         })
         .catch((error) => {
@@ -25,7 +25,7 @@ export const useTableService = (): any => {
     return new Promise<TableDto>((resolve, reject) => {
       axios.get<TableDto>(`/api/database/${databaseId}/table/${tableId}`)
         .then((response) => {
-          console.info('Found table with id', tableId, 'in database with id', databaseId);
+          console.info('Found table');
           resolve(response.data)
         })
         .catch((error) => {
@@ -41,7 +41,7 @@ export const useTableService = (): any => {
     return new Promise<ColumnDto>((resolve, reject) => {
       axios.put<ColumnDto>(`/api/database/${databaseId}/table/${tableId}/column/${columnId}`, data)
         .then((response) => {
-          console.info('Updated column with id', columnId, 'table with id', tableId, 'in database with id', databaseId);
+          console.info('Updated column');
           resolve(response.data)
         })
         .catch((error) => {
@@ -57,7 +57,7 @@ export const useTableService = (): any => {
     return new Promise<TableDto>((resolve, reject) => {
       axios.put<TableDto>(`/api/database/${databaseId}/table/${tableId}`, data)
         .then((response) => {
-          console.info('Updated table with id', tableId, 'in database with id', databaseId);
+          console.info('Updated table');
           resolve(response.data)
         })
         .catch((error) => {
@@ -73,7 +73,7 @@ export const useTableService = (): any => {
     return new Promise<ImportDto>((resolve, reject) => {
       axios.post<ImportDto>(`/api/database/${databaseId}/table/${tableId}/data/import`, data)
         .then((response) => {
-          console.info('Imported csv to table with id', tableId, 'in database with id', databaseId)
+          console.info('Imported csv to table')
           resolve(response.data)
         })
         .catch((error) => {
@@ -89,7 +89,7 @@ export const useTableService = (): any => {
     return new Promise<QueryResultDto>((resolve, reject) => {
       axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/data`, { params: mapFilter(timestamp, page, size) })
         .then((response) => {
-          console.info('Got data for table with id', tableId, 'in database with id', databaseId)
+          console.info('Got data for table')
           const result: QueryResultDto = {
             id: tableId,
             headers: response.headers['x-headers'] ? response.headers['x-headers'].split(',') : [],
@@ -111,7 +111,7 @@ export const useTableService = (): any => {
       axios.head<void>(`/api/database/${databaseId}/table/${tableId}/data`, { params: mapFilter(timestamp, null, null) })
         .then((response: AxiosResponse<void>) => {
           const count: number = Number(response.headers['x-count'])
-          console.info('Found' + count + 'in table with id', tableId, 'in database with id', databaseId)
+          console.info(`Found ${count} tuple(s)`)
           resolve(count)
         })
         .catch((error) => {
@@ -134,7 +134,7 @@ export const useTableService = (): any => {
     return new Promise<QueryResultDto>((resolve, reject) => {
       axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/export`, config)
         .then((response) => {
-          console.info('Exported data for table with id', tableId, 'in database with id', databaseId)
+          console.info('Exported data for table')
           resolve(response.data)
         })
         .catch((error) => {
@@ -150,7 +150,7 @@ export const useTableService = (): any => {
     return new Promise<TableDto>((resolve, reject) => {
       axios.post<TableDto>(`/api/database/${databaseId}/table`, data)
         .then((response) => {
-          console.info('Created table in database with id', databaseId)
+          console.info('Created table')
           resolve(response.data)
         })
         .catch((error: AxiosError) => {
@@ -166,7 +166,7 @@ export const useTableService = (): any => {
     return new Promise<void>((resolve, reject) => {
       axios.delete<void>(`/api/database/${databaseId}/table/${tableId}`)
         .then((response) => {
-          console.info('Deleted table with id', tableId, 'in database with id', databaseId)
+          console.info('Deleted table')
           resolve(response.data)
         })
         .catch((error) => {
@@ -182,7 +182,7 @@ export const useTableService = (): any => {
     return new Promise<void>((resolve, reject) => {
       axios.delete<void>(`/api/database/${databaseId}/table/${tableId}`, {data})
         .then((response) => {
-          console.info('Deleted tuple(s) in table with id', tableId, 'in database with id', databaseId)
+          console.info(`Deleted tuple(s)`)
           resolve(response.data)
         })
         .catch((error) => {
@@ -198,7 +198,7 @@ export const useTableService = (): any => {
     return new Promise<TableHistoryDto[]>((resolve, reject) => {
       axios.get<TableHistoryDto[]>(`/api/database/${databaseId}/table/${tableId}/history`)
         .then((response) => {
-          console.info('Loaded history of table with id', tableId, 'in database with id', databaseId)
+          console.info('Loaded history of table')
           resolve(response.data)
         })
         .catch((error) => {
@@ -214,7 +214,7 @@ export const useTableService = (): any => {
     return new Promise<TableColumnEntityDto[]>((resolve, reject) => {
       axios.get<TableColumnEntityDto[]>(`/api/database/${databaseId}/table/${tableId}/column/${columnId}/suggest`)
         .then((response) => {
-          console.info('Suggested semantic entities for table column with id', columnId, 'of table with id', tableId, 'of database with id', databaseId)
+          console.info('Suggested semantic entities')
           resolve(response.data)
         })
         .catch((error) => {
@@ -255,7 +255,7 @@ export const useTableService = (): any => {
     if (!table || !user) {
       return false
     }
-    return table.owner.id === user.id
+    return table.owner.id === user.uid
   }
 
   function tableNameToInternalName(name: string) {
diff --git a/dbrepo-ui/composables/upload-service.ts b/dbrepo-ui/composables/upload-service.ts
index f7a6964d58cba007c3aa7e515f362349ca0a4f4a..ee0bdd5dc029a061ee102a9e526933ef7ca26413 100644
--- a/dbrepo-ui/composables/upload-service.ts
+++ b/dbrepo-ui/composables/upload-service.ts
@@ -1,11 +1,9 @@
 import * as tus from 'tus-js-client'
 import {useCacheStore} from '@/stores/cache'
-import {useUserStore} from '@/stores/user'
 
 export const useUploadService = (): any => {
 
   function create (data: File) {
-    const userStore = useUserStore()
     const config = useRuntimeConfig()
     const endpoint = config.public.upload.client
     return new Promise<string>((resolve, reject) => {
@@ -13,10 +11,16 @@ export const useUploadService = (): any => {
         console.error('Your browser does not support uploads!')
         return
       }
+      const { loggedIn, user, login, logout } = useOidcAuth()
+      if (!loggedIn || !user.value?.accessToken) {
+        console.error('Please login to use the upload!')
+        return
+      }
+      const { accessToken } = user.value
       const uploadClient: tus.Upload = new tus.Upload(data, {
         endpoint,
         headers: {
-          'Authorization': `Bearer ${userStore.getToken}`
+          'Authorization': `Bearer ${accessToken}`
         },
         retryDelays: [0, 3000, 5000, 10000, 20000],
         onError (error) {
diff --git a/dbrepo-ui/composables/user-service.ts b/dbrepo-ui/composables/user-service.ts
index e68b914e0e5bd5cfc410b82213e18f3eb0fa32ab..3425dbaa5c7d77d927798914b8a4fdac6123c166 100644
--- a/dbrepo-ui/composables/user-service.ts
+++ b/dbrepo-ui/composables/user-service.ts
@@ -80,32 +80,6 @@ export const useUserService = (): any => {
     })
   }
 
-  async function obtainToken(username: string, password: string): Promise<KeycloakOpenIdTokenDto> {
-    console.debug('obtain user token for user with username', username)
-    return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => {
-      const config = useRuntimeConfig()
-      const userStore = useUserStore()
-      const instance = axios.create({
-        timeout: 90_000,
-        params: {},
-        baseURL: config.public.api.client
-      })
-      instance.post<KeycloakOpenIdTokenDto>('/api/user/token', {username, password})
-        .then((response) => {
-          console.info('Obtained user token')
-          // eslint-disable-next-line camelcase
-          const {access_token, refresh_token} = response.data
-          userStore.setToken(access_token)
-          userStore.setRefreshToken(refresh_token)
-          userStore.setRoles(tokenToRoles(access_token))
-          resolve(response.data)
-        }).catch((error) => {
-          console.error('Failed to obtain user token', error)
-          reject(axiosErrorToApiError(error))
-      })
-    })
-  }
-
   async function refreshToken(refreshToken: string): Promise<KeycloakOpenIdTokenDto> {
     console.debug('refresh user token')
     return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => {
@@ -136,21 +110,6 @@ export const useUserService = (): any => {
     return data.realm_access.roles || []
   }
 
-  function tokenToUserId(token: string): string {
-    const data: Token = jwtDecode<Token>(token)
-    return data.uid
-  }
-
-  function userInfoToUser(data: UserDto) {
-    const obj: UserDto = Object.assign({}, data)
-    obj.attributes = {
-      theme: data.attributes.theme,
-      orcid: data.attributes.orcid,
-      affiliation: data.attributes.affiliation
-    }
-    return obj
-  }
-
   function nameIdentifierToNameIdentifierScheme(nameIdentifier: string) {
     if (nameIdentifier.includes('orcid.org')) {
       return 'ORCID'
@@ -182,13 +141,13 @@ export const useUserService = (): any => {
   }
 
   function hasWriteAccess(table: TableDto, access: DatabaseAccessDto, user: UserDto): boolean {
-    if (!table || !access) {
+    if (!table || !access || !user) {
       return false
     }
     if (access.type === 'write_all') {
       return true
     }
-    return access.type === 'write_own' && table.owner.id === user.id
+    return access.type === 'write_own' && table.owner.id === user.uid
   }
 
   return {
@@ -197,11 +156,6 @@ export const useUserService = (): any => {
     update,
     create,
     updatePassword,
-    obtainToken,
-    refreshToken,
-    tokenToRoles,
-    tokenToUserId,
-    userInfoToUser,
     nameIdentifierToNameIdentifierScheme,
     userToFullName,
     hasReadAccess,
diff --git a/dbrepo-ui/dto/index.ts b/dbrepo-ui/dto/index.ts
index 9171734aa350f242d2f38b0d0d0f795871f0306d..605a7c0db9984525632570c70e76dd542845f225 100644
--- a/dbrepo-ui/dto/index.ts
+++ b/dbrepo-ui/dto/index.ts
@@ -224,7 +224,11 @@ interface IdentifierFunderSaveDto {
 
 interface IdentifierDto {
   id: number;
-  type: string;
+  database_id: number | null;
+  query_id: number | null;
+  table_id: number | null;
+  view_id: number | null;
+  type: IdentifierTypeDto;
   titles: IdentifierTitleDto[] | [];
   descriptions: IdentifierDescriptionDto[] | [];
   funders: IdentifierFunderDto[] | [];
@@ -236,23 +240,43 @@ interface IdentifierDto {
   licenses: LicenseDto[] | [];
   creators: CreatorDto[] | [];
   created: Date;
-  database_id: number | null;
-  query_id: number | null;
-  table_id: number | null;
-  view_id: number | null;
   query_normalized: string | null;
   related_identifiers: RelatedIdentifierDto[] | [];
   query_hash: string | null;
   result_hash: string | null;
-  /**
-   * @deprecated
-   */
   result_number: number | null;
   publication_day: number | null;
   publication_month: number | null;
-  value: string | null;
   publication_year: number;
-  last_modified: Date;
+}
+
+enum IdentifierTypeDto {
+  database,
+  subset,
+  table,
+  view
+}
+
+enum IdentifierStatusTypeDto {
+  draft,
+  published
+}
+
+interface IdentifierBriefDto {
+  id: number;
+  database_id: number | null;
+  query_id: number | null;
+  table_id: number | null;
+  view_id: number | null;
+  type: IdentifierTypeDto;
+  creators: CreatorBriefDto[] | [];
+  titles: IdentifierTitleDto[] | [];
+  description: IdentifierDescriptionDto[] | [];
+  doi: string | null;
+  publisher: string;
+  publication_year: number;
+  status: IdentifierStatusTypeDto;
+  owned_by: string;
 }
 
 interface IdentifierTitleDto {
@@ -279,19 +303,35 @@ interface IdentifierFunderDto {
   award_title: string;
 }
 
+enum NameTypeDto {
+  Personal,
+  Organizational
+}
+
 interface CreatorDto {
   id: number;
   firstname: string;
   lastname: string;
   affiliation: string;
   creator_name: string;
-  name_type: string;
-  name_identifier: string;
-  name_identifier_scheme: string;
-  name_identifier_scheme_uri: string;
-  affiliation_identifier: string;
-  affiliation_identifier_scheme: string;
-  affiliation_identifier_scheme_uri: string;
+  name_type: NameTypeDto | null;
+  name_identifier: string | null;
+  name_identifier_scheme: string | null;
+  name_identifier_scheme_uri: string | null;
+  affiliation_identifier: string | null;
+  affiliation_identifier_scheme: string | null;
+  affiliation_identifier_scheme_uri: string | null;
+}
+
+interface CreatorBriefDto {
+  id: number;
+  affiliation: string;
+  creator_name: string;
+  name_type: NameTypeDto | null;
+  name_identifier: string | null;
+  name_identifier_scheme: string | null;
+  affiliation_identifier: string | null;
+  affiliation_identifier_scheme: string | null;
 }
 
 interface RelatedIdentifierDto {
@@ -342,7 +382,6 @@ interface ColumnDto {
   database_id: number;
   table_id: number;
   internal_name: string;
-  date_format: ImageDateDto;
   is_primary_key: boolean;
   index_length: number;
   length: number;
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index 0ad4cb818d353d283c15d0cc7c6240fec513a54b..3ac8e32f900e9b2b95cfb5ab3dc6929a5aae7684 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -96,29 +96,22 @@
           @click:append-inner="retrieve" />
         <v-spacer />
         <v-btn
-          v-if="!user"
+          v-if="!loggedIn"
           class="mr-2"
           color="secondary"
           variant="flat"
+          :loading="loadingLogin"
           :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-login' : null"
-          to="/login">
+          @click="loadingLogin=true;login()">
           {{ $t('navigation.login') }}
         </v-btn>
         <v-btn
-          v-if="!user"
-          color="primary"
-          variant="flat"
-          :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-account-plus' : null"
-          to="/signup">
-          {{ $t('navigation.signup') }}
-        </v-btn>
-        <v-btn
-          v-if="user"
+          v-if="cacheUser"
           to="/user"
           variant="plain"
-          :text="user.username" />
+          :text="cacheUser.preferred_username" />
         <v-menu
-          v-if="user"
+          v-if="loggedIn"
           location="bottom">
           <template v-slot:activator="{ props }">
             <v-btn
@@ -127,20 +120,19 @@
           </template>
           <v-list>
             <v-list-item
-              v-if="user"
+              v-if="cacheUser"
               exact
-              :to="`/search?type=database&owner.username=${user.username}`">
+              :to="`/search?type=database&owner.username=${cacheUser.username}`">
               {{ $t('navigation.databases') + ' ' + $t('navigation.mine')}}
             </v-list-item>
             <v-list-item
-              v-if="user"
+              v-if="cacheUser"
               exact
-              :to="`/search?type=identifier&identifiers.creator.username=${user.username}`">
+              :to="`/search?type=identifier&identifiers.creator.username=${cacheUser.username}`">
               {{ $t('navigation.identifiers') + ' ' + $t('navigation.mine') }}
             </v-list-item>
             <v-list-item
-              v-if="user"
-              @click="logout">
+              @click="logout()">
               {{ $t('navigation.logout') }}
             </v-list-item>
           </v-list>
@@ -161,10 +153,13 @@
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { useCacheStore } from '@/stores/cache.js'
 
+const { loggedIn, user, login, logout } = useOidcAuth()
+const cacheStore = useCacheStore()
+cacheStore.setUser(loggedIn ? user.value?.userInfo : null)
+cacheStore.setRoles(loggedIn ? user.value?.claims?.realm_access?.roles : [])
 const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
 useServerHead({
   title: runtimeConfig.public.title,
   meta: [
@@ -175,9 +170,9 @@ useServerHead({
 </script>
 <script>
 import JumboBox from '@/components/JumboBox.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import { errorCodeKey, makeError } from '@/utils'
+import {useNuxtApp} from "#app";
 
 export default {
   components: {
@@ -189,6 +184,7 @@ export default {
       model: null,
       query: null,
       loading: true,
+      loadingLogin: false,
       databaseError: null,
       accessError: null,
       searchResults: [],
@@ -197,26 +193,13 @@ export default {
       loadingSearch: false,
       loadingDatabases: false,
       search: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    locale () {
-      return this.userStore.getLocale
-    },
     messages () {
       return this.cacheStore.getMessages
     },
-    access () {
-      return this.userStore.getAccess
-    },
     table () {
       return this.cacheStore.getTable
     },
@@ -229,6 +212,18 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    identifier () {
+      return this.cacheStore.getIdentifier
+    },
     resource () {
       if (!this.$route.params.database_id) {
         return null
@@ -244,9 +239,6 @@ export default {
       }
       return 'database'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     version () {
       return this.$config.public.version
     },
@@ -260,22 +252,25 @@ export default {
       return this.$config.public.commit.substr(0, 8)
     },
     error () {
+      if (this.identifier) {
+        return null
+      }
       if (this.databaseError) {
         return this.databaseError
       }
       if (this.accessError) {
         return this.accessError
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return null
       }
-      if (this.table && !this.table.is_public && !this.table.is_schema_public && this.table.owner.id !== this.user.id) {
+      if (this.table && !this.table.is_public && !this.table.is_schema_public && !this.access) {
         return makeError(403, null, null)
       }
-      if (this.view && !this.view.is_public && !this.view.is_schema_public && this.view.owner.id !== this.user.id) {
+      if (this.view && !this.view.is_public && !this.view.is_schema_public && !this.access) {
         return makeError(403, null, null)
       }
-      if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && this.subset.owner.id !== this.user.id) {
+      if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && !this.access) {
         return makeError(403, null, null)
       }
       return null
@@ -287,41 +282,53 @@ export default {
       return this.roles.includes('list-ontologies')
     },
     canListContainers () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-containers')
+      return this.cacheUser
     },
     logo () {
       return this.$config.public.logo
     },
+    locale () {
+      return this.cacheStore.getLocale
+    },
     searchVariant () {
       const runtimeConfig = useRuntimeConfig()
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : 'solo-filled'
-    },
+    }
   },
   watch: {
     '$route.params': {
       handler (newObj, oldObj) {
+        if (import.meta.server) {
+          return
+        }
         if (!newObj.database_id) {
           this.databaseError = null
           this.accessError = null
           this.cacheStore.setTable(null)
           this.cacheStore.setView(null)
           this.cacheStore.setSubset(null)
+          this.cacheStore.setAccess(null)
+          this.cacheStore.setIdentifier(null)
           return
         }
-        if (import.meta.server) {
-          return
+        if (this.identifier) {
+          if (newObj.query_id && this.identifier.query_id !== Number(newObj.query_id)) {
+            this.cacheStore.setIdentifier(null)
+          } else if (newObj.table_id && this.identifier.table_id !== Number(newObj.table_id)) {
+            this.cacheStore.setIdentifier(null)
+          } else if (newObj.view_id && this.identifier.view_id !== Number(newObj.view_id)) {
+            this.cacheStore.setIdentifier(null)
+          }
+          if (this.$route.query.pid && this.identifier.id !== Number(this.$route.query.pid)) {
+            this.cacheStore.setIdentifier(null)
+          }
         }
         /* load database and optional access */
+        this.cacheStore.setRouteAccess(newObj.database_id, this.cacheUser?.uid)
         this.cacheStore.setRouteDatabase(newObj.database_id)
           .catch((error) => {
             this.databaseError = error
           })
-        if (this.user) {
-          this.userStore.setRouteAccess(newObj.database_id)
-        }
         /* load table */
         if (newObj.table_id) {
           this.cacheStore.setRouteTable(newObj.database_id, newObj.table_id)
@@ -346,43 +353,33 @@ export default {
     }
   },
   mounted () {
-    this.initEnvironment()
     if (this.$route.query && this.$route.query.q) {
       this.search = this.$route.query.q
     }
-    if (!this.user) {
+    if (!this.cacheUser) {
       return
     }
     this.setTheme()
+    this.setLocale()
     this.cacheStore.reloadMessages()
   },
   methods: {
-    errorCodeKey,
-    login () {
-      const redirect = ![undefined, '/', '/login'].includes(this.$router.currentRoute.path)
-      this.$router.push({ path: '/login', query: redirect ? { redirect: this.$router.currentRoute.path } : {} })
-    },
-    logout () {
-      this.$vuetify.theme.global.name = 'tuwThemeLight'
-      this.userStore.logout()
-      this.$router.push('/database')
-    },
     retrieve () {
       console.debug('performing fuzzy search')
       this.$router.push({ path: '/search', query: { q: this.search } })
     },
-    initEnvironment () {
-      if (this.token && !this.user) {
-        console.error('Something went wrong with loading the user: reset user cache')
-        this.userStore.logout()
-      }
+    setLocale () {
       if (!this.locale) {
-        this.userStore.setLocale('en')
+        this.cacheStore.setLocale('en')
+        return
       }
       this.$i18n.locale = this.locale
     },
     setTheme () {
-      switch (this.user.attributes.theme) {
+      if (!this.cacheUser?.theme) {
+        return
+      }
+      switch (this.cacheUser.theme) {
         case 'dark':
           this.$vuetify.theme.global.name = 'tuwThemeDark'
           break
@@ -396,10 +393,6 @@ export default {
           this.$vuetify.theme.global.name = 'tuwThemeDarkContrast'
           break
       }
-    },
-    setLocale (code) {
-      this.userStore.setLocale(code)
-      this.$i18n.locale = this.locale
     }
   }
 }
diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json
index 2e94f572ec68f7f3c595254ed5c9a5e14099e623..07ac0163ef086dd1915d90daf5cf7aabc59695d4 100644
--- a/dbrepo-ui/locales/en-US.json
+++ b/dbrepo-ui/locales/en-US.json
@@ -606,10 +606,10 @@
       },
       "status": {
         "title": "Status",
-        "public": "Public",
+        "public": "Visible",
         "data": "Data-only",
         "schema": "Schema-only",
-        "draft": "Draft"
+        "draft": "Hidden"
       },
       "resource": {
         "data": {
diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts
index 4bce6ec5c5b3dc7f025734d9bf15d8e914123f79..b3da7bd98c657513e85c64cd51fac4c118d433b7 100644
--- a/dbrepo-ui/nuxt.config.ts
+++ b/dbrepo-ui/nuxt.config.ts
@@ -3,7 +3,7 @@ import vuetify from 'vite-plugin-vuetify'
 
 const proxy: any = {}
 
-/* proxies the backend calls, >>NOT<< the frontend calls (clicking) */
+/* proxies the backend calls, >>NOT<< the frontend calls */
 if (process.env.NODE_ENV === 'development') {
   const api = 'http://localhost'
   proxy['/api'] = api
@@ -14,7 +14,14 @@ if (process.env.NODE_ENV === 'development') {
       '^/pid': '/pid'
     }
   }
+  process.env.VERSION = 'bun-dev'
   process.env.NUXT_PUBLIC_API_SERVER = api
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL = api + '/realms/dbrepo/protocol/openid-connect/auth'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI = api + ':3001'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL = api + '/realms/dbrepo/protocol/openid-connect/logout'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI = api + ':3001/auth/keycloak/callback'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL = api + '/realms/dbrepo/protocol/openid-connect/token'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL = api + '/realms/dbrepo/protocol/openid-connect/userinfo'
 }
 
 /**
@@ -107,11 +114,37 @@ export default defineNuxtConfig({
     port: 3001
   },
 
+  oidc: {
+    defaultProvider: 'keycloak',
+    providers: {
+      keycloak: {
+        audience: 'account',
+        authorizationUrl: '',
+        baseUrl: 'http://localhost/realms/dbrepo',
+        clientId: 'dbrepo-client',
+        clientSecret: 'MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG',
+        exposeAccessToken: true,
+        logoutRedirectUri: '',
+        logoutUrl: '',
+        optionalClaims: ['realm_access'],
+        redirectUri: 'http://localhost',
+        scope: ['openid', 'roles'],
+        tokenUrl: '',
+        userInfoUrl: ''
+      },
+    },
+    middleware: {
+      globalMiddlewareEnabled: false,
+      customLoginPage: false
+    },
+  },
+
   modules: [
-    '@artmizu/nuxt-prometheus',
+    ['@artmizu/nuxt-prometheus', {verbose: false}],
     '@nuxtjs/i18n',
     '@pinia/nuxt',
     '@pinia-plugin-persistedstate/nuxt',
+    'nuxt-oidc-auth',
     async (options, nuxt) => {
       nuxt.hooks.hook('vite:extendConfig', config => config.plugins.push(
         vuetify()
@@ -160,6 +193,8 @@ export default defineNuxtConfig({
     },
   },
 
-  devtools: {enabled: true},
-  compatibilityDate: '2024-07-24'
+  devtools: {
+    enabled: false
+  },
+  compatibilityDate: '2025-01-25'
 })
diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json
index a1354778200ebabb28a575e204e264e6bd155774..d7d4917e9f45f113156951746486755d91ae7bed 100644
--- a/dbrepo-ui/package.json
+++ b/dbrepo-ui/package.json
@@ -4,7 +4,7 @@
   "type": "module",
   "scripts": {
     "build": "nuxt build",
-    "dev": "VERSION=bun-dev NODE_ENV=development nuxt dev",
+    "dev": "NODE_ENV=development nuxt dev",
     "generate": "nuxt generate",
     "preview": "nuxt preview",
     "postinstall": "nuxt prepare",
@@ -28,6 +28,7 @@
     "merkle-json": "^2.6.0",
     "moment": "^2.30.1",
     "nuxt": "^3.10.3",
+    "nuxt-oidc-auth": "^1.0.0-beta.5",
     "parse-md": "^3.0.3",
     "pinia": "^2.1.7",
     "qs": "^6.11.2",
diff --git a/dbrepo-ui/pages/container/index.vue b/dbrepo-ui/pages/container/index.vue
index 360ce1543fdf086d60d568ed066ccca1f7c04537..20fed36801c24184664744ccf8b06eecba358c33 100644
--- a/dbrepo-ui/pages/container/index.vue
+++ b/dbrepo-ui/pages/container/index.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <v-toolbar
       flat
       :title="$t('pages.container.title')">
@@ -11,6 +12,9 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import ContainerList from '@/components/container/ContainerList.vue'
 
@@ -25,19 +29,19 @@ export default {
       containers: []
     }
   },
-  computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-  },
   mounted () {
-    this.loading = true
-    const containerService = useContainerService();
-    containerService.findAll()
-      .then((containers) => {
-        this.containers = containers
-        this.loading = false
-      })
+    this.fetchContainers()
+  },
+  methods: {
+    fetchContainers () {
+      this.loading = true
+      const containerService = useContainerService();
+      containerService.findAll()
+        .then((containers) => {
+          this.containers = containers
+          this.loading = false
+        })
+    }
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue
index 6e1e35aabb3b2c150f532edf8c8fea5af610088c..025cc9c4c438523c876c346f6ccb219933a5362c 100644
--- a/dbrepo-ui/pages/database/[database_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/info.vue
@@ -1,26 +1,27 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="identifier || canViewInfo">
     <DatabaseToolbar />
     <v-window
       v-model="tab">
       <v-window-item value="1">
         <Summary
-          v-if="hasIdentifier"
+          v-if="identifier"
           :identifier="identifier" />
         <v-card
-          v-if="hasIdentifier"
+          v-if="identifier"
           variant="flat"
           rounded="0">
           <v-card-text>
             <Select
-              :identifiers="filteredIdentifiers"
+              :identifiers="identifiers"
               :identifier="identifier" />
           </v-card-text>
         </v-card>
         <v-divider
-          v-if="hasIdentifier" />
+          v-if="identifier" />
         <v-card
+          v-if="canViewInfo"
           :title="$t('pages.database.title')"
           variant="flat"
           rounded="0">
@@ -94,7 +95,7 @@
                 <div>
                   <UserBadge
                     :user="database.owner"
-                    :other-user="user" />
+                    :other-user="cacheUser" />
                 </div>
               </v-list-item>
               <v-list-item
@@ -104,7 +105,7 @@
                 <div>
                   <UserBadge
                     :user="database.contact"
-                    :other-user="user" />
+                    :other-user="cacheUser" />
                 </div>
               </v-list-item>
             </v-list>
@@ -163,13 +164,30 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&type=database&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { sizeToHumanLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -197,7 +215,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -206,7 +223,7 @@ export default {
       return 0
     },
     description () {
-      if (!this.hasIdentifier) {
+      if (!this.identifier) {
         return ''
       }
       return this.database.identifier.description
@@ -218,46 +235,25 @@ export default {
       return this.$config.public.database.image.height
     },
     publisher () {
-      if (!this.hasIdentifier) {
+      if (!this.identifier) {
         return ''
       }
       return this.database.identifier.publisher
     },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
-    roles () {
-      return this.userStore.getRoles
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    identifiers () {
-      if (!this.database) {
-        return []
-      }
-      return this.database.identifiers
+    access () {
+      return this.cacheStore.getAccess
     },
-    filteredIdentifiers () {
-      if (!this.identifiers) {
+    identifiers () {
+      if (!this.database || !this.database.identifiers) {
         return []
       }
-      if (!this.user) {
-        return this.identifiers.filter(i => i.status === 'published')
-      }
-      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id)
-    },
-    identifier () {
-      if (this.pid) {
-        const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
-      }
-      return this.filteredIdentifiers[0]
-    },
-    access () {
-      return this.userStore.getAccess
+      return this.database.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
     pid () {
       return this.$route.query.pid
@@ -300,9 +296,6 @@ export default {
       const databaseService = useDatabaseService()
       return databaseService.databaseToOwner(this.database)
     },
-    hasIdentifier () {
-      return this.identifier
-    },
     accessDescription () {
       if (!this.access) {
         return
@@ -335,12 +328,19 @@ export default {
       }
       return this.database.preview_image
     },
-    canViewSchema () {
-      if (this.error) {
+    canViewInfo () {
+      if (!this.database) {
         return false
       }
-      return this.database
-    }
+      if (this.database.is_public || this.database.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
+    },
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
index a57b439b216ae4743fd4bda292dc53e5f7e05a69..505a7651232b071a03dd2b7ea481ff306e8dc3b4 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist
       type="database"
       :database="database" />
@@ -9,9 +9,8 @@
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -39,34 +38,53 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    database () {
-      return this.cacheStore.getDatabase
+    access () {
+      return this.cacheStore.getAccess
+    },
+    identifier () {
+      if (!this.database) {
+        return false
+      }
+      const filter = this.database.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    canPersistIdentifier () {
+      if (!this.database || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
index df675d262e8e116b0c4252d74fe6878681388acb..b66e8d706de8f4d87dd44baff8e7ded81aa7fffa 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier">
     <Persist
       type="database"
       :database="database" />
@@ -9,9 +9,8 @@
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -35,46 +34,40 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
-    hasIdentifier () {
-      if (this.database && 'identifier' in this.database && this.database.identifier) {
-        return 'id' in this.database.identifier
-      }
-      return false
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    access () {
+      return this.cacheStore.getAccess
     },
     isOwner () {
-      if (!this.database || !this.user) {
+      if (!this.database || !this.cacheUser) {
         return false
       }
-      return this.database.owner.username === this.user.username
+      return this.database.owner.id === this.cacheUser.uid
     },
-    canCreateIdentifier () {
-      if (!this.roles || this.hasIdentifier) {
+    canPersistIdentifier () {
+      if (!this.database || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier') && this.isOwner
-    },
-    canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.hasIdentifier && this.roles.includes('modify-identifier-metadata')
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue
index d0fb517daebc37d65c3d18f1faed9f631a0ecff0..8905ede1d2f88c8b2411f65655c4443827c23315 100644
--- a/dbrepo-ui/pages/database/[database_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/settings.vue
@@ -1,14 +1,13 @@
 <template>
   <div
-    v-if="canView">
+    v-if="canViewSettings">
     <DatabaseToolbar
       ref="toolbar" />
     <v-window
-      v-if="user"
       v-model="tab">
       <v-window-item>
         <v-card
-          v-if="isOwner && canModifyImage"
+          v-if="canModifyImage"
           variant="flat"
           rounded="0"
           :title="$t('pages.database.subpages.settings.title')"
@@ -89,7 +88,6 @@
         </v-card>
         <v-divider />
         <v-card
-          v-if="isOwner"
           variant="flat"
           rounded="0"
           :title="$t('pages.database.subpages.access.title')"
@@ -106,7 +104,7 @@
             </template>
             <template v-slot:item.action="{ item }">
               <v-btn
-                v-if="item && item.user && item.user.username !== user.username"
+                v-if="item && item.user && item.user.username !== cacheUser.username"
                 size="x-small"
                 variant="flat"
                 color="warning"
@@ -247,7 +245,6 @@
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import EditAccess from '@/components/dialogs/EditAccess.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -323,7 +320,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -335,34 +331,22 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    token () {
-      return this.userStore.getToken
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     uploadProgress () {
       return this.cacheStore.getUploadProgress
     },
-    isOwner () {
-      if (!this.database || !this.user) {
-        return false
-      }
-      if (this.database.owner.id === null || this.user.id === null) {
-        return false
-      }
-      return this.database.owner.id === this.user.id
-    },
     isSameOwner () {
-      if (!this.modifyOwner || !this.user) {
+      if (!this.modifyOwner || !this.cacheUser) {
         return false
       }
-      return this.modifyOwner.id === this.user.id
+      return this.modifyOwner.id === this.cacheUser.uid
     },
     isSameVisibility () {
       if (!this.modifyVisibility || !this.database) {
@@ -371,46 +355,47 @@ export default {
       return this.modifyVisibility.is_public === this.database.is_public && this.modifyVisibility.is_schema_public === this.database.is_schema_public
     },
     canModifyVisibility () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('modify-database-visibility')
     },
     canModifyOwnership () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('modify-database-owner')
     },
     canUpdateScheme () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('find-database')
     },
     canModifyAccess () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('update-database-access')
     },
     canCreateAccess () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('create-database-access')
     },
     canModifyImage () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('modify-database-image')
     },
-    canView () {
-      if (this.error) {
+    canViewSettings () {
+      if (!this.database || !this.cacheUser || !this.access) {
         return false
       }
-      return this.database
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid
     },
     previewImage () {
       if (this.file) {
@@ -477,7 +462,7 @@ export default {
         .then((database) => {
           const toast = useToastInstance()
           toast.success(this.$t('success.database.visibility'))
-          this.cacheStore.setDatabase(database)
+          this.cacheStore.reloadDatabase()
         })
         .catch(() => {
           this.loading = false
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
index f96b6e41758eb2a6e25d6ea3425dfb3c2ea043b3..682fc59b98fa61b0b3fb15af227960050e5d94cb 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="canViewSubsetData">
     <SubsetToolbar />
     <v-toolbar
       color="secondary"
@@ -17,7 +18,7 @@
       </v-toolbar-title>
       <v-spacer />
       <v-btn
-        v-if="canDownload"
+        v-if="canViewSubsetData"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-download' : null"
         variant="flat"
         :loading="downloadLoading"
@@ -96,30 +97,31 @@ export default {
     subset () {
       return this.cacheStore.getSubset
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     executionUTC () {
       if (!this.subset) {
         return null
       }
       return formatTimestampUTCLabel(this.subset.created)
     },
-    canDownload () {
-      if (!this.result_visibility || !this.subset.id) {
-        return false
-      }
-      return this.subset.id
-    },
-    result_visibility () {
+    canViewSubsetData () {
       if (!this.database || !this.subset) {
         return false
       }
       if (this.database.is_public) {
         return true
       }
-      return this.subset.owner.username === this.username
-    },
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
+    }
   },
   mounted () {
-    this.loadResult()
+    this.loadSubset()
   },
   methods: {
     loadSubset () {
@@ -128,7 +130,9 @@ export default {
       queryService.findOne(this.$route.params.database_id, this.$route.params.subset_id)
         .then((subset) => {
           this.subset = subset
-          this.loadResult()
+          this.$refs.queryResults.reExecute(subset.id)
+          this.$refs.queryResults.reExecuteCount(subset.id)
+          this.loadingSubset = false
         })
         .catch(() => {
           this.loadingSubset = false
@@ -137,12 +141,6 @@ export default {
           this.loadingSubset = false
         })
     },
-    loadResult () {
-      if (this.subset) {
-        this.$refs.queryResults.reExecute(this.subset.id)
-        this.$refs.queryResults.reExecuteCount(this.subset.id)
-      }
-    },
     download () {
       this.downloadLoading = true
       const queryService = useQueryService()
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
index f067fbadb4a190aff0843e289281971997426772..db5d45b4610de195f2a16d213eea60674c8dcf86 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
@@ -1,36 +1,29 @@
 <template>
-  <div>
+  <div
+    v-if="identifier || canViewInfo">
     <SubsetToolbar />
     <v-card
       variant="flat"
       rounded="0">
       <Summary
-        v-if="hasIdentifier"
+        v-if="identifier"
         :identifier="identifier" />
       <v-card-text
-        v-if="hasIdentifier">
+        v-if="identifier">
         <Select
           :identifiers="identifiers"
           :identifier="identifier" />
       </v-card-text>
     </v-card>
     <v-divider
-      v-if="subset && identifier" />
+      v-if="canViewInfo && identifier" />
     <v-card
+      v-if="canViewInfo"
       variant="flat"
       rounded="0"
       :title="$t('pages.subset.title')">
       <v-card-text>
         <v-list
-          v-if="!subset"
-          lines="two"
-          dense>
-          <v-skeleton-loader
-            type="list-item-three-line"
-            width="50%" />
-        </v-list>
-        <v-list
-          v-else-if="subset"
           lines="two"
           dense>
           <v-list-item
@@ -50,7 +43,9 @@
             v-if="subset.creator"
             :title="$t('pages.subset.creator.title')"
             density="compact">
-            <UserBadge :user="subset.creator" :other-user="user" />
+            <UserBadge
+              :user="subset.creator"
+              :other-user="cacheUser" />
           </v-list-item>
           <v-list-item
             :title="$t('pages.subset.query.title')"
@@ -86,13 +81,30 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id, subset_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&qid=${subset_id}&type=subset&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import Summary from '@/components/identifier/Summary.vue'
 import SubsetToolbar from '@/components/subset/SubsetToolbar.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -134,7 +146,6 @@ export default {
       downloadLoading: false,
       error: false,
       promises: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -145,35 +156,33 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
-    access () {
-      return this.userStore.getAccess
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     subset () {
       return this.cacheStore.getSubset
     },
-    user () {
-      return this.userStore.getUser
-    },
     identifiers () {
-      if (!this.database || !this.database.subsets || this.database.subsets.length === 0) {
+      if (!this.database || !this.database.subsets) {
         return []
       }
-      return this.database.subsets.filter(s => s.query_id === Number(this.$route.params.subset_id))
-    },
-    hasIdentifier () {
-      return this.identifiers.length > 0
+      return this.database.subsets.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
-    identifier () {
-      if (this.pid) {
-        const filter = this.identifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
+    canViewInfo () {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_public || this.database.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
+        return false
       }
-      return this.identifiers[0]
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     title () {
-      if (!this.hasIdentifier) {
+      if (!this.identifier) {
         return null
       }
       const enTitle = this.identifier.titles.filter(t => t.language).filter(t => t.language === 'en')
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
index b15ecb3292520979e550f68c7c16ef873638b124..78878a0015f61ea3dadf38258b747b20fa8e94d9 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist
       type="subset"
       :database="database" />
@@ -9,9 +9,8 @@
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -47,34 +46,56 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    subset () {
+      return this.cacheStore.getSubset
     },
-    database () {
-      return this.cacheStore.getDatabase
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    identifier () {
+      if (!this.subset) {
+        return false
+      }
+      const filter = this.subset.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
+    },
+    canPersistIdentifier () {
+      if (!this.subset || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.subset.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
index 07be66bc73911c9bd7580991ef2c71c6d36de5bc..88209f50188e473e306a826674051de883e83b3f 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
@@ -1,18 +1,17 @@
 <template>
   <div
-    v-if="canPersistQuery">
+    v-if="canPersistIdentifier">
     <Persist
       type="subset"
       :database="database"
-      :query="query" />
+      :query="subset" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -21,8 +20,6 @@ export default {
   data () {
     return {
       loading: false,
-      loadingQuery: false,
-      query: null,
       isAuthorizationError: false,
       items: [
         {
@@ -47,51 +44,37 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
+    },
+    subset () {
+      return this.cacheStore.getSubset
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    canPersistQuery () {
-      if (this.loadingQuery || !this.query) {
+    canPersistIdentifier () {
+      if (!this.subset || !this.roles || !this.cacheUser || !this.access) {
+        return false
+      }
+      if (this.roles.includes('create-foreign-identifier')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
       const userService = useUserService()
-      return userService.hasReadAccess(this.access)
-    }
-  },
-  mounted () {
-    this.loadQuery()
-  },
-  methods: {
-    loadQuery () {
-      this.loadingQuery = true
-      return new Promise((resolve, reject) => {
-        const queryService = useQueryService()
-        queryService.findOne(this.$route.params.database_id, this.$route.params.subset_id)
-          .then((query) => {
-            this.query = query
-            resolve(query)
-          })
-          .catch((error) => {
-            if (error.response.status === 405) {
-              this.isAuthorizationError = true
-            }
-            reject(error)
-          })
-          .finally(() => {
-            this.loadingQuery = false
-          })
-      })
+      return userService.hasReadAccess(this.access) && this.subset.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
index 0fb591f9f8307018da13539491089c68c2a9ba16..c3d07bba1570ef6e116ff0bb5e18145104526175 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
@@ -7,7 +7,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import Builder from '@/components/subset/Builder.vue'
 import {useCacheStore} from '@/stores/cache.js'
 
@@ -36,28 +35,15 @@ export default {
           disabled: true
         }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+      return this.cacheStore.getAccess
     },
     canCreateSubset () {
       if (!this.database) {
@@ -66,7 +52,11 @@ export default {
       if (this.database.is_public) {
         return true
       }
-      return this.hasReadAccess
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
index 2f68604881a0e222dbd280a5c54ff375ca8c0825..d98a8ba2afc6f26466c50e31acfc10ed0f32acd3 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
@@ -39,11 +39,21 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canViewSchema () {
-      if (this.error) {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
         return false
       }
-      return this.database
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
index 2e76d4ebd4a62d0744813740d7c4b55e950d54ca..13ee3951c80fae3bb0a3f8391133b53aec57bf79 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
@@ -53,7 +53,6 @@
         class="ml-2 mr-2"
         @click.stop="pick" />
     </v-toolbar>
-    <TimeDrift />
     <v-card
       v-if="error"
       variant="flat">
@@ -81,6 +80,7 @@
         @close="pickVersion" />
     </v-dialog>
     <v-dialog
+      v-if="loggedIn"
       v-model="addTupleDialog"
       persistent
       max-width="640">
@@ -91,6 +91,7 @@
         @close="close" />
     </v-dialog>
     <v-dialog
+      v-if="loggedIn"
       v-model="editTupleDialog"
       persistent
       max-width="640">
@@ -104,12 +105,13 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import TableHistory from '@/components/table/TableHistory.vue'
-import TimeDrift from '@/components/TimeDrift.vue'
 import TableToolbar from '@/components/table/TableToolbar.vue'
 import { formatTimestamp } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import EditTuple from '@/components/dialogs/EditTuple.vue'
 import BlobDownload from '@/components/table/BlobDownload.vue'
@@ -121,12 +123,12 @@ export default {
     BlobDownload,
     EditTuple,
     TableHistory,
-    TableToolbar,
-    TimeDrift
+    TableToolbar
   },
   data () {
     return {
       loading: true,
+      error: false,
       loadingData: false,
       loadingCount: false,
       loadingDelete: false,
@@ -178,31 +180,24 @@ export default {
       ],
       headers: [],
       rows: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     table () {
       return this.cacheStore.getTable
     },
-    user () {
-      return this.userStore.getUser
+    roles () {
+      return this.cacheStore.getRoles
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     title () {
       return (this.version ? this.$t('toolbars.database.history') : this.$t('toolbars.database.current')) + ' ' + this.versionFormatted
@@ -228,15 +223,6 @@ export default {
       }
       return this.version.substring(0, 10) + 'T' + this.version.substring(11, 19) + 'Z'
     },
-    canModify () {
-      if (!this.user || !this.access || !this.table) {
-        return false
-      }
-      if (this.access.type === 'write_own' && this.table.owner.id === this.user.id) {
-        return true
-      }
-      return this.access.type === 'write_all'
-    },
     primaryKeyColumns () {
       if (!this.table) {
         return []
@@ -244,47 +230,45 @@ export default {
       return this.table.constraints.primary_key.map(pk => pk.column)
     },
     canViewTableData () {
-      if (this.error) {
-        return false
-      }
       if (!this.table) {
         return false
       }
       if (this.table.is_public) {
         return true
       }
-      if (!this.roles || !this.roles.includes('view-table-data')) {
+      if (!this.roles || !this.roles.includes('view-table-data') || !this.access) {
         return false
       }
-      return this.hasReadAccess
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     canAddTuple () {
       if (!this.roles) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data')
     },
     canSelectTuples () {
       if (!this.roles) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data')
     },
     canEditTuple () {
       if (!this.roles || this.selection === null || this.selection.length !== 1) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data')
     },
     canDeleteTuple () {
       if (!this.roles || this.selection === null || this.selection.length < 1) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('delete-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('delete-table-data')
     }
   },
   watch: {
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
index 4cf0057ea429438ca08282a63ac27f182f80baf0..efbcd6accf7d3d896769241a7de0d1325a30b3a4 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
@@ -30,7 +30,6 @@
 
 <script>
 import TableImport from '@/components/table/TableImport.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -69,19 +68,21 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    table () {
+      return this.cacheStore.getTable
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    table () {
-      return this.cacheStore.getTable
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    access () {
+      return this.cacheStore.getAccess
     },
     title () {
       if (!this.table) {
@@ -90,10 +91,11 @@ export default {
       return this.$t('pages.table.import.title') + ' ' + this.table.name
     },
     canInsertTableData () {
-      if (!this.roles) {
+      if (!this.table || !this.access || !this.cacheUser || !this.roles || !this.roles.includes('insert-table-data')) {
         return false
       }
-      return this.roles.includes('insert-table-data')
+      const userService = useUserService()
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
index 916c72b85052ce54c71d0bfa3cbe67708d606b0a..687358f0290177012dc89f36e23666d6dd6d48d0 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
@@ -1,15 +1,14 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="identifier || canViewInfo">
     <TableToolbar
       :selection="selection" />
     <v-card
+      v-if="identifier"
       variant="flat">
       <Summary
-        v-if="hasIdentifier"
         :identifier="identifier" />
-      <v-card-text
-        v-if="hasIdentifier">
+      <v-card-text>
         <Select
           :identifiers="identifiers"
           :identifier="identifier" />
@@ -18,6 +17,7 @@
     <v-divider
       v-if="identifier" />
     <v-card
+      v-if="canViewInfo"
       variant="flat"
       rounded="0"
       :title="$t('pages.table.title')">
@@ -64,7 +64,7 @@
             :title="$t('pages.table.owner.title')">
             <UserBadge
               :user="table.owner"
-              :other-user="user" />
+              :other-user="cacheUser" />
           </v-list-item>
         </v-list>
       </v-card-text>
@@ -118,12 +118,29 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id, table_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&tid=${table_id}&type=table&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
 import Select from '@/components/identifier/Select.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -165,7 +182,6 @@ export default {
       loading: false,
       exchange: null,
       queue: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -173,50 +189,47 @@ export default {
     pid () {
       return this.$route.query.pid
     },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     table () {
       return this.cacheStore.getTable
     },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     canRead () {
       if (this.database && this.database.is_public) {
         return true
       }
-      if (!this.user || !this.access) {
+      if (!this.access) {
         return false
       }
-      return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all'
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
-    canViewSchema () {
-      if (this.error) {
-        return false
-      }
+    canViewInfo () {
       if (!this.table) {
         return false
       }
-      if (this.table.is_schema_public || this.table.is_public) {
+      if (this.table.is_public || this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     canWrite () {
-      if (!this.table || !this.user || !this.access) {
-        return false
-      }
-      return (this.access.type === 'write_own' && this.table.owned_by === this.user.id) || this.access.type === 'write_all'
+      const userService = useUserService()
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser)
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasDescription () {
       return this.table && this.table.description
@@ -228,31 +241,10 @@ export default {
       return this.roles.includes('insert-table-data')
     },
     identifiers () {
-      if (!this.table || !this.table.identifiers || this.table.identifiers.length === 0) {
-        return []
-      }
-      return this.table.identifiers
-    },
-    filteredIdentifiers () {
-      if (!this.identifiers) {
+      if (!this.table || !this.table.identifiers) {
         return []
       }
-      if (!this.user) {
-        return this.identifiers.filter(i => i.status === 'published')
-      }
-      return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.user.id)
-    },
-    identifier () {
-      if (this.pid) {
-        const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
-      }
-      return this.filteredIdentifiers[0]
-    },
-    hasIdentifier () {
-      return this.identifier
+      return this.table.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
     brokerExtraInfo () {
       return this.$config.public.broker.extra
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
index 663b2a5550d7875e1da0c3ed86fab1f24f359350..e2d16e8db44efb0f558fa2c42e1225fc9e6b8355 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist type="table" :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
@@ -8,7 +8,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -45,34 +44,56 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    table () {
+      return this.cacheStore.getTable
     },
-    database () {
-      return this.cacheStore.getDatabase
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    access () {
+      return this.cacheStore.getAccess
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    identifier () {
+      if (!this.table) {
+        return false
+      }
+      const filter = this.table.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
+    },
+    canPersistIdentifier () {
+      if (!this.table || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
index 250fedaa5d4676dc6c304d3d71aa9b3a23b21ffc..6c26187fa23ff0669bad399b57e3ab48b15ec061 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canPersistTable">
+    v-if="canPersistIdentifier">
     <Persist
       type="table"
       :database="database"
@@ -13,7 +13,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -48,29 +47,37 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     table () {
       return this.cacheStore.getTable
     },
-    canPersistTable () {
-      if (!this.table) {
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    canPersistIdentifier () {
+      if (!this.table || !this.roles || !this.cacheUser || !this.access) {
+        return false
+      }
+      if (this.roles.includes('create-foreign-identifier')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
       const userService = useUserService()
-      return userService.hasReadAccess(this.access)
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
index 0c6a60e15b9c052656a61e9d71ec3fcd3d944cb2..ac48b40644823b9393b26608a0cfa5e56790d03a 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
@@ -120,9 +120,11 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -168,14 +170,10 @@ export default {
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
       dateColumns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -183,7 +181,13 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
     },
     hasReadAccess () {
       if (!this.access) {
@@ -191,29 +195,24 @@ export default {
       }
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     canViewSchema () {
-      if (this.error) {
-        return false
-      }
       if (!this.table) {
         return false
       }
       if (this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     primaryKeysColumns () {
       return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ')
     },
     canAssignSemanticInformation () {
-      if (!this.user) {
+      if (!this.cacheUser || !this.roles) {
         return false
       }
       if (this.roles.includes('modify-foreign-table-column-semantics')) {
@@ -222,7 +221,7 @@ export default {
       if (!this.access) {
         return false
       }
-      return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.username === this.user.username)
+      return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.id === this.cacheUser.uid)
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
index 3d718d57398324f1099ceff42b80d80a55cf18b5..0f0a8feab62a7fb065c3ecb6af6b63b83a9884be 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
@@ -3,7 +3,6 @@
     v-if="canUpdateTable">
     <TableToolbar />
     <v-window
-      v-if="user"
       v-model="tab">
       <v-window-item>
         <v-form
@@ -23,9 +22,6 @@
                   <v-textarea
                     v-model="modify.description"
                     rows="2"
-                    :rules="[
-                      v => !max(v, 180) || ($t('validation.max-length') + 180),
-                    ]"
                     clearable
                     counter="180"
                     persistent-counter
@@ -116,7 +112,6 @@
 
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import { max } from '@/utils'
 
@@ -127,7 +122,7 @@ export default {
   data () {
     return {
       tab: 0,
-      valid: false,
+      valid: true,
       loading: false,
       modify: {
         description: null,
@@ -175,14 +170,10 @@ export default {
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
       dateColumns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -190,47 +181,39 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     isChange () {
       if (!this.table) {
         return false
       }
-      if (this.table.is_public !== this.modify.is_public) {
+      if (this.table.is_public !== this.modify.is_public || this.table.is_schema_public !== this.modify.is_schema_public) {
         return true
       }
-      return this.table.is_schema_public !== this.modify.is_schema_public
+      return this.table.description !== this.modify.description
     },
     canUpdateTable () {
-      if (!this.roles || !this.user || !this.table) {
-        return false
-      }
-      return this.roles.includes('update-table') && this.table.owner.id === this.user.id
-    },
-    canModifyVisibility () {
-      if (!this.roles || !this.user || !this.table) {
+      if (!this.cacheUser || !this.table || !this.access || !this.roles || !this.roles.includes('update-table')) {
         return false
       }
-      return this.roles.includes('update-table') && this.table.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
     },
     canDropTable () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
       if (this.roles.includes('delete-foreign-table')) {
         return true
       }
       const tableService = useTableService()
-      return tableService.isOwner(this.table, this.user) && this.roles.includes('delete-table') && this.table.identifiers.length === 0
+      return tableService.isOwner(this.table, this.cacheUser) && this.roles.includes('delete-table') && this.table.identifiers.length === 0
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
index df74cc6e7046e90f6e5e9844769a2e1e8f45e372..24aed7f2ffc6b77edfae4a90e1c4dc7607f97955 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
@@ -92,9 +92,6 @@
                       <v-textarea
                         v-model="tableCreate.description"
                         rows="2"
-                        :rules="[
-                          v => (!!v || v.length <= 180) || ($t('validation.max-length') + 180),
-                        ]"
                         clearable
                         counter="180"
                         persistent-counter
@@ -219,10 +216,9 @@
   </div>
 </template>
 
-<script>
+  <script>
 import TableSchema from '@/components/table/TableSchema.vue'
 import { notEmpty } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -304,7 +300,6 @@ export default {
       loading: false,
       url: null,
       columns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -316,15 +311,12 @@ export default {
     this.tableCreate.is_schema_public = this.database.is_schema_public
   },
   computed: {
-    user() {
-      return this.userStore.getUser
-    },
-    roles() {
-      return this.userStore.getRoles
-    },
     database() {
       return this.cacheStore.getDatabase
     },
+    roles () {
+      return this.cacheStore.getRoles
+    },
     generatedTableName() {
       if (!this.tableCreate.name) {
         return null
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 c900ba31aa104dcc1ce5e3250dd0bb5a2b92f6fa..804ae03c15072719f7612fd46eeca80d45b1a2b8 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
@@ -70,9 +70,6 @@
                     <v-textarea
                       v-model="tableCreate.description"
                       rows="2"
-                      :rules="[
-                        v => (!v || v.length <= 180) || $t('validation.max-length') + 180
-                      ]"
                       clearable
                       counter="180"
                       persistent-counter
@@ -188,7 +185,6 @@
 <script>
 import TableSchema from '@/components/table/TableSchema.vue'
 import { notEmpty } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -247,7 +243,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -259,15 +254,12 @@ export default {
       const tableService = useTableService()
       return tableService.tableNameToInternalName(this.tableCreate.name)
     },
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
+    roles () {
+      return this.cacheStore.getRoles
+    },
     canCreateTable () {
       if (!this.roles) {
         return false
diff --git a/dbrepo-ui/pages/database/[database_id]/table/index.vue b/dbrepo-ui/pages/database/[database_id]/table/index.vue
index ae3e3c13f1b173b62514e1ee8887fd648e3f65a1..c2a2b76206918a0882c7e041aa3f38fb19ccfe12 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/index.vue
@@ -48,11 +48,18 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canViewSchema () {
-      if (this.error) {
+      if (!this.database) {
         return false
       }
-      return this.database
+      if (this.database.is_schema_public) {
+        return true
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
index 54c54dad00d4764383c8d38e979870391680d563..f732661f369710b4637f01952f5fab930e9e4812 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
@@ -22,7 +22,6 @@
         :loading="loadingData"
         @click="reload" />
     </v-toolbar>
-    <TimeDrift />
     <v-card tile>
       <QueryResults
         id="query-results"
@@ -35,14 +34,11 @@
 </template>
 
 <script>
-import TimeDrift from '@/components/TimeDrift.vue'
 import QueryResults from '@/components/subset/Results.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
-    QueryResults,
-    TimeDrift
+    QueryResults
   },
   data () {
     return {
@@ -70,14 +66,10 @@ export default {
           disabled: true
         }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -85,13 +77,10 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' ||  this.access.type === 'write_own' ||  this.access.type === 'write_all'
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     canReadData () {
       if (!this.view) {
@@ -100,10 +89,11 @@ export default {
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.view.owner.id === this.user.id || this.hasReadAccess
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
   },
   mounted () {
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
index c9865a1b4abbefd3bd07361b7c6a5a5ff86b0834..3c0c40e33ce7546e351ea3252a051a0ebb56049e 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
@@ -1,25 +1,25 @@
 <template>
   <div
-    v-if="canViewView">
+    v-if="identifier || canViewInfo">
     <ViewToolbar />
     <v-window
       v-model="tab">
-      <v-window-item
-        v-if="view">
+      <v-window-item>
         <v-card variant="flat">
           <Summary
-            v-if="hasIdentifier"
+            v-if="identifier"
             :identifier="identifier" />
           <v-card-text
-            v-if="hasIdentifier">
+            v-if="identifier">
             <Select
               :identifiers="identifiers"
               :identifier="identifier" />
           </v-card-text>
         </v-card>
         <v-divider
-          v-if="hasIdentifier" />
+          v-if="identifier" />
         <v-card
+          v-if="canViewInfo"
           :title="$t('pages.view.title')"
           variant="flat">
           <v-card-text>
@@ -39,7 +39,7 @@
                 <UserBadge
                   v-if="view"
                   :user="view.owner"
-                  :other-user="user" />
+                  :other-user="cacheUser" />
                 <v-skeleton-loader
                   v-else
                   type="subtitle"
@@ -59,13 +59,30 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id, view_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&vid=${view_id}&type=view&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -103,55 +120,30 @@ export default {
         }
       ],
       error: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     view () {
       return this.cacheStore.getView
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    roles () {
+      return this.cacheStore.getRoles
     },
-    identifiers () {
-      if (!this.view) {
-        return []
-      }
-      return this.view.identifiers
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    filteredIdentifiers () {
-      if (!this.identifiers) {
+    identifiers () {
+      if (!this.view || !this.view.identifiers) {
         return []
       }
-      if (!this.user) {
-        return this.identifiers.filter(i => i.status === 'published')
-      }
-      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id)
-    },
-    identifier () {
-      if (this.pid) {
-        const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
-      }
-      return this.filteredIdentifiers[0]
+      return this.view.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
     views () {
       if (!this.database) {
@@ -162,9 +154,6 @@ export default {
     pid () {
       return this.$route.query.pid
     },
-    hasIdentifier () {
-      return this.identifier
-    },
     creator () {
       if (!this.view) {
         return null
@@ -172,17 +161,18 @@ export default {
       const userService = useUserService()
       return userService.userToFullName(this.view.creator)
     },
-    canViewView () {
+    canViewInfo () {
       if (!this.view) {
         return false
       }
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   },
   methods: {
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
index 8c1f24c2a166150bd1dc3903dfa984c435815f9b..540bbbdb5e454c725c6d5b9dc6a1da6498e5f8bc 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist
       type="view"
       :database="database" />
@@ -10,7 +10,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -47,34 +46,56 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    view () {
+      return this.cacheStore.getView
     },
-    database () {
-      return this.cacheStore.getDatabase
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    identifier () {
+      if (!this.view) {
+        return false
+      }
+      const filter = this.view.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
+    },
+    canPersistIdentifier () {
+      if (!this.view || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
index b76d076645e05ef7123215c578d20b489924d523..ed8067d21327f2e0a069733fb9873b7912a5a32e 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canPersistView">
+    v-if="canPersistIdentifier">
     <Persist
       type="view"
       :database="database"
@@ -11,7 +11,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -45,32 +44,37 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
     view () {
-      if (!this.database) {
-        return null
-      }
-      return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0]
+      return this.cacheStore.getView
     },
-    access () {
-      return this.userStore.getAccess
+    roles () {
+      return this.cacheStore.getRoles
     },
-    canPersistView () {
-      if (!this.view) {
+    canPersistIdentifier () {
+      if (!this.view || !this.roles || !this.cacheUser || !this.access) {
+        return false
+      }
+      if (this.roles.includes('create-foreign-identifier')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
       const userService = useUserService()
-      return userService.hasReadAccess(this.access)
+      return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
index 477654f656c9dbc5361315d323b8cc638add6ca9..5b35faf3a5250c712a6e9b7f442a6e779863b42c 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
@@ -53,7 +53,6 @@
 
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -95,14 +94,10 @@ export default {
         { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') },
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -110,13 +105,13 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     canViewSchema () {
       if (!this.view) {
@@ -125,13 +120,11 @@ export default {
       if (this.view.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
-    },
-    roles () {
-      return this.userStore.getRoles
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
index 18d73d05768d1a45b36eed9a58ea7841235554b3..d027a4347b5300025f83d23adba52d78278a443f 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
@@ -92,7 +92,6 @@
 
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -148,14 +147,10 @@ export default {
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
       dateColumns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -163,16 +158,13 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
-    },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     isChange () {
       if (!this.view) {
@@ -184,22 +176,23 @@ export default {
       return this.view.is_schema_public !== this.modify.is_schema_public
     },
     canUpdateVisibility () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.cacheUser || !this.view) {
         return false
       }
-      return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.user.id
+      return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.cacheUser.uid
     },
     canDeleteView () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.cacheUser || !this.view) {
         return false
       }
-      return this.roles.includes('delete-database-view') && this.view.owner.id === this.user.id
+      return this.roles.includes('delete-database-view') && this.view.owner.id === this.cacheUser.uid
     },
     canViewSettings () {
-      if (!this.user || !this.view) {
+      if (!this.view || !this.access || !this.cacheUser) {
         return false
       }
-      return this.view.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/view/create.vue b/dbrepo-ui/pages/database/[database_id]/view/create.vue
index 47b56cfbad81968d056d028cc48758d250efc612..a834bdb5c90340d247dbb3df880acbec8dc4a08f 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue
@@ -8,7 +8,7 @@
 
 <script>
 import Builder from '@/components/subset/Builder.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -35,21 +35,22 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    access () {
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     canCreateView () {
-      if (!this.roles) {
+      if (!this.roles || !this.roles.includes('create-database-view')) {
         return false
       }
-      return this.roles.includes('create-database-view')
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/index.vue b/dbrepo-ui/pages/database/[database_id]/view/index.vue
index 64f777dce3f905f19d2ff8f16e5e4b3de80fd277..b2a2c17a1afe0553777e21e593b8865bfb63efc9 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/index.vue
@@ -48,11 +48,18 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canViewSchema () {
-      if (this.error) {
+      if (!this.database) {
         return false
       }
-      return this.database
+      if (this.database.is_schema_public) {
+        return true
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/index.vue b/dbrepo-ui/pages/index.vue
index 1c30c25e5c7e9edfd52861ca568c492ce39f13a7..9e5e20186dcdd58ab66662b5aca827e2682df121 100644
--- a/dbrepo-ui/pages/index.vue
+++ b/dbrepo-ui/pages/index.vue
@@ -30,7 +30,7 @@
 <script>
 import DatabaseList from '@/components/database/DatabaseList.vue'
 import DatabaseCreate from '@/components/database/DatabaseCreate.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -42,12 +42,12 @@ export default {
       loading: true,
       dialog: null,
       databases: [],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     canCreateDatabase () {
       if (!this.roles) {
@@ -57,17 +57,20 @@ export default {
     }
   },
   mounted () {
-    this.loading = true
-    const databaseService = useDatabaseService();
-    databaseService.findAll()
-      .then((databases) => {
-        this.databases = databases
-        this.loading = false
-      })
+    this.fetchDatabases()
   },
   methods: {
     closed () {
       this.dialog = false
+    },
+    fetchDatabases () {
+      this.loading = true
+      const databaseService = useDatabaseService()
+      databaseService.findAll()
+        .then((databases) => {
+          this.databases = databases
+          this.loading = false
+        })
     }
   }
 }
diff --git a/dbrepo-ui/pages/login.vue b/dbrepo-ui/pages/login.vue
deleted file mode 100644
index 532a221c4823cfd8be39fd53e94c34426311260a..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/login.vue
+++ /dev/null
@@ -1,160 +0,0 @@
-<template>
-  <div>
-    <v-toolbar
-      v-if="!user"
-      variant="flat"
-      :title="$t('pages.login.name')">
-    </v-toolbar>
-    <v-card
-      rounded="0"
-      variant="flat">
-      <v-card-text>
-        <v-form
-          v-if="!user"
-          ref="form"
-          v-model="valid"
-          @submit.prevent="submit">
-          <v-row
-            dense>
-            <v-col
-              md="8">
-              <v-text-field
-                v-model="username"
-                autocomplete="off"
-                autofocus
-                required
-                name="username"
-                persistent-hint
-                :rules="[v => !!v || $t('validation.required')]"
-                :label="$t('pages.login.username.label')"
-                :hint="$t('pages.login.username.hint')"/>
-            </v-col>
-          </v-row>
-          <v-row
-            dense>
-            <v-col
-              md="8">
-              <v-text-field
-                v-model="password"
-                autocomplete="off"
-                type="password"
-                required
-                name="password"
-                persistent-hint
-                :rules="[v => !!v || $t('validation.required')]"
-                :label="$t('pages.login.password.label')"
-                :hint="$t('pages.login.password.hint')"/>
-            </v-col>
-          </v-row>
-          <v-row>
-            <v-col
-              md="8">
-              <v-btn
-                id="login"
-                class="mb-2"
-                :disabled="!valid"
-                color="primary"
-                variant="flat"
-                type="submit"
-                name="submit"
-                :loading="loading"
-                :text="$t('pages.login.submit.label')"
-                @click="login"/>
-            </v-col>
-          </v-row>
-        </v-form>
-      </v-card-text>
-      <v-card-actions>
-        <v-spacer/>
-        <v-btn
-          v-for="(link, i) in loginLinks"
-          :key="`li-${i}`"
-          variant="plain"
-          size="small"
-          :text="link.text"
-          :href="link.href"/>
-      </v-card-actions>
-    </v-card>
-  </div>
-</template>
-
-<script>
-import {useUserStore} from '@/stores/user.js'
-
-export default {
-  data() {
-    return {
-      loading: false,
-      valid: false,
-      username: null,
-      password: null,
-      userStore: useUserStore()
-    }
-  },
-  computed: {
-    user() {
-      return this.userStore.getUser
-    },
-    loginLinks() {
-      if (!this.$config.public.links) {
-        return []
-      }
-      return Object.keys(this.$config.public.links).map(key => {
-        return this.$config.public.links[key]
-      })
-    }
-  },
-  methods: {
-    submit() {
-      this.$refs.form.validate()
-    },
-    login() {
-      this.loading = true
-      const userService = useUserService()
-      userService.obtainToken(this.username, this.password)
-        .then((data) => {
-          const userId = userService.tokenToUserId(data.access_token)
-          userService.findOne(userId)
-            .then((user) => {
-              const toast = useToastInstance()
-              toast.success(this.$t('success.user.login', { username : user.username }))
-              switch (user.attributes.theme) {
-                case 'dark':
-                  this.$vuetify.theme.global.name = 'tuwThemeDark'
-                  break
-                case 'light':
-                  this.$vuetify.theme.global.name = 'tuwThemeLight'
-                  break
-                case 'light-contrast':
-                  this.$vuetify.theme.global.name = 'tuwThemeLightContrast'
-                  break
-                case 'dark-contrast':
-                  this.$vuetify.theme.global.name = 'tuwThemeDarkContrast'
-                  break
-              }
-              this.userStore.setUser(user)
-              this.$router.push('/database')
-            })
-            .catch(({code}) => {
-              const toast = useToastInstance()
-              if (typeof code !== 'string') {
-                return
-              }
-              toast.error(this.$t(code))
-            })
-        })
-        .catch(({code}) => {
-          this.loading = false
-          const toast = useToastInstance()
-          if (typeof code !== 'string') {
-            return
-          }
-          toast.error(this.$t(code))
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue
index 15475b212bc724e0e55d9f0765461990e574618e..507f81b731407a3059e61f7956368d25481de9a0 100644
--- a/dbrepo-ui/pages/search.vue
+++ b/dbrepo-ui/pages/search.vue
@@ -65,7 +65,6 @@
 
 <script>
 import AdvancedSearch from '@/components/search/AdvancedSearch.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -75,14 +74,10 @@ export default {
     return {
       results: [],
       type: 'database',
-      loading: false,
-      userStore: useUserStore()
+      loading: false
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     q () {
       if (!this.$route.query || !this.$route.query.q) {
         return null
@@ -92,12 +87,6 @@ export default {
     header () {
       return `${this.results.length} ${this.results.length !== 1 ? this.$t('toolbars.search.results') : this.$t('toolbars.search.result')}`
     },
-    canCreateDatabase () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('create-database')
-    },
     isDatabaseSearch () {
       return this.type === 'database'
     }
diff --git a/dbrepo-ui/pages/semantic/index.vue b/dbrepo-ui/pages/semantic/index.vue
deleted file mode 100644
index db555b4c0d4778401e6988015b1064cc8bd0c82e..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/semantic/index.vue
+++ /dev/null
@@ -1,194 +0,0 @@
-<template>
-  <div v-if="canListOntologies">
-    <v-toolbar flat>
-      <v-toolbar-title>
-        {{ $t('pages.semantics.title') }}
-      </v-toolbar-title>
-      <v-spacer />
-      <v-btn
-        v-if="canListOntologies"
-        to="/semantic/ontology"
-        variant="flat"
-        :text="ontologies.length + ' ' + $t('toolbars.semantic.ontologies.text')"
-        color="secondary" />
-      <template v-slot:extension>
-        <v-tabs
-          v-model="tab"
-          color="primary">
-          <v-tab>
-            {{ $t('toolbars.semantic.ontologies.concepts') }}
-          </v-tab>
-          <v-tab>
-            {{ $t('toolbars.semantic.ontologies.units') }}
-          </v-tab>
-        </v-tabs>
-      </template>
-    </v-toolbar>
-    <v-card flat>
-      <v-card-text>
-        <v-data-table
-          :headers="headers"
-          :items="rows"
-          :options.sync="options"
-          :server-items-length="total"
-          :footer-props="footerProps"
-          :items-per-page-options="footerProps.itemsPerPageOptions">
-          <template v-slot:item.uri="{ item }">
-            <a :href="item.uri"
-               target="_blank">
-              {{ item.uri }}
-            </a>
-          </template>
-          <template v-slot:item.action="{ item }">
-            <v-btn
-              small
-              :disabled="disabled(item)"
-              :text="$t('pages.semantics.usages.text')"
-              @click="view(item)" />
-          </template>
-        </v-data-table>
-      </v-card-text>
-    </v-card>
-    <v-dialog
-      v-model="viewSemanticEntityDialog"
-      max-width="640">
-      <ViewSemanticEntity
-        :mode="mode"
-        :entity="entity"
-        @close="close" />
-    </v-dialog>
-    <v-breadcrumbs
-      :items="items"
-      class="pa-0 mt-2" />
-  </div>
-</template>
-
-<script>
-import ViewSemanticEntity from '@/components/dialogs/ViewSemanticEntity.vue'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  components: {
-    ViewSemanticEntity
-  },
-  data () {
-    return {
-      loadingConcepts: false,
-      loadingUnits: false,
-      entity: null,
-      viewSemanticEntityDialog: false,
-      headers: [
-        { text: 'URI', value: 'uri' },
-        { text: 'Name', value: 'name' },
-        { text: 'Description', value: 'description' },
-        { text: 'Usages', value: 'usages' },
-        { text: null, value: 'action' }
-      ],
-      options: {
-        page: 1,
-        itemsPerPage: 10
-      },
-      total: -1,
-      footerProps: {
-        itemsPerPageOptions: [10, 25, 50, 100]
-      },
-      tab: 0,
-      tabs: [
-        'concepts', 'units'
-      ],
-      concepts: [],
-      units: [],
-      createOntologyDialog: false,
-      items: [
-        {
-          title: `${this.$t('navigation.semantics')}`,
-          to: '/semantic'
-        }
-      ],
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    },
-    rows () {
-      return this.tab === 0 ? this.concepts : this.units
-    },
-    mode () {
-      return this.tab === 0 ? 'concept' : 'unit'
-    },
-    canListOntologies () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-ontologies')
-    }
-  },
-  mounted () {
-    this.loadUnits()
-    this.loadConcepts()
-  },
-  methods: {
-    loadConcepts () {
-      this.loadingConcepts = true
-      const conceptService = useConceptService()
-      conceptService.findAll()
-        .then((concepts) => {
-          concepts = concepts.map((column) => {
-            column.usages = column.columns.length
-            return column
-          })
-          this.concepts = concepts
-        })
-        .catch(() => {
-          this.loadingConcepts = false
-        })
-        .finally(() => {
-          this.loadingConcepts = false
-        })
-    },
-    loadUnits () {
-      this.loadingUnits = true
-      const unitService = useUnitService()
-      unitService.findAll()
-        .then((units) => {
-          units = units.map((unit) => {
-            unit.usages = unit.columns.length
-            return unit
-          })
-          this.units = units
-        })
-        .catch(() => {
-          this.loadingUnits = false
-        })
-        .finally(() => {
-          this.loadingUnits = false
-        })
-    },
-    disabled (item) {
-      return !item.usages || this.usages === 0
-    },
-    view (entity) {
-      this.entity = entity
-      this.viewSemanticEntityDialog = true
-    },
-    close (event) {
-      if (this.mode === 'unit') {
-        this.loadUnits()
-      } else if (this.mode === 'concept') {
-        this.loadConcepts()
-      }
-      this.viewSemanticEntityDialog = false
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
deleted file mode 100644
index 14749460c931c70c8430a28e51a7aa3c13d26ed1..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
+++ /dev/null
@@ -1,273 +0,0 @@
-<template>
-  <div
-    v-if="canListOntologies">
-    <v-toolbar flat>
-      <v-toolbar-title>
-        <v-btn
-          id="back-btn"
-          plain
-          class="mr-2"
-          to="/semantic/ontology">
-          <v-icon left>mdi-arrow-left</v-icon>
-        </v-btn>
-      </v-toolbar-title>
-      <v-toolbar-title>
-        <v-skeleton-loader
-          v-if="loading"
-          type="text"
-          class="skeleton-small" />
-        <span v-if="!loading">
-          Ontology
-          <a
-            v-if="ontology"
-            :href="ontology.uri"
-            target="_blank">
-            {{ ontology.uri }}
-          </a>
-        </span>
-      </v-toolbar-title>
-      <v-spacer />
-      <v-toolbar-title>
-        <v-btn
-          v-if="canDeleteOntology"
-          :loading="loadingDelete"
-          color="error"
-          @click="deleteOntology">
-          Delete Ontology
-        </v-btn>
-      </v-toolbar-title>
-    </v-toolbar>
-    <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit">
-      <v-card v-if="ontology" variant="flat">
-        <v-card-text>
-          <v-row dense>
-            <v-col cols="6">
-              <v-text-field
-                id="prefix"
-                v-model="ontologyChangeDto.prefix"
-                name="prefix"
-                label="Prefix *"
-                hint="Only lowercase alphanumeric letters, max. 8"
-                autofocus
-                :rules="[
-                  v => notEmpty(v) || $t('validation.required'),
-                  v => validPrefix(v) || $t('validation.prefix.pattern'),
-                  v => validPrefixLength(v,1,8) || $t('validation.prefix.length'),
-                  v => validPrefixNotExists(v) || $t('validation.prefix.exists')
-                ]"
-                required />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col cols="6">
-              <v-text-field
-                id="uri"
-                v-model="ontologyChangeDto.uri"
-                name="uri"
-                label="URI *"
-                :rules="[
-                  v => notEmpty(v) || $t('validation.required'),
-                  v => validUri(v) || $t('validation.uri.pattern'),
-                  v => validUriNotExists(v) || $t('validation.uri.exists')
-                ]"
-                required />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col cols="6">
-              <v-text-field
-                id="sparql-endpoint"
-                v-model="ontologyChangeDto.sparql_endpoint"
-                name="sparql-endpoint"
-                label="SPARQL Endpoint"
-                :rules="[
-                  v => validUriOptional(v) || $t('validation.uri.pattern')
-                ]" />
-            </v-col>
-          </v-row>
-        </v-card-text>
-        <v-card-actions>
-          <v-btn
-            id="createDB"
-            class="mb-2 ml-2"
-            :disabled="!valid || loading"
-            color="primary"
-            type="submit"
-            :loading="loading"
-            @click="save">
-            Update
-          </v-btn>
-        </v-card-actions>
-      </v-card>
-    </v-form>
-    <v-breadcrumbs :items="items" class="pa-0 mt-2" />
-  </div>
-</template>
-
-<script>
-import { notEmpty } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  data () {
-    return {
-      loading: false,
-      loadingDelete: false,
-      ontology: null,
-      ontologyChangeDto: {
-        uri: null,
-        prefix: null,
-        sparql_endpoint: null
-      },
-      valid: false,
-      createOntologyDialog: false,
-      items: [
-        { text: `${this.$t('layout.semantics')}`, to: '/semantic', activeClass: '' },
-        { text: `${this.$t('layout.ontologies')}`, to: '/semantic/ontology', activeClass: '' },
-        { text: `${this.$route.params.ontology_id}`, to: `/semantic/ontology/${this.$route.params.ontology_id}`, activeClass: '' }
-      ],
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    },
-    canListOntologies () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-ontologies')
-    },
-    canDeleteOntology () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('delete-ontology')
-    }
-  },
-  mounted () {
-    this.loadOntology()
-  },
-  methods: {
-    loadOntology () {
-      this.loading = true
-      const ontologyService = useOntologyService()
-      ontologyService.findOne(this.$route.params.ontology_id)
-        .then((ontology) => {
-          this.ontology = ontology
-          this.ontologyChangeDto = Object.assign({}, ontology)
-        })
-        .catch(() => {
-          this.loading = false
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    },
-    deleteOntology () {
-      this.loadingDelete = true
-      const ontologyService = useOntologyService()
-      ontologyService.remove(this.$route.params.ontology_id)
-        .then(async () => {
-          // await this.$store.dispatch('reloadOntologies')
-          await this.$router.push('/semantic/ontology')
-        })
-        .catch(() => {
-          this.loadingDelete = false
-        })
-        .finally(() => {
-          this.loadingDelete = false
-        })
-    },
-    save () {
-      this.loading = true
-      const payload = {
-        uri: this.ontologyChangeDto.uri,
-        prefix: this.ontologyChangeDto.prefix,
-        sparql_endpoint: this.ontologyChangeDto.sparql_endpoint
-      }
-      const ontologyService = useOntologyService()
-      ontologyService.update(this.$route.params.ontology_id, payload)
-        .then(() => {
-          this.loadOntology()
-          // this.$store.dispatch('reloadOntologies')
-          const toast = useToastInstance()
-          toast.success('Successfully update ontology!')
-        })
-        .catch(() => {
-          this.loading = false
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    },
-    validPrefix (str) {
-      if (!str) {
-        return false
-      }
-      return str.match(/[a-z0-9]+/g)
-    },
-    validPrefixLength (str, min, max) {
-      if (!str) {
-        return false
-      }
-      return str.length > min && str.length <= max
-    },
-    validPrefixNotExists (str) {
-      const ontologies = this.ontologies.filter(o => o.prefix === str)
-      if (ontologies && ontologies.length !== 0) {
-        /* same prefix is fine for the same ontology, but not for others */
-        return ontologies[0].id === this.ontology.id
-      }
-      return !this.ontologies.map(o => o.prefix).includes(str)
-    },
-    validUriNotExists (str) {
-      const ontologies = this.ontologies.filter(o => o.uri === str)
-      if (ontologies && ontologies.length !== 0) {
-        /* same uri is fine for the same ontology, but not for others */
-        return ontologies[0].id === this.ontology.id
-      }
-      return !this.ontologies.map(o => o.uri).includes(str)
-    },
-    validUriOptional (str) {
-      if (!str) {
-        return true
-      }
-      return this.validUri(str)
-    },
-    validUri (str) {
-      if (!str) {
-        return false
-      }
-      return str.match(/^https?:\/\//g)
-    },
-    close (event) {
-      if (event.success) {
-        // this.$store.dispatch('reloadOntologies')
-      }
-      this.createOntologyDialog = false
-    },
-    submit () {
-      this.$refs.form.validate()
-    },
-    notEmpty
-  }
-}
-</script>
-<style>
-.skeleton-medium > div {
-  width: 200px !important;
-}
-.skeleton-xsmall > div {
-  width: 50px !important;
-}
-</style>
diff --git a/dbrepo-ui/pages/semantic/ontology/index.vue b/dbrepo-ui/pages/semantic/ontology/index.vue
deleted file mode 100644
index 36898d90739c2d219e9f9987c02527e2409a676f..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/semantic/ontology/index.vue
+++ /dev/null
@@ -1,96 +0,0 @@
-<template>
-  <div v-if="canListOntologies">
-    <v-toolbar flat>
-      <v-btn
-        variant="plain"
-        size="small"
-        icon="mdi-arrow-left"
-        to="/semantic" />
-      <v-toolbar-title>
-        {{ ontologies.length + ' ' + $t('toolbars.semantic.ontologies.title') }}
-      </v-toolbar-title>
-      <v-spacer />
-      <v-btn
-        v-if="canCreateOntology"
-        color="secondary"
-        variant="flat"
-        name="create-ontology"
-        prepend-icon="mdi-plus"
-        :text="$t('toolbars.semantic.ontology.text')"
-        @click.stop="createOntologyDialog = true" />
-    </v-toolbar>
-    <OntologiesList />
-    <v-dialog
-      v-model="createOntologyDialog"
-      persistent
-      max-width="640">
-      <CreateOntology ref="ont" @close="close" />
-    </v-dialog>
-    <v-breadcrumbs :items="items" class="pa-0 mt-2" />
-  </div>
-</template>
-
-<script>
-import OntologiesList from '@/components/OntologiesList.vue'
-import CreateOntology from '@/components/dialogs/CreateOntology.vue'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  components: {
-    OntologiesList,
-    CreateOntology
-  },
-  data () {
-    return {
-      createOntologyDialog: false,
-      items: [
-        {
-          title: `${this.$t('navigation.semantics')}`,
-          to: '/semantic'
-        },
-        {
-          title: `${this.$t('navigation.ontologies')}`,
-          to: '/semantic/ontology'
-        }
-      ],
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    },
-    canListOntologies () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-ontologies')
-    },
-    canCreateOntology () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('create-ontology')
-    }
-  },
-  methods: {
-    close (event) {
-      if (event.success) {
-        // this.$store.dispatch('reloadOntologies')
-      }
-      this.createOntologyDialog = false
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/signup.vue b/dbrepo-ui/pages/signup.vue
deleted file mode 100644
index 54c00602256c7815d8aff0b255214e66836bc727..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/signup.vue
+++ /dev/null
@@ -1,163 +0,0 @@
-<template>
-  <div>
-    <v-toolbar
-      :title="$t('pages.signup.name')"
-      flat />
-    <v-form
-      ref="form"
-      v-model="valid"
-      @submit.prevent="submit">
-      <v-card
-        variant="flat"
-        rounded="0">
-        <v-card-text>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="createAccount.email"
-                type="email"
-                autocomplete="off"
-                autofocus
-                required
-                name="email"
-                :rules="[v => !!v || $t('validation.required')]"
-                :hint="$t('pages.signup.email.hint')"
-                :label="$t('pages.signup.email.label')" />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="createAccount.username"
-                autocomplete="off"
-                required
-                name="username"
-                :rules="[v => !!v || $t('validation.required'),
-                         v => /^[a-z0-9]{3,}$/.test(v) || $t('validation.user.pattern'),
-                         v => !usernames.includes(v) || $t('validation.user.exists')]"
-                persistent-hint
-                :hint="$t('pages.signup.username.hint')"
-                :label="$t('pages.signup.username.label')" />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="createAccount.password"
-                autocomplete="off"
-                required
-                name="password"
-                :rules="[
-                  v => !!v || $t('validation.required')
-                ]"
-                type="password"
-                persistent-hint
-                :label="$t('pages.signup.password.label')"
-                :hint="$t('pages.signup.password.hint')" />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="password2"
-                autocomplete="off"
-                required
-                name="password-confirm"
-                :rules="[
-                  v => !!v || $t('validation.required')
-                ]"
-                :error-messages="password2 && password2 !== this.createAccount.password ? [this.$t('validation.matching')] : []"
-                type="password"
-                persistent-hint
-                :label="$t('pages.signup.confirm.label')"
-                :hint="$t('pages.signup.confirm.hint')" />
-            </v-col>
-          </v-row>
-        </v-card-text>
-        <v-card-text>
-          <v-btn
-            id="login"
-            variant="flat"
-            :disabled="!valid"
-            color="primary"
-            type="submit"
-            name="submit"
-            :text="$t('pages.signup.submit.label')"
-            :loading="loading"
-            @click="register" />
-        </v-card-text>
-      </v-card>
-    </v-form>
-  </div>
-</template>
-
-<script>
-export default {
-  data () {
-    return {
-      loading: false,
-      loadingUsers: false,
-      usernames: [],
-      error: false, // XXX: `error` is never changed
-      valid: false,
-      password2: null,
-      privacy: false,
-      consent: false,
-      createAccount: {
-        username: null,
-        email: null,
-        password: null
-      }
-    }
-  },
-  mounted () {
-    this.loadUsers()
-  },
-  methods: {
-    submit () {
-      this.$refs.form.validate()
-    },
-    register () {
-      this.loading = true
-      const userService = useUserService()
-      userService.create(this.createAccount)
-        .then(() => {
-          const toast = useToastInstance()
-          toast.success(this.$t('success.signup'))
-          this.$router.push('/login')
-          this.loading = false
-        })
-        .catch(({code}) => {
-          this.loading = false
-          const toast = useToastInstance()
-          if (typeof code !== 'string') {
-            return
-          }
-          toast.error(this.$t(code))
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    },
-    loadUsers () {
-      this.loadingUsers = true
-      const userService = useUserService()
-      userService.findAll()
-        .then((users) => {
-          this.usernames = users.map(u => u.username)
-        })
-        .catch(({code}) => {
-          this.loadingUsers = false
-          const toast = useToastInstance()
-          if (typeof code !== 'string') {
-            return
-          }
-          toast.error(this.$t(code))
-        })
-        .finally(() => {
-          this.loadingUsers = false
-        })
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue
index 3a43421a709560b3e841760620321f0c640275f9..50008d3c5dab56111fb15ae7a6164e1a591af1f9 100644
--- a/dbrepo-ui/pages/user/authentication.vue
+++ b/dbrepo-ui/pages/user/authentication.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <UserToolbar />
     <v-window v-model="tab">
       <v-window-item>
@@ -10,8 +11,7 @@
           rounded="0">
           <v-card-text>
             <v-form
-              v-model="valid2"
-              @submit.prevent="submit">
+              v-model="valid2">
               <v-row dense>
                 <v-col md="6">
                   <v-text-field
@@ -60,9 +60,12 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import UserToolbar from '@/components/user/UserToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -88,12 +91,12 @@ export default {
       email: null,
       password: null,
       password2: null,
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
@@ -104,15 +107,11 @@ export default {
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal
     }
   },
-  mounted () {
-  },
   methods: {
-    submit () {
-    },
     changePassword () {
       this.loadingUpdate = true
       const userService = useUserService()
-      userService.updatePassword(this.user.id, {'password': this.password})
+      userService.updatePassword(this.cacheUser.uid, {'password': this.password})
         .then(() => {
           const toast = useToastInstance()
           toast.success(this.$t('success.user.password'))
diff --git a/dbrepo-ui/pages/user/developer.vue b/dbrepo-ui/pages/user/developer.vue
deleted file mode 100644
index de52a490aff050b7a7a92c1870645301bf68b9d3..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/user/developer.vue
+++ /dev/null
@@ -1,230 +0,0 @@
-<template>
-  <div>
-    <UserToolbar />
-    <v-window
-      v-model="tab">
-      <v-window-item>
-        <v-card
-          v-if="canHandleMessages"
-          :title="$t('pages.settings.subpages.developer.maintenance.title')"
-          rounded="0"
-          variant="flat">
-          <v-data-table
-            :headers="headers"
-            :items="messages"
-            :loading="loadingMessages"
-            :items-per-page="10">
-            <template v-slot:item.action="{ item }">
-              <v-btn
-                size="x-small"
-                variant="flat"
-                :text="$t('pages.settings.subpages.developer.maintenance.modify.text')"
-                @click="modifyMessage(item)" />
-            </template>
-          </v-data-table>
-          <v-card-text>
-            <v-btn
-              size="small"
-              variant="flat"
-              :text="$t('pages.settings.subpages.developer.maintenance.add.text')"
-              :disabled="!canCreateMessage"
-              @click="createMessage" />
-          </v-card-text>
-        </v-card>
-        <v-divider
-          v-if="canHandleMessages" />
-        <v-card
-          :title="$t('pages.settings.subpages.developer.token.title')"
-          :subtitle="$t('pages.settings.subpages.developer.token.subtitle')"
-          variant="flat"
-          rounded="0">
-          <v-card-text>
-            <v-row dense>
-              <v-col xl="4">
-                <v-text-field
-                  v-model="accessTokenField"
-                  disabled
-                  :variant="inputVariant"
-                  :label="$t('pages.settings.subpages.developer.token.access.label')" />
-              </v-col>
-              <v-col xl="2">
-                <v-text-field
-                  v-model="tokenExpiry"
-                  disabled
-                  :variant="inputVariant"
-                  :label="expiryLabel(token)" />
-              </v-col>
-            </v-row>
-            <v-row dense>
-              <v-col xl="4">
-                <v-text-field
-                  v-model="refreshTokenField"
-                  disabled
-                  :variant="inputVariant"
-                  :label="$t('pages.settings.subpages.developer.token.refresh.label')" />
-              </v-col>
-              <v-col xl="2">
-                <v-text-field
-                  v-model="refreshTokenExpiry"
-                  disabled
-                  :variant="inputVariant"
-                  :label="expiryLabel(refreshToken)" />
-              </v-col>
-            </v-row>
-          </v-card-text>
-        </v-card>
-      </v-window-item>
-    </v-window>
-    <v-breadcrumbs :items="items" class="pa-0 mt-2" />
-    <v-dialog
-      v-model="dialog"
-      persistent
-      max-width="640">
-      <EditMaintenanceMessage
-        :id="messageId"
-        @close-dialog="closeDialog" />
-    </v-dialog>
-  </div>
-</template>
-
-<script>
-import UserToolbar from '@/components/user/UserToolbar.vue'
-import EditMaintenanceMessage from '@/components/dialogs/EditMaintenanceMessage.vue'
-import { formatTimestampUTCLabel, isActiveMessage, timestampsToHumanDifference } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  components: {
-    UserToolbar,
-    EditMaintenanceMessage
-  },
-  data () {
-    return {
-      tab: 0,
-      accessTokenField: null,
-      refreshTokenField: null,
-      headers: [
-        { title: this.$t('pages.settings.subpages.developer.maintenance.active'), value: 'active' },
-        { title: this.$t('pages.settings.subpages.developer.maintenance.type'), value: 'type' },
-        { title: this.$t('pages.settings.subpages.developer.maintenance.message'), value: 'message' },
-        { title: this.$t('pages.settings.subpages.developer.maintenance.action'), value: 'action' }
-      ],
-      items: [
-        {
-          title: this.$t('navigation.user'),
-          to: '/user'
-        },
-        {
-          title: this.$t('toolbars.user.developer'),
-          to: `/user/developer`,
-          disabled: true
-        }
-      ],
-      messages: [],
-      loadingMessages: false,
-      dialog: false,
-      messageId: null,
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    tokenExpiry () {
-      if (!this.token) {
-        return null
-      }
-      const authenticationService = useAuthenticationService()
-      return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.token))
-    },
-    refreshToken () {
-      return this.userStore.getRefreshToken
-    },
-    refreshTokenExpiry () {
-      if (!this.refreshToken) {
-        return null
-      }
-      const authenticationService = useAuthenticationService()
-      return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.refreshToken))
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    canCreateMessage () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('create-maintenance-message')
-    },
-    canModifyMessage () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('modify-maintenance-message')
-    },
-    canHandleMessages () {
-      return this.canCreateMessage || this.canModifyMessage
-    },
-    inputVariant () {
-      const runtimeConfig = useRuntimeConfig()
-      return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal
-    },
-    buttonVariant () {
-      const runtimeConfig = useRuntimeConfig()
-      return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal
-    }
-  },
-  mounted () {
-    this.loadMessages()
-    if (!this.token || !this.refreshToken) {
-      return
-    }
-    this.accessTokenField = this.token
-    this.refreshTokenField = this.refreshToken
-  },
-  methods: {
-    submit () {
-    },
-    modifyMessage (message) {
-      this.messageId = message.id
-      this.dialog = true
-    },
-    createMessage () {
-      this.messageId = null
-      this.dialog = true
-    },
-    expiryLabel (token) {
-      const authenticationService = useAuthenticationService()
-      return this.$t('pages.settings.subpages.developer.token.expiry') + ' ' + timestampsToHumanDifference(Date.now(), authenticationService.tokenToExpiryDate(token))
-    },
-    loadMessages () {
-      const messageService = useMessageService()
-      messageService.findAll()
-        .then((messages) => {
-          this.messages = messages.map((message) => {
-            message.active = isActiveMessage(message) ? '● true' : 'false'
-            return message
-          })
-        })
-        .catch(() => {
-          this.loadingMessages = false
-        })
-        .finally(() => {
-          this.loadingMessages = false
-        })
-    },
-    closeDialog (event) {
-      if (event.success) {
-        this.cacheStore.reloadMessages()
-      }
-      this.dialog = false
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/user/index.vue b/dbrepo-ui/pages/user/index.vue
index accae861052044324dc08ae48f6858e643172c5f..aa8ee559441bfdc4dd29380d77a98662c476ed79 100644
--- a/dbrepo-ui/pages/user/index.vue
+++ b/dbrepo-ui/pages/user/index.vue
@@ -3,24 +3,10 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
-
 export default {
-  data () {
-    return {
-      userStore: useUserStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    }
-  },
   mounted () {
-    if (!this.user) {
+    const { loggedIn } = useOidcAuth()
+    if (!loggedIn) {
       return
     }
     this.$router.push('/user/info')
diff --git a/dbrepo-ui/pages/user/info.vue b/dbrepo-ui/pages/user/info.vue
index 9b94dde4dad312bb648e992efbc38120798bf869..470b7bc438a0211d80ad44f06411f1da7f54dddc 100644
--- a/dbrepo-ui/pages/user/info.vue
+++ b/dbrepo-ui/pages/user/info.vue
@@ -1,9 +1,12 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <UserToolbar />
-    <v-window v-model="tab">
+    <v-window
+      v-model="tab">
       <v-window-item>
-        <v-form v-model="valid1" @submit.prevent="submit">
+        <v-form
+          v-model="valid1">
           <v-card
             :title="$t('pages.user.subpages.info.title')"
             :subtitle="$t('pages.user.subpages.info.subtitle')"
@@ -19,10 +22,12 @@
                     :label="$t('pages.user.subpages.info.id.label')" />
                 </v-col>
               </v-row>
-              <v-row dense>
+              <v-row
+                v-if="cacheUser"
+                dense>
                 <v-col md="6">
                   <v-text-field
-                    v-model="model.username"
+                    v-model="cacheUser.preferred_username"
                     disabled
                     :variant="inputVariant"
                     :label="$t('pages.user.subpages.info.username.label')"  />
@@ -122,9 +127,12 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import UserToolbar from '@/components/user/UserToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -138,15 +146,16 @@ export default {
       error: false,
       loadingUpdate: false,
       loadingTheme: false,
-      theme: null,
       orcidLoading: false,
       model: {
         id: null,
-        username: null,
+        preferred_username: null,
         firstname: null,
         lastname: null,
         theme: null,
-        language: null
+        language: null,
+        orcid: null,
+        affiliation: null
       },
       themes: [
         { name: this.$t('pages.user.subpages.theme.light'), value: 'light' },
@@ -169,23 +178,23 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    locale () {
+      return this.cacheStore.getLocale
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    locale () {
-      return this.userStore.getLocale
-    },
-    canModifyTheme () {
-      return this.roles.includes('modify-user-theme')
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     canModifyInformation () {
+      if (!this.roles) {
+        return false
+      }
       return this.roles.includes('modify-user-information')
     },
     inputVariant () {
@@ -201,8 +210,6 @@ export default {
     this.init()
   },
   methods: {
-    submit () {
-    },
     updateInfo () {
       this.loadingUpdate = true
       const payload = {
@@ -211,17 +218,16 @@ export default {
         orcid: this.model.orcid,
         affiliation: this.model.affiliation,
         theme: this.model.theme,
-        language: this.model.language,
+        language: this.model.language
       }
       const userService = useUserService()
-      userService.update(this.user.id, payload)
+      userService.update(this.cacheUser.uid, payload)
         .then((user) => {
           console.info('Updated user information')
           const toast = useToastInstance()
           toast.success(this.$t('success.user.info'))
-          this.userStore.setUser(user)
           /* language */
-          this.userStore.setLocale(this.model.language)
+          this.cacheStore.setLocale(this.model.language)
           this.$i18n.locale = this.locale
           /* theme */
           switch (this.model.theme) {
@@ -247,18 +253,18 @@ export default {
         })
     },
     init () {
-      if (!this.user) {
+      if (!this.cacheUser) {
         return
       }
       this.model = {
-        id: this.user.id,
-        username: this.user.username,
-        firstname: this.user.given_name,
-        lastname: this.user.family_name,
-        orcid: this.user.attributes.orcid,
-        affiliation: this.user.attributes.affiliation,
-        theme: this.user.attributes.theme,
-        language: this.user.attributes.language
+        id: this.cacheUser.uid,
+        username: this.cacheUser.username,
+        firstname: this.cacheUser.given_name,
+        lastname: this.cacheUser.family_name,
+        orcid: this.cacheUser.orcid,
+        affiliation: this.cacheUser.affiliation,
+        theme: this.cacheUser.theme ? this.cacheUser.theme : 'light',
+        language: this.cacheUser.language ? this.cacheUser.language : 'en'
       }
     },
     retrieve () {
diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js
index 3574b24d7c6300b884f7874726254e3c805393b3..c2e34f48bbc9bedc8d4afc31c9158963a9450749 100644
--- a/dbrepo-ui/stores/cache.js
+++ b/dbrepo-ui/stores/cache.js
@@ -7,9 +7,14 @@ export const useCacheStore = defineStore('cache', {
       database: null,
       table: null,
       view: null,
+      access: null,
       subset: null,
+      locale: null,
+      identifier: null,
       ontologies: [],
       messages: [],
+      user: null,
+      roles: [],
       uploadProgress: null
     }
   },
@@ -17,9 +22,14 @@ export const useCacheStore = defineStore('cache', {
     getDatabase: (state) => state.database,
     getTable: (state) => state.table,
     getView: (state) => state.view,
+    getAccess: (state) => state.access,
     getSubset: (state) => state.subset,
+    getLocale: (state) => state.locale,
+    getIdentifier: (state) => state.identifier,
     getOntologies: (state) => state.ontologies,
     getMessages: (state) => state.messages,
+    getUser: (state) => state.user,
+    getRoles: (state) => state.roles,
     getUploadProgress: (state) => state.uploadProgress,
   },
   actions: {
@@ -32,12 +42,27 @@ export const useCacheStore = defineStore('cache', {
     setView(view) {
       this.view = view
     },
+    setAccess(access) {
+      this.access = access
+    },
     setSubset(subset) {
       this.subset = subset
     },
+    setLocale(locale) {
+      this.locale = locale
+    },
+    setIdentifier(identifier) {
+      this.identifier = identifier
+    },
     setOntologies(ontologies) {
       this.ontologies = ontologies
     },
+    setUser(user) {
+      this.user = user
+    },
+    setRoles(roles) {
+      this.roles = roles
+    },
     setUploadProgress(uploadProgress) {
       this.uploadProgress = uploadProgress
     },
@@ -81,6 +106,14 @@ export const useCacheStore = defineStore('cache', {
           console.error('Failed to reload view', error)
         })
     },
+    reloadSubset() {
+      const queryService = useQueryService()
+      queryService.findOne(this.subset.database_id, this.subset.id)
+        .then(subset => this.subset = subset)
+        .catch((error) => {
+          console.error('Failed to reload subset', error)
+        })
+    },
     setRouteDatabase (databaseId) {
       return new Promise((resolve, reject) => {
         if (!databaseId) {
@@ -102,17 +135,24 @@ 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()
       tableService.findOne(databaseId, tableId)
         .then(table => this.table = table)
     },
+    setRouteAccess(databaseId, userId) {
+      if (!databaseId || !userId) {
+        this.access = null
+        return
+      }
+      const accessService = useAccessService()
+      accessService.findOne(databaseId, userId)
+        .then(access => this.access = access)
+    },
     setRouteView(databaseId, viewId) {
       if (!databaseId || !viewId) {
         this.view = null
-        console.error('Cannot set route view: database view id', databaseId, 'or view id', viewId)
         return
       }
       const viewService = useViewService()
@@ -122,7 +162,6 @@ export const useCacheStore = defineStore('cache', {
     setRouteSubset(databaseId, subsetId) {
       if (!databaseId || !subsetId) {
         this.subset = null
-        console.error('Cannot set route subset: missing database id', databaseId, 'or subset id', subsetId)
         return
       }
       const subsetService = useQueryService()
diff --git a/dbrepo-ui/stores/user.js b/dbrepo-ui/stores/user.js
deleted file mode 100644
index 522ce02a06ed1c695897d92a73c2682d791b499a..0000000000000000000000000000000000000000
--- a/dbrepo-ui/stores/user.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import {defineStore} from 'pinia'
-
-export const useUserStore = defineStore('user', {
-  persist: true,
-  state: () => {
-    return {
-      /** @type String */
-      token: null,
-      /** @type String */
-      refreshToken: null,
-      roles: [],
-      user: null,
-      access: null,
-      locale: null
-    }
-  },
-  getters: {
-    getToken: (state) => state.token,
-    getRefreshToken: (state) => state.refreshToken,
-    getRoles: (state) => state.roles,
-    getUser: (state) => state.user,
-    getAccess: (state) => state.access,
-    getLocale: (state) => state.locale
-  },
-  actions: {
-    setToken(token) {
-      this.token = token
-    },
-    setRefreshToken(refreshToken) {
-      this.refreshToken = refreshToken
-    },
-    setRoles(roles) {
-      this.roles = roles
-    },
-    setUser(user) {
-      this.user = user
-    },
-    setAccess(access) {
-      this.access = access
-    },
-    setLocale (locale) {
-      this.locale = locale
-    },
-    logout() {
-      this.token = null
-      this.refreshToken = null
-      this.roles = []
-      this.user = null
-      this.access = null
-    },
-    setRouteAccess(databaseId) {
-      if (!databaseId || !this.user || !this.user.id) {
-        return
-      }
-      const accessService = useAccessService()
-      accessService.findOne(databaseId, this.user.id)
-        .then(access => this.access = access)
-    }
-  }
-})
diff --git a/dbrepo-upload-service/pom.xml b/dbrepo-upload-service/pom.xml
index f2bea092361406c7f933a5c26f8eadb0ecbcb131..20f379e32e7e58ab53dedc75c230071a2759c3cd 100644
--- a/dbrepo-upload-service/pom.xml
+++ b/dbrepo-upload-service/pom.xml
@@ -11,7 +11,7 @@
     <groupId>at.tuwien</groupId>
     <artifactId>dbrepo-upload-service</artifactId>
     <name>dbrepo-upload-service</name>
-    <version>1.6.1</version>
+    <version>1.6.3</version>
 
     <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url>
     <developers>
diff --git a/dbrepo-upload-service/pre-create.sh b/dbrepo-upload-service/pre-create.sh
index 536a2e63e060c32db1882bbaad7f4de02cc3d2f7..2d6eb4f861297db095e9dcf5268ed858fde7cd6d 100755
--- a/dbrepo-upload-service/pre-create.sh
+++ b/dbrepo-upload-service/pre-create.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 REQUEST_RAW=$(cat /dev/stdin)
-AUTH_SERVICE_ENDPOINT="${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}"
+METADATA_SERVICE_ENDPOINT="${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}"
 
 echo "[DEBUG] [pre-create hook] request started" >&2
 if [ "$(echo "$REQUEST_RAW" | jq '.Event.HTTPRequest.Header | has("Authorization")')" == "false" ]; then
@@ -21,11 +21,11 @@ END
   exit 0
 fi
 
-echo "[DEBUG] [pre-create hook] request has 'Authorization' header present" >&2
+echo "[DEBUG] [pre-create hook] request has 'Authorization' header p  resent" >&2
 
 BEARER="$(echo "$REQUEST_RAW" | jq -r '.Event.HTTPRequest.Header.Authorization[0]')"
-echo "[DEBUG] [pre-create hook] attempting to contact ${AUTH_SERVICE_ENDPOINT}" >&2
-if [ ! "$(wget -O- --quiet --header "Authorization: ${BEARER}" ${AUTH_SERVICE_ENDPOINT}/realms/dbrepo/protocol/openid-connect/userinfo)" ]; then
+
+if [ ! "$(wget -O- --quiet --header='Authorization: ${BEARER}' ${METADATA_SERVICE_ENDPOINT}/api/license)" ]; then
   echo "[ERROR] [pre-create hook] Unauthorized" >&2
   cat <<END
   {
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java b/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java
index e360cecfdc106386a1229cfd12de189a8b57d60c..601229b5e5ae64da214820b2f91396a926d77884 100644
--- a/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java
@@ -1,13 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 @Log4j2
 @Getter
@@ -28,13 +26,4 @@ public class GatewayConfig {
         return new RestTemplate();
     }
 
-    @Bean("keycloakRestTemplate")
-    public RestTemplate keycloakRestTemplate() {
-        final RestTemplate restTemplate = new RestTemplate();
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
-        restTemplate.getInterceptors()
-                .add(new KeycloakInterceptor(restTemplate(), keycloakUsername, keycloakPassword, keycloakEndpoint));
-        return restTemplate;
-    }
-
 }
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java
index 01be743daa98d258391d3d9c4e6bdec7aa4f8773..6243cb3ab5ecffc614cf71391886cae1852d30a2 100644
--- a/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java
@@ -1,25 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.api.auth.KeycloakErrorDto;
-import at.tuwien.api.keycloak.UserCreateDto;
-import at.tuwien.api.keycloak.UserDto;
-import at.tuwien.exception.AuthServiceConnectionException;
-import at.tuwien.exception.AuthServiceException;
-import at.tuwien.exception.EmailExistsException;
-import at.tuwien.exception.UserExistsException;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
+import org.keycloak.admin.client.Keycloak;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
 
 @Log4j2
 @Getter
@@ -29,55 +15,9 @@ public class KeycloakConfig {
     @Value("${dbrepo.endpoints.keycloak}")
     private String keycloakEndpoint;
 
-    @Autowired
-    @Qualifier("keycloakRestTemplate")
-    private RestTemplate keycloakRestTemplate;
-
-    public Boolean existsByUsername(String username) throws AuthServiceException, AuthServiceConnectionException {
-        final String path = "/admin/realms/dbrepo/users/?username=" + username;
-        final ResponseEntity<UserDto[]> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto[].class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to find user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (Exception e) {
-            log.error("Failed to find user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
-        }
-        final UserDto[] body = response.getBody();
-        if (body == null || body.length != 1) {
-            log.error("Failed to find user with username {}", username);
-            return false;
-        }
-        return true;
-    }
-
-    public void createUser(UserCreateDto data) throws UserExistsException, EmailExistsException,
-            AuthServiceConnectionException, AuthServiceException {
-        final String path = "/admin/realms/dbrepo/users";
-        final ResponseEntity<Void> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to create user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.Conflict e) {
-            if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) {
-                final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
-                if (error != null && error.getErrorMessage().contains("same email")) {
-                    log.error("Failed to create user: email exists: {}", e.getMessage());
-                    throw new EmailExistsException("E-Mail exists", e);
-                }
-            }
-            log.error("Failed to create user: user exists: {}", e.getMessage());
-            throw new UserExistsException("User exists", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
-            log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value());
-            throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value());
-        }
-        log.debug("Created user {} at auth service", data.getUsername());
+    @Bean
+    public Keycloak keycloak() {
+        return Keycloak.getInstance(keycloakEndpoint, "master", "admin", "admin", "admin-cli");
     }
 
 }
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6b5d429e7b87b1a3a4759167f794ad183311883
--- /dev/null
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java
@@ -0,0 +1,22 @@
+package at.tuwien.mapper;
+
+
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.api.user.external.ExternalResultType;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+
+import java.util.LinkedList;
+
+@Mapper(componentModel = "spring", imports = {LinkedList.class, ExternalResultType.class})
+public interface MetadataMapper {
+
+    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class);
+
+    @Mappings({
+            @Mapping(target = "attributes", ignore = true)
+    })
+    UserRepresentation userCreateDtoToUserRepresentation(UserCreateDto data);
+}
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java b/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java
index 30fd6752c3b37a20487aa4133aefdefcbdf3e4b0..052d028d39478f3f8a61b2639bf8bfe8487af9ba 100644
--- a/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java
@@ -7,11 +7,9 @@ import at.tuwien.api.keycloak.UserCreateDto;
 import at.tuwien.config.KeycloakConfig;
 import at.tuwien.config.TusdConfig;
 import at.tuwien.config.TusdContainerConfig;
-import at.tuwien.exception.AuthServiceConnectionException;
 import at.tuwien.exception.AuthServiceException;
-import at.tuwien.exception.EmailExistsException;
-import at.tuwien.exception.UserExistsException;
 import at.tuwien.interceptor.KeycloakInterceptor;
+import at.tuwien.util.KeycloakUtil;
 import com.github.dockerjava.api.model.ExposedPort;
 import dasniko.testcontainers.keycloak.KeycloakContainer;
 import lombok.extern.log4j.Log4j2;
@@ -20,7 +18,10 @@ 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.*;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.DynamicPropertyRegistry;
 import org.springframework.test.context.DynamicPropertySource;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -33,7 +34,6 @@ import org.testcontainers.junit.jupiter.Testcontainers;
 
 import java.util.List;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 @Log4j2
@@ -48,6 +48,9 @@ public class UploadServiceIntegrationTest {
     @Autowired
     private TusdConfig tusdConfig;
 
+    @Autowired
+    private KeycloakUtil keycloakUtil;
+
     @Autowired
     private KeycloakConfig keycloakConfig;
 
@@ -55,7 +58,7 @@ public class UploadServiceIntegrationTest {
     private static TusdContainerConfig.TusdContainer tusdContainer = TusdContainerConfig.TusdContainer.getInstance();
 
     @Container
-    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0")
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:26.0")
             .withImagePullPolicy(PullPolicy.alwaysPull())
             .withRealmImportFile("init/dbrepo-realm.json")
             .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false")
@@ -69,9 +72,8 @@ public class UploadServiceIntegrationTest {
     }
 
     @BeforeEach
-    public void beforeEach() throws UserExistsException, AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException {
-        if (keycloakConfig.existsByUsername(keycloakContainer.getAdminUsername())) {
+    public void beforeEach() throws AuthServiceException {
+        if (keycloakUtil.existsByUsername(keycloakContainer.getAdminUsername())) {
             return;
         }
         final UserCreateDto payload = UserCreateDto.builder()
@@ -82,7 +84,7 @@ public class UploadServiceIntegrationTest {
                         .value(keycloakContainer.getAdminPassword())
                         .build()))
                 .build();
-        keycloakConfig.createUser(payload);
+        keycloakUtil.createUser(payload);
     }
 
     @Test
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java b/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7c24cab9d5221f893e2e1fceb3f378b59e6d684
--- /dev/null
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java
@@ -0,0 +1,46 @@
+package at.tuwien.util;
+
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.mapper.MetadataMapper;
+import jakarta.ws.rs.core.Response;
+import lombok.extern.log4j.Log4j2;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+@Log4j2
+public class KeycloakUtil {
+
+
+    private final MetadataMapper metadataMapper;
+    private final Keycloak keycloak;
+
+    @Autowired
+    public KeycloakUtil(MetadataMapper metadataMapper, Keycloak keycloak) {
+        this.metadataMapper = metadataMapper;
+        this.keycloak = keycloak;
+    }
+
+    public void createUser(UserCreateDto data) throws AuthServiceException {
+        final UserRepresentation user = metadataMapper.userCreateDtoToUserRepresentation(data);
+        try (Response response = keycloak.realm("dbrepo")
+                .users()
+                .create(user)) {
+            if (response.getStatus() != 200) {
+                log.error("Failed to delete user: unexpected response status: {}", response.getStatus());
+                throw new AuthServiceException("Unexpected response status: " + response.getStatus());
+            }
+        }
+        log.info("Created user at auth service");
+    }
+
+    public boolean existsByUsername(String username) {
+        return keycloak.realm("dbrepo")
+                .users()
+                .search(username)
+                .isEmpty();
+    }
+}
diff --git a/docker-compose.yml b/docker-compose.yml
index 5a0d1a4242d9ca2f7f0f8cd97617def35e65cd6a..9176f6404a06df5e30269f4a0dde4d8e4483ebd8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -80,20 +80,25 @@ services:
     restart: "no"
     container_name: dbrepo-auth-service
     hostname: auth-service
-    image: bitnami/keycloak:24.0.5-debian-12-r8
+    image: bitnami/keycloak:26.0.4-debian-12-r0
     volumes:
       - ./dbrepo-auth-service/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh
       - ./dbrepo-auth-service/master-realm.json:/opt/keycloak/data/import/master-realm.json
       - ./dbrepo-auth-service/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json
+      - ./dbrepo-auth-service/listeners/target/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar
     ports:
       - "8080:8080"
     environment:
+      KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true"
       KEYCLOAK_ENABLE_HTTPS: "false"
       KEYCLOAK_ENABLE_STATISTICS: "true"
       KEYCLOAK_DATABASE_HOST: "auth-db"
       KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}"
       KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}"
       KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}/api/user"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+      SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}"
     healthcheck:
       test: curl -fsS http://localhost:8080/realms/master
       interval: 10s
@@ -110,8 +115,8 @@ services:
   dbrepo-auth-service-init:
     init: true
     restart: "no"
-    image: dbrepo-auth-service-init:latest
     container_name: dbrepo-auth-service-init
+    image: dbrepo-auth-service-init:latest
     build:
       context: ./dbrepo-auth-service/init
       network: host
@@ -331,6 +336,14 @@ services:
       NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}"
       NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}"
       NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/auth"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/logout"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/token"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/userinfo"
     depends_on:
       dbrepo-search-service:
         condition: service_healthy
@@ -341,6 +354,8 @@ services:
       interval: 10s
       timeout: 5s
       retries: 12
+    extra_hosts:
+      - "localhost:host-gateway"
     logging:
       driver: json-file
 
@@ -475,7 +490,7 @@ services:
       LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}"
       LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}"
     healthcheck:
-      test: test -f /opt/bitnami/grafana/tmp/grafana.pid
+      test: curl -fsSL --head http://127.0.0.1:3000
       interval: 10s
       timeout: 5s
       retries: 12
@@ -523,6 +538,7 @@ services:
       AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}"
       AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}"
       AWS_REGION: "${STORAGE_REGION_NAME:-default}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}"
     depends_on:
       dbrepo-storage-service:
         condition: service_healthy
diff --git a/helm/dbrepo/Chart.lock b/helm/dbrepo/Chart.lock
index b18ee6f5f6f9fa67da970a2779fd6a33ca3974a1..297b4b1a9287732c869533cd2f2fe261ae43f4a5 100644
--- a/helm/dbrepo/Chart.lock
+++ b/helm/dbrepo/Chart.lock
@@ -4,7 +4,7 @@ dependencies:
   version: 1.4.0
 - name: keycloak
   repository: https://charts.bitnami.com/bitnami
-  version: 21.6.1
+  version: 24.0.3
 - name: mariadb-galera
   repository: https://charts.bitnami.com/bitnami
   version: 13.2.7
@@ -26,5 +26,5 @@ dependencies:
 - name: nginx
   repository: https://charts.bitnami.com/bitnami
   version: 18.3.1
-digest: sha256:414c043a3751945d7bd5b02fa00ee0464bee7f08efb469e00a5f059cdbff03b5
-generated: "2025-01-19T17:22:48.686050629+01:00"
+digest: sha256:aa148a5f656ad17971203ea710206117d6de6f27b6940f9d532a6c5762e5df25
+generated: "2025-02-04T22:01:27.370259572+01:00"
diff --git a/helm/dbrepo/Chart.yaml b/helm/dbrepo/Chart.yaml
index 22d1865df5866213c931df8b2b522af33137c1e6..99f8a84d23b7808e81dd94a337655594abf1721f 100644
--- a/helm/dbrepo/Chart.yaml
+++ b/helm/dbrepo/Chart.yaml
@@ -7,8 +7,8 @@ description: Helm Chart for installing DBRepo
 sources:
   - https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services
 type: application
-version: "1.6.1"
-appVersion: "1.6.1"
+version: "1.6.3"
+appVersion: "1.6.3"
 keywords:
   - dbrepo
 maintainers:
@@ -24,7 +24,7 @@ dependencies:
     condition: searchdb.enabled
   - name: keycloak
     alias: authservice
-    version: 21.6.1  # app version: 24.0.5
+    version: 24.0.3  # app version: 26.0.4
     repository: https://charts.bitnami.com/bitnami
     condition: authservice.enabled
   - name: mariadb-galera
diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md
index 7c613aaebc7a68b53f7df511ec85d66e00b489ca..a45297396372cc5580e4f065e4f7172929ba7c5a 100644
--- a/helm/dbrepo/README.md
+++ b/helm/dbrepo/README.md
@@ -11,7 +11,7 @@ sample [
 for your deployment and update the variables, especially `hostname`.
 
 ```bash
-helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.6.1"
+helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.6.3"
 ```
 
 ## Prerequisites
@@ -28,7 +28,7 @@ helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo"
 To install the chart with the release name `my-release`:
 
 ```bash
-helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.6.1"
+helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.6.3"
 ```
 
 The command deploys DBRepo on the Kubernetes cluster in the default configuration. The Parameters section lists the
@@ -86,6 +86,7 @@ The command removes all the Kubernetes components associated with the chart and
 | `authservice.enabled`                  | Enable the Auth Service.                                                                                          | `true`                                                                                                                                                                                                                                                                                                                                                                                                     |
 | `authservice.image.debug`              | Set the logging level to `trace`. Otherwise, set to `info`.                                                       | `false`                                                                                                                                                                                                                                                                                                                                                                                                    |
 | `authservice.endpoint`                 | The hostname for the microservices.                                                                               | `http://auth-service`                                                                                                                                                                                                                                                                                                                                                                                      |
+| `authservice.production`               | Start Keycloak with production profile.                                                                           | `true`                                                                                                                                                                                                                                                                                                                                                                                                     |
 | `authservice.resourcesPreset`          | The container resource presets                                                                                    | `small`                                                                                                                                                                                                                                                                                                                                                                                                    |
 | `authservice.jwt.pubkey`               | The JWT public key from the `dbrepo-client`.                                                                      | `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB` |
 | `authservice.tls.enabled`              | Enable TLS/SSL communication. Required for HTTPS.                                                                 | `true`                                                                                                                                                                                                                                                                                                                                                                                                     |
@@ -388,7 +389,7 @@ mqtt.prefetch = 10
 | `ui.public.pid.default.publisher`                      | The default dataset publisher for persisted identifiers.                                                          | `Example University`    |
 | `ui.public.doi.enabled`                                | Enable the display that DOIs are minted.                                                                          | `false`                 |
 | `ui.public.doi.endpoint`                               | The DOI proxy.                                                                                                    | `https://doi.org`       |
-| `ui.replicaCount`                                      | The number of replicas.                                                                                           | `2`                     |
+| `ui.replicaCount`                                      | The number of replicas.                                                                                           | `1`                     |
 
 ### Dashboard Service
 
diff --git a/helm/dbrepo/charts/keycloak-21.6.1.tgz b/helm/dbrepo/charts/keycloak-21.6.1.tgz
deleted file mode 100644
index 6479f5943846dee589d3ec90bbda649a8d7b72fe..0000000000000000000000000000000000000000
Binary files a/helm/dbrepo/charts/keycloak-21.6.1.tgz and /dev/null differ
diff --git a/helm/dbrepo/charts/keycloak-24.0.3.tgz b/helm/dbrepo/charts/keycloak-24.0.3.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..29a964b44168bec6c04969e16cf51c94b75952fc
Binary files /dev/null and b/helm/dbrepo/charts/keycloak-24.0.3.tgz differ
diff --git a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz
index 6fd5807b55c4d6ad8041d96ca5d4a39ed3795138..a463170406b9c62f8f33ba315ac440fe435ad93c 100644
Binary files a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz and b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz differ
diff --git a/helm/dbrepo/files/01-setup-schema.sql b/helm/dbrepo/files/01-setup-schema.sql
index c9ce89d1be71f4791c5e55dbb7c24f46e979355a..e2bde25ed6d64f69c4f8d6e897a49a672e3f9a71 100644
--- a/helm/dbrepo/files/01-setup-schema.sql
+++ b/helm/dbrepo/files/01-setup-schema.sql
@@ -3,10 +3,10 @@ BEGIN;
 CREATE TABLE IF NOT EXISTS `mdb_users`
 (
     id               character varying(36)  NOT NULL,
+    keycloak_id      character varying(36)  NOT NULL,
     username         character varying(255) NOT NULL,
     firstname        character varying(255),
     lastname         character varying(255),
-    email            character varying(255) NOT NULL,
     orcid            character varying(255),
     affiliation      character varying(255),
     is_internal      BOOLEAN                NOT NULL DEFAULT FALSE,
@@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS `mdb_users`
     theme            character varying(255) NOT NULL default ('light'),
     language         character varying(3)   NOT NULL default ('en'),
     PRIMARY KEY (id),
-    UNIQUE (username),
-    UNIQUE (email)
+    UNIQUE (keycloak_id),
+    UNIQUE (username)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS `mdb_images`
diff --git a/helm/dbrepo/files/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9a9cd149f84ff92e5292a9fdc19a81edcc9ca7b7
Binary files /dev/null and b/helm/dbrepo/files/create-event-listener.jar differ
diff --git a/helm/dbrepo/templates/auth-configmap.yaml b/helm/dbrepo/templates/auth-configmap.yaml
index ffd14c4b1765cab2f20af5888c746fbf47a71a45..28ad32d66494ba0a284b73354af7e240bff48dd4 100644
--- a/helm/dbrepo/templates/auth-configmap.yaml
+++ b/helm/dbrepo/templates/auth-configmap.yaml
@@ -4,8 +4,11 @@ kind: ConfigMap
 metadata:
   name: auth-service-config
   namespace: {{ include "common.names.namespace" . | quote }}
+binaryData:
+  create-event-listener.jar: |-
+    {{ .Files.Get "files/create-event-listener.jar" | b64enc }}
 data:
-  dbrepo-realm.json: |
+  dbrepo-realm.json: |-
     {
       "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "realm" : "dbrepo",
@@ -35,7 +38,7 @@ data:
       "oauth2DevicePollingInterval" : 5,
       "enabled" : true,
       "sslRequired" : "none",
-      "registrationAllowed" : false,
+      "registrationAllowed" : true,
       "registrationEmailAsUsername" : false,
       "rememberMe" : false,
       "verifyEmail" : true,
@@ -46,6 +49,7 @@ data:
       "bruteForceProtected" : false,
       "permanentLockout" : false,
       "maxTemporaryLockouts" : 0,
+      "bruteForceStrategy" : "MULTIPLE",
       "maxFailureWaitSeconds" : 900,
       "minimumQuickLoginWaitSeconds" : 60,
       "waitIncrementSeconds" : 60,
@@ -1316,8 +1320,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
-          "client.use.lightweight.access.token.enabled" : "true"
+          "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+"
         },
         "authenticationFlowBindingOverrides" : { },
         "fullScopeAllowed" : true,
@@ -1391,6 +1395,38 @@ data:
         "fullScopeAllowed" : true,
         "nodeReRegistrationTimeout" : -1,
         "protocolMappers" : [ {
+          "id" : "266edf62-a19a-483b-b594-81428e4af792",
+          "name" : "orcid",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "ORCID",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "orcid",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "1a21798a-38b6-4df5-89f0-86942415246f",
+          "name" : "theme",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "THEME",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "theme",
+            "jsonType.label" : "String"
+          }
+        }, {
           "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
           "name" : "preferred_username",
           "protocol" : "openid-connect",
@@ -1404,18 +1440,66 @@ data:
             "userinfo.token.claim" : "true"
           }
         }, {
-          "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
-          "name" : "aud",
+          "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a",
+          "name" : "affiliation",
           "protocol" : "openid-connect",
-          "protocolMapper" : "oidc-hardcoded-claim-mapper",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "claim.value" : "dbrepo",
+            "introspection.token.claim" : "true",
             "userinfo.token.claim" : "true",
+            "user.attribute" : "AFFILIATION",
             "id.token.claim" : "true",
+            "lightweight.claim" : "false",
             "access.token.claim" : "true",
-            "claim.name" : "aud",
-            "access.tokenResponse.claim" : "false"
+            "claim.name" : "affiliation",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3",
+          "name" : "given name",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "firstName",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "given_name",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88",
+          "name" : "language",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "LANGUAGE",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "language",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb",
+          "name" : "family name",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "lastName",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "family_name",
+            "jsonType.label" : "String"
           }
         }, {
           "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
@@ -1432,9 +1516,26 @@ data:
             "access.token.claim" : "true",
             "claim.name" : "uid"
           }
+        }, {
+          "id" : "c304ed2f-5952-4772-838d-91998a45f154",
+          "name" : "aud",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-hardcoded-claim-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "claim.value" : "account",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "aud",
+            "jsonType.label" : "String",
+            "access.tokenResponse.claim" : "false"
+          }
         } ],
-        "defaultClientScopes" : [ "roles", "attributes", "basic" ],
-        "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+        "defaultClientScopes" : [ "roles", "basic" ],
+        "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
       }, {
         "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
         "clientId" : "rabbitmq-client",
@@ -1479,12 +1580,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "false",
             "user.attribute" : "username",
             "id.token.claim" : "false",
             "access.token.claim" : "true",
             "claim.name" : "client_id",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "false"
           }
         }, {
           "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
@@ -1493,11 +1594,11 @@ data:
           "protocolMapper" : "oidc-hardcoded-claim-mapper",
           "consentRequired" : false,
           "config" : {
-            "claim.value" : "rabbitmq",
-            "userinfo.token.claim" : "false",
             "id.token.claim" : "false",
             "access.token.claim" : "true",
             "claim.name" : "aud",
+            "claim.value" : "rabbitmq",
+            "userinfo.token.claim" : "false",
             "access.tokenResponse.claim" : "false"
           }
         } ],
@@ -1556,8 +1657,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
           "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+",
           "pkce.code.challenge.method" : "S256"
         },
         "authenticationFlowBindingOverrides" : { },
@@ -1570,12 +1671,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "locale",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "locale",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ],
         "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
@@ -1599,8 +1700,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${emailScopeConsentText}"
+          "consent.screen.text" : "${emailScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
@@ -1609,12 +1710,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "emailVerified",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "email_verified",
-            "jsonType.label" : "boolean"
+            "jsonType.label" : "boolean",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
@@ -1623,12 +1724,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "email",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "email",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1638,8 +1739,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${profileScopeConsentText}"
+          "consent.screen.text" : "${profileScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
@@ -1648,12 +1749,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "username",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "preferred_username",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
@@ -1662,12 +1763,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "gender",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "gender",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
@@ -1676,12 +1777,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "birthdate",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "birthdate",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
@@ -1701,12 +1802,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "profile",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "profile",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
@@ -1715,12 +1816,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "updatedAt",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "updated_at",
-            "jsonType.label" : "long"
+            "jsonType.label" : "long",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "841ea785-26ab-429a-a420-09ce3948924d",
@@ -1729,12 +1830,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "lastName",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "family_name",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
@@ -1743,12 +1844,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "website",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "website",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "475f071d-5149-4379-b928-76482f5f519c",
@@ -1757,12 +1858,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "zoneinfo",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "zoneinfo",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
@@ -1771,12 +1872,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "middleName",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "middle_name",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
@@ -1785,12 +1886,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "picture",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "picture",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
@@ -1799,12 +1900,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "locale",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "locale",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
@@ -1813,12 +1914,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "firstName",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "given_name",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
@@ -1827,12 +1928,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "nickname",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "nickname",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1866,12 +1967,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "username",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "upn",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1913,8 +2014,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${phoneScopeConsentText}"
+          "consent.screen.text" : "${phoneScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
@@ -1923,12 +2024,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "phoneNumber",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "phone_number",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
@@ -1937,12 +2038,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "phoneNumberVerified",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "phone_number_verified",
-            "jsonType.label" : "boolean"
+            "jsonType.label" : "boolean",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1952,8 +2053,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "false",
-          "consent.screen.text" : ""
+          "consent.screen.text" : "",
+          "display.on.consent.screen" : "false"
         },
         "protocolMappers" : [ {
           "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
@@ -2033,6 +2134,61 @@ data:
           "gui.order" : "",
           "consent.screen.text" : ""
         }
+      }, {
+        "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6",
+        "name" : "service_account",
+        "description" : "Specific scope for a client enabled for service accounts",
+        "protocol" : "openid-connect",
+        "attributes" : {
+          "include.in.token.scope" : "false",
+          "display.on.consent.screen" : "false"
+        },
+        "protocolMappers" : [ {
+          "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512",
+          "name" : "Client IP Address",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientAddress",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientAddress",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a",
+          "name" : "Client Host",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientHost",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientHost",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae",
+          "name" : "Client ID",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "client_id",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "client_id",
+            "jsonType.label" : "String"
+          }
+        } ]
       }, {
         "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
         "name" : "offline_access",
@@ -2049,8 +2205,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${addressScopeConsentText}"
+          "consent.screen.text" : "${addressScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
@@ -2123,8 +2279,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${rolesScopeConsentText}"
+          "consent.screen.text" : "${rolesScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
@@ -2140,11 +2296,15 @@ data:
           "protocolMapper" : "oidc-usermodel-realm-role-mapper",
           "consentRequired" : false,
           "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "false",
+            "multivalued" : "true",
             "user.attribute" : "foo",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
             "access.token.claim" : "true",
             "claim.name" : "realm_access.roles",
-            "jsonType.label" : "String",
-            "multivalued" : "true"
+            "jsonType.label" : "String"
           }
         }, {
           "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
@@ -2174,8 +2334,12 @@ data:
         "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
       },
       "smtpServer" : { },
+      "loginTheme" : "keycloak.v2",
+      "accountTheme" : "",
+      "adminTheme" : "",
+      "emailTheme" : "",
       "eventsEnabled" : false,
-      "eventsListeners" : [ "jboss-logging" ],
+      "eventsListeners" : [ "create-event-listener", "jboss-logging" ],
       "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
       "adminEventsEnabled" : false,
       "adminEventsDetailsEnabled" : false,
@@ -2223,7 +2387,7 @@ data:
           "subType" : "anonymous",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
           }
         }, {
           "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2249,7 +2413,15 @@ data:
           "subType" : "authenticated",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+          }
+        } ],
+        "org.keycloak.userprofile.UserProfileProvider" : [ {
+          "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
+          "providerId" : "declarative-user-profile",
+          "subComponents" : { },
+          "config" : {
+            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
           }
         } ],
         "org.keycloak.storage.UserStorageProvider" : [ {
@@ -2265,8 +2437,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "createTimestamp" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "read.only" : [ "true" ],
                 "always.read.value.from.ldap" : [ "true" ],
+                "read.only" : [ "true" ],
                 "user.model.attribute" : [ "createTimestamp" ]
               }
             }, {
@@ -2277,8 +2449,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "sn" ],
                 "is.mandatory.in.ldap" : [ "true" ],
-                "always.read.value.from.ldap" : [ "true" ],
                 "read.only" : [ "false" ],
+                "always.read.value.from.ldap" : [ "true" ],
                 "user.model.attribute" : [ "lastName" ]
               }
             }, {
@@ -2301,8 +2473,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "mail" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "false" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "email" ]
               }
             }, {
@@ -2311,19 +2483,19 @@ data:
               "providerId" : "group-ldap-mapper",
               "subComponents" : { },
               "config" : {
+                "mode" : [ "LDAP_ONLY" ],
                 "membership.attribute.type" : [ "DN" ],
+                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
                 "group.name.ldap.attribute" : [ "cn" ],
-                "preserve.group.inheritance" : [ "false" ],
                 "membership.user.ldap.attribute" : [ "uid" ],
-                "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ],
-                "mode" : [ "LDAP_ONLY" ],
-                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
-                "membership.ldap.attribute" : [ "member" ],
                 "ignore.missing.groups" : [ "false" ],
+                "preserve.group.inheritance" : [ "false" ],
+                "membership.ldap.attribute" : [ "member" ],
                 "memberof.ldap.attribute" : [ "memberOf" ],
                 "group.object.classes" : [ "groupOfNames" ],
-                "drop.non.existing.groups.during.sync" : [ "false" ],
-                "groups.path" : [ "/" ]
+                "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
+                "groups.path" : [ "/" ],
+                "drop.non.existing.groups.during.sync" : [ "false" ]
               }
             }, {
               "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb",
@@ -2347,15 +2519,15 @@ data:
                 "is.mandatory.in.ldap" : [ "true" ],
                 "attribute.force.default" : [ "false" ],
                 "is.binary.attribute" : [ "false" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "false" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "username" ]
               }
             } ]
           },
           "config" : {
-            "pagination" : [ "false" ],
             "fullSyncPeriod" : [ "-1" ],
+            "pagination" : [ "false" ],
             "startTls" : [ "false" ],
             "connectionPooling" : [ "true" ],
             "usersDn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ],
@@ -2363,15 +2535,15 @@ data:
             "useKerberosForPasswordAuthentication" : [ "false" ],
             "importEnabled" : [ "true" ],
             "enabled" : [ "true" ],
+            "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ],
             "changedSyncPeriod" : [ "-1" ],
-            "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ],
             "usernameLDAPAttribute" : [ "uid" ],
-            "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ],
+            "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ],
             "lastSync" : [ "1719252666" ],
             "vendor" : [ "other" ],
             "uuidLDAPAttribute" : [ "entryUUID" ],
-            "connectionUrl" : [ "ldap://identity-service:389" ],
             "allowKerberosAuthentication" : [ "false" ],
+            "connectionUrl" : [ "ldap://identity-service:389" ],
             "syncRegistrations" : [ "true" ],
             "authType" : [ "simple" ],
             "useTruststoreSpi" : [ "always" ],
@@ -2383,14 +2555,6 @@ data:
             "validatePasswordPolicy" : [ "false" ]
           }
         } ],
-        "org.keycloak.userprofile.UserProfileProvider" : [ {
-          "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
-          "providerId" : "declarative-user-profile",
-          "subComponents" : { },
-          "config" : {
-            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
-          }
-        } ],
         "org.keycloak.keys.KeyProvider" : [ {
           "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
           "name" : "rsa-enc-generated",
@@ -3003,10 +3167,12 @@ data:
         "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
         "parRequestUriLifespan" : "60",
         "clientSessionMaxLifespan" : "0",
+        "organizationsEnabled" : "false",
         "shortVerificationUri" : ""
       },
-      "keycloakVersion" : "24.0.5",
+      "keycloakVersion" : "26.0.4",
       "userManagedAccessAllowed" : false,
+      "organizationsEnabled" : false,
       "clientProfiles" : {
         "profiles" : [ ]
       },
@@ -3014,7 +3180,7 @@ data:
         "policies" : [ ]
       }
     }
-  master-realm.json: |
+  master-realm.json: |-
     {
       "id" : "afe47bd0-61f8-40c3-95cb-04930407ebdd",
       "realm" : "master",
@@ -3057,6 +3223,7 @@ data:
       "bruteForceProtected" : false,
       "permanentLockout" : false,
       "maxTemporaryLockouts" : 0,
+      "bruteForceStrategy" : "MULTIPLE",
       "maxFailureWaitSeconds" : 900,
       "minimumQuickLoginWaitSeconds" : 60,
       "waitIncrementSeconds" : 60,
@@ -3681,8 +3848,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
-          "client.use.lightweight.access.token.enabled" : "true"
+          "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+"
         },
         "authenticationFlowBindingOverrides" : { },
         "fullScopeAllowed" : true,
@@ -3800,8 +3967,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
           "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+",
           "pkce.code.challenge.method" : "S256"
         },
         "authenticationFlowBindingOverrides" : { },
@@ -3833,8 +4000,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${addressScopeConsentText}"
+          "consent.screen.text" : "${addressScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "4aed5e41-0d8d-4c24-80a0-cd9822072756",
@@ -3862,8 +4029,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${organizationScopeConsentText}"
+          "consent.screen.text" : "${organizationScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92",
@@ -3881,6 +4048,61 @@ data:
             "jsonType.label" : "String"
           }
         } ]
+      }, {
+        "id" : "1be1e284-2749-4bbb-890a-2d519cc1531c",
+        "name" : "service_account",
+        "description" : "Specific scope for a client enabled for service accounts",
+        "protocol" : "openid-connect",
+        "attributes" : {
+          "include.in.token.scope" : "false",
+          "display.on.consent.screen" : "false"
+        },
+        "protocolMappers" : [ {
+          "id" : "c913a673-cf66-4493-a2ed-14556c07617c",
+          "name" : "Client ID",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "client_id",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "client_id",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "5c244d68-5c63-4356-ac71-5a586f40c77e",
+          "name" : "Client IP Address",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientAddress",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientAddress",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "600285d4-ae51-4b39-a7be-bb83cf5870db",
+          "name" : "Client Host",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientHost",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientHost",
+            "jsonType.label" : "String"
+          }
+        } ]
       }, {
         "id" : "0411ea86-a074-4781-850d-ea3ca94590a2",
         "name" : "offline_access",
@@ -3932,8 +4154,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${profileScopeConsentText}"
+          "consent.screen.text" : "${profileScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "2d1400be-4053-4393-ba87-91b64f699054",
@@ -4234,8 +4456,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "false",
-          "consent.screen.text" : ""
+          "consent.screen.text" : "",
+          "display.on.consent.screen" : "false"
         },
         "protocolMappers" : [ {
           "id" : "635cbac1-7cab-43bd-99fc-f7084aca2fa2",
@@ -4271,8 +4493,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${rolesScopeConsentText}"
+          "consent.screen.text" : "${rolesScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "2b5a3df4-1adb-402d-bc28-2bd43224e682",
@@ -4281,12 +4503,12 @@ data:
           "protocolMapper" : "oidc-usermodel-realm-role-mapper",
           "consentRequired" : false,
           "config" : {
-            "introspection.token.claim" : "true",
-            "multivalued" : "true",
             "user.attribute" : "foo",
+            "introspection.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "realm_access.roles",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "multivalued" : "true"
           }
         }, {
           "id" : "f3b60071-ef26-48a7-9554-67f62f84d543",
@@ -4295,12 +4517,12 @@ data:
           "protocolMapper" : "oidc-usermodel-client-role-mapper",
           "consentRequired" : false,
           "config" : {
-            "introspection.token.claim" : "true",
-            "multivalued" : "true",
             "user.attribute" : "foo",
+            "introspection.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "resource_access.${client_id}.roles",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "multivalued" : "true"
           }
         }, {
           "id" : "b757200e-494a-4585-857e-e4c18aef7a0c",
@@ -4320,8 +4542,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${emailScopeConsentText}"
+          "consent.screen.text" : "${emailScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "e18769b3-778b-47d8-be52-dd2769deebd1",
@@ -4361,8 +4583,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${phoneScopeConsentText}"
+          "consent.screen.text" : "${phoneScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "98cc724c-3f53-47f7-bf9f-baf2f7e08026",
@@ -4448,7 +4670,7 @@ data:
           "subType" : "anonymous",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper" ]
           }
         }, {
           "id" : "4b976576-c880-48a0-9b4d-2956cfd19b4a",
@@ -4457,7 +4679,7 @@ data:
           "subType" : "authenticated",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper" ]
           }
         }, {
           "id" : "e1861ec9-2761-46fb-8048-149492269ff0",
@@ -4487,6 +4709,14 @@ data:
             "allow-default-scopes" : [ "true" ]
           }
         } ],
+        "org.keycloak.userprofile.UserProfileProvider" : [ {
+          "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
+          "providerId" : "declarative-user-profile",
+          "subComponents" : { },
+          "config" : {
+            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
+          }
+        } ],
         "org.keycloak.storage.UserStorageProvider" : [ {
           "id" : "3a6f24e8-128b-4ac1-b3ab-694836db82fd",
           "name" : "Identity Service",
@@ -4500,8 +4730,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "mail" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "false" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "email" ]
               }
             }, {
@@ -4512,8 +4742,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "sn" ],
                 "is.mandatory.in.ldap" : [ "true" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "true" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "lastName" ]
               }
             }, {
@@ -4524,8 +4754,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "modifyTimestamp" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "always.read.value.from.ldap" : [ "true" ],
                 "read.only" : [ "true" ],
+                "always.read.value.from.ldap" : [ "true" ],
                 "user.model.attribute" : [ "modifyTimestamp" ]
               }
             }, {
@@ -4558,17 +4788,17 @@ data:
               "providerId" : "group-ldap-mapper",
               "subComponents" : { },
               "config" : {
+                "mode" : [ "LDAP_ONLY" ],
                 "membership.attribute.type" : [ "DN" ],
+                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
                 "group.name.ldap.attribute" : [ "cn" ],
+                "ignore.missing.groups" : [ "false" ],
                 "membership.user.ldap.attribute" : [ "uid" ],
                 "preserve.group.inheritance" : [ "false" ],
-                "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ],
-                "mode" : [ "LDAP_ONLY" ],
-                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
                 "membership.ldap.attribute" : [ "member" ],
-                "ignore.missing.groups" : [ "false" ],
-                "group.object.classes" : [ "groupOfNames" ],
+                "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
                 "memberof.ldap.attribute" : [ "memberOf" ],
+                "group.object.classes" : [ "groupOfNames" ],
                 "drop.non.existing.groups.during.sync" : [ "false" ],
                 "groups.path" : [ "/" ]
               }
@@ -4580,8 +4810,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "createTimestamp" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "always.read.value.from.ldap" : [ "true" ],
                 "read.only" : [ "true" ],
+                "always.read.value.from.ldap" : [ "true" ],
                 "user.model.attribute" : [ "createTimestamp" ]
               }
             } ]
@@ -4597,13 +4827,13 @@ data:
             "importEnabled" : [ "true" ],
             "enabled" : [ "true" ],
             "changedSyncPeriod" : [ "-1" ],
+            "usernameLDAPAttribute" : [ "uid" ],
             "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ],
             "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ],
-            "usernameLDAPAttribute" : [ "uid" ],
             "vendor" : [ "other" ],
             "uuidLDAPAttribute" : [ "entryUUID" ],
             "allowKerberosAuthentication" : [ "false" ],
-            "connectionUrl" : [ "ldap://identity-service:1389" ],
+            "connectionUrl" : [ "ldap://identity-service:389" ],
             "syncRegistrations" : [ "true" ],
             "authType" : [ "simple" ],
             "krbPrincipalAttribute" : [ "krb5PrincipalName" ],
@@ -4617,14 +4847,6 @@ data:
             "validatePasswordPolicy" : [ "false" ]
           }
         } ],
-        "org.keycloak.userprofile.UserProfileProvider" : [ {
-          "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
-          "providerId" : "declarative-user-profile",
-          "subComponents" : { },
-          "config" : {
-            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
-          }
-        } ],
         "org.keycloak.keys.KeyProvider" : [ {
           "id" : "5b1052d2-fb71-47d2-86f9-908c869c8d1b",
           "name" : "hmac-generated-hs512",
@@ -5236,10 +5458,12 @@ data:
         "parRequestUriLifespan" : "60",
         "clientSessionMaxLifespan" : "0",
         "frontendUrl" : "",
+        "organizationsEnabled" : "false",
         "acr.loa.map" : "{}"
       },
-      "keycloakVersion" : "24.0.5",
+      "keycloakVersion" : "26.0.4",
       "userManagedAccessAllowed" : false,
+      "organizationsEnabled" : false,
       "clientProfiles" : {
         "profiles" : [ ]
       },
diff --git a/helm/dbrepo/templates/auth-secret.yaml b/helm/dbrepo/templates/auth-secret.yaml
index a568ef25007e51d70bf4ad1ac186645e57499015..dca0f861f132ea1557a52b488c63e74e6b435917 100644
--- a/helm/dbrepo/templates/auth-secret.yaml
+++ b/helm/dbrepo/templates/auth-secret.yaml
@@ -11,6 +11,8 @@ stringData:
   AUTH_SERVICE_ENDPOINT: "{{ .Values.authservice.endpoint }}"
   METADATA_DB: "{{ .Values.metadatadb.db.name }}"
   METADATA_DB_PASSWORD: "{{ .Values.metadatadb.rootUser.password }}"
+  METADATA_SERVICE_ENDPOINT: "{{ .Values.metadataservice.endpoint }}/api/user"
   METADATA_USERNAME: "{{ .Values.metadatadb.rootUser.user }}"
   SYSTEM_USERNAME: "{{ .Values.identityservice.users }}"
+  SYSTEM_PASSWORD: "{{ .Values.identityservice.userPasswords }}"
 {{- end }}
diff --git a/helm/dbrepo/templates/gateway-configmap.yaml b/helm/dbrepo/templates/gateway-configmap.yaml
index aa314d3c65948076a4e7eaf977bf47b8735b153d..8ef358871523c80ac16ec128e54e116b3d57d52e 100644
--- a/helm/dbrepo/templates/gateway-configmap.yaml
+++ b/helm/dbrepo/templates/gateway-configmap.yaml
@@ -39,6 +39,24 @@ data:
             proxy_read_timeout      90;
         }
 
+        location /realms {
+            proxy_set_header        Host $host;
+            proxy_set_header        X-Real-IP $remote_addr;
+            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header        X-Forwarded-Proto $scheme;
+            proxy_pass              https://auth-service;
+            proxy_read_timeout      90;
+        }
+
+        location /resources {
+            proxy_set_header        Host $host;
+            proxy_set_header        X-Real-IP $remote_addr;
+            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header        X-Forwarded-Proto $scheme;
+            proxy_pass              https://auth-service;
+            proxy_read_timeout      90;
+        }
+
         location /api/search {
             proxy_set_header        Host $host;
             proxy_set_header        X-Real-IP $remote_addr;
diff --git a/helm/dbrepo/templates/ui-secret.yaml b/helm/dbrepo/templates/ui-secret.yaml
index 5620e7b2da88226759723c4bbd24f2e5479bc444..a84ac8f5cef024c88fa41ce085f494cca396df9f 100644
--- a/helm/dbrepo/templates/ui-secret.yaml
+++ b/helm/dbrepo/templates/ui-secret.yaml
@@ -22,4 +22,13 @@ stringData:
   NUXT_PUBLIC_PID_DEFAULT_PUBLISHER: "{{ .Values.ui.public.pid.default.publisher }}"
   NUXT_PUBLIC_UPLOAD_CLIENT: "{{ .Values.ui.public.upload.client | default $uploadEndpoint }}"
   NUXT_PUBLIC_BROKER_CONNECTIONS: "{{ include "dbrepo.broker.connections" . }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/auth"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_BASE_URL: "{{ .Values.gateway }}/realms/dbrepo"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "{{ .Values.authservice.client.id }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "{{ .Values.authservice.client.secret }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "{{ .Values.gateway }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/logout"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "{{ .Values.gateway }}/auth/keycloak/callback"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/token"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/userinfo"
 {{- end }}
diff --git a/helm/dbrepo/values.schema.json b/helm/dbrepo/values.schema.json
index 9ade1b07493e1aa92d11a726d38f869b4ad69461..641287b434aff0bf533a2416081a9d6c0e447742 100644
--- a/helm/dbrepo/values.schema.json
+++ b/helm/dbrepo/values.schema.json
@@ -126,7 +126,7 @@
                 "endpoint": {
                     "type": "string"
                 },
-                "extraEnvVarsCM": {
+                "extraEnvVarsSecret": {
                     "type": "string"
                 },
                 "extraVolumeMounts": {
@@ -137,6 +137,9 @@
                             },
                             "name": {
                                 "type": "string"
+                            },
+                            "subPath": {
+                                "type": "string"
                             }
                         },
                         "type": "object"
@@ -224,6 +227,9 @@
                     },
                     "type": "object"
                 },
+                "production": {
+                    "type": "boolean"
+                },
                 "replicaCount": {
                     "type": "integer"
                 },
diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml
index 34db1f569f07dd9198c5247505b3ba45a52a19f8..7515778b33d38b5e427a85742d5aa0d71b9e6a3a 100644
--- a/helm/dbrepo/values.yaml
+++ b/helm/dbrepo/values.yaml
@@ -87,6 +87,8 @@ authservice:
     fullnameOverride: auth-db
     auth:
       postgresPassword: postgres
+  ## @param authservice.production Start Keycloak with production profile.
+  production: true
   ## @param authservice.resourcesPreset The container resource presets
   resourcesPreset: "small"
   jwt:
@@ -116,7 +118,7 @@ authservice:
   setupJob:
     image:
       ## @skip authservice.setupJob.image.name
-      name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.1
+      name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.3
     ## @param authservice.setupJob.resourcesPreset The container resource preset
     resourcesPreset: "nano"
     ## @param authservice.setupJob.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
@@ -127,8 +129,8 @@ authservice:
     ##   limits:
     ##     cpu: 500m
     ##     memory: 1024Mi
-  ## @skip authservice.extraEnvVarsCM
-  extraEnvVarsCM: auth-service-config
+  ## @skip authservice.extraEnvVarsSecret
+  extraEnvVarsSecret: auth-service-secret
   ## @skip authservice.extraVolumes
   extraVolumes:
     - name: config-map
@@ -140,7 +142,14 @@ authservice:
   ## @skip authservice.extraVolumeMounts
   extraVolumeMounts:
     - name: config-map
-      mountPath: /opt/keycloak/data/import
+      mountPath: /opt/keycloak/data/import/dbrepo-realm.json
+      subPath: dbrepo-realm.json
+    - name: config-map
+      mountPath: /opt/keycloak/data/import/master-realm.json
+      subPath: master-realm.json
+    - name: config-map
+      mountPath: /opt/bitnami/keycloak/providers/create-event-listener.jar
+      subPath: create-event-listener.jar
     - name: cache
       mountPath: /bitnami/keycloak/
   ## @skip authservice.replicaCount The number of replicas.
@@ -392,7 +401,7 @@ analyseservice:
   enabled: true
   image:
     ## @skip analyseservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.1
+    name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param analyseservice.podSecurityContext.enabled Enable pods' Security Context
@@ -453,7 +462,7 @@ metadataservice:
   enabled: true
   image:
     ## @skip metadataservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.1
+    name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param metadataservice.podSecurityContext.enabled Enable pods' Security Context
@@ -550,7 +559,7 @@ dataservice:
   endpoint: http://data-service
   image:
     ## @skip dataservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.1
+    name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param dataservice.podSecurityContext.enabled Enable pods' Security Context
@@ -636,7 +645,7 @@ searchservice:
   endpoint: http://search-service
   image:
     ## @skip searchservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.1
+    name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param searchservice.podSecurityContext.enabled Enable pods' Security Context
@@ -683,7 +692,7 @@ searchservice:
   init:
     image:
       ## @skip searchservice.init.image.name
-      name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.1
+      name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
     ## @param searchservice.init.resourcesPreset The container resource preset
     resourcesPreset: "nano"
     ## @param searchservice.init.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
@@ -744,7 +753,7 @@ storageservice:
   init:
     image:
       ## @skip storageservice.init.image.name
-      name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.1
+      name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
     s3:
       ## @param storageservice.init.s3.endpoint The S3-capable endpoint the microservice connects to.
       endpoint: http://storage-service-s3:8333
@@ -853,7 +862,7 @@ ui:
   enabled: true
   image:
     ## @skip ui.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.1
+    name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param ui.podSecurityContext.enabled Enable pods' Security Context
@@ -941,7 +950,7 @@ ui:
       ## @param ui.public.doi.endpoint The DOI proxy.
       endpoint: https://doi.org
   ## @param ui.replicaCount The number of replicas.
-  replicaCount: 2
+  replicaCount: 1
   ## @skip ui.extraVolumes
   extraVolumes: [ ]
   #  - name: images-map
diff --git a/helm/seaweedfs/Chart.lock b/helm/seaweedfs/Chart.lock
index edcc38c41f0c6b2b35f8d740566918ddb16f17fc..96e5c8dce913d2f7a73bf8adc5d7f121fb2a3b70 100644
--- a/helm/seaweedfs/Chart.lock
+++ b/helm/seaweedfs/Chart.lock
@@ -1,12 +1,12 @@
 dependencies:
 - name: mariadb
   repository: oci://registry-1.docker.io/bitnamicharts
-  version: 20.2.1
+  version: 20.2.2
 - name: postgresql
   repository: oci://registry-1.docker.io/bitnamicharts
-  version: 16.4.3
+  version: 16.4.6
 - name: common
   repository: oci://registry-1.docker.io/bitnamicharts
-  version: 2.29.0
-digest: sha256:4c967f771b303ca0db9ba2e355790152448c77a05d3f6c69eda6c234bc3f60c6
-generated: "2025-01-17T15:24:18.141765362+01:00"
+  version: 2.29.1
+digest: sha256:bc14ae7bbe7be291adc4a6329ae64835c367b09277a2678c4e10cc74b19ee491
+generated: "2025-02-04T22:22:11.88596441+01:00"
diff --git a/helm/seaweedfs/charts/common-2.29.0.tgz b/helm/seaweedfs/charts/common-2.29.0.tgz
deleted file mode 100644
index f36e9e24ec32ce1237d1ee774541c5586fce222d..0000000000000000000000000000000000000000
Binary files a/helm/seaweedfs/charts/common-2.29.0.tgz and /dev/null differ
diff --git a/helm/seaweedfs/charts/common-2.29.1.tgz b/helm/seaweedfs/charts/common-2.29.1.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..8b9abbbc5b6c62a743cc0fb041d26b199c4313c8
Binary files /dev/null and b/helm/seaweedfs/charts/common-2.29.1.tgz differ
diff --git a/helm/seaweedfs/charts/mariadb-20.2.1.tgz b/helm/seaweedfs/charts/mariadb-20.2.1.tgz
deleted file mode 100644
index 9bba8eed49e866977396c0076b1a9c5946ec88b1..0000000000000000000000000000000000000000
Binary files a/helm/seaweedfs/charts/mariadb-20.2.1.tgz and /dev/null differ
diff --git a/helm/seaweedfs/charts/mariadb-20.2.2.tgz b/helm/seaweedfs/charts/mariadb-20.2.2.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..a983469f30dfce693288215705891f387c517319
Binary files /dev/null and b/helm/seaweedfs/charts/mariadb-20.2.2.tgz differ
diff --git a/helm/seaweedfs/charts/postgresql-16.4.3.tgz b/helm/seaweedfs/charts/postgresql-16.4.3.tgz
deleted file mode 100644
index 429f7ed063f6655796792fbe711b027e147ddda4..0000000000000000000000000000000000000000
Binary files a/helm/seaweedfs/charts/postgresql-16.4.3.tgz and /dev/null differ
diff --git a/helm/seaweedfs/charts/postgresql-16.4.6.tgz b/helm/seaweedfs/charts/postgresql-16.4.6.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..9016ba352dfd2b553e3cac4a8a80fb7c8c539d65
Binary files /dev/null and b/helm/seaweedfs/charts/postgresql-16.4.6.tgz differ
diff --git a/install.sh b/install.sh
index 710e9d55a1d65ba99d66a1540180548614464559..fa48d9bc35c83375ca02c9810b7e6a0ee780af21 100644
--- a/install.sh
+++ b/install.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # preset
-VERSION="1.6.1"
+VERSION="1.6.3"
 MIN_CPU=8
 MIN_RAM=4
 MIN_MAP_COUNT=262144
diff --git a/lib/python/Pipfile b/lib/python/Pipfile
index b54561e5f8ff11eb4706050946f23f4a4004fdb5..62a93cc02a1d043464485a4506adcf65ca2160a2 100644
--- a/lib/python/Pipfile
+++ b/lib/python/Pipfile
@@ -13,6 +13,7 @@ pandas = "*"
 
 [dev-packages]
 build = "*"
+pyyaml = "*"
 setuptools = "*"
 twine = "*"
 coverage = "*"
diff --git a/lib/python/Pipfile.lock b/lib/python/Pipfile.lock
index 836140fd7bff162440f0e8fdd3ab3ef5d2c4a316..52b7202c3e6e17d9651d8851a66dc925f010a4df 100644
--- a/lib/python/Pipfile.lock
+++ b/lib/python/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "4fc272b993d5091dc8d60aee49575f17cd1de3145d916dc6aa82c09f7cefe4ee"
+            "sha256": "01e7f752292f6f3d558a9418f7172696f9bd200d00c7eed2745b74d08ef27eb4"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -442,64 +442,64 @@
         },
         "numpy": {
             "hashes": [
-                "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2",
-                "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5",
-                "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60",
-                "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71",
-                "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631",
-                "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8",
-                "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2",
-                "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16",
-                "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa",
-                "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591",
-                "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964",
-                "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821",
-                "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484",
-                "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957",
-                "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800",
-                "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918",
-                "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95",
-                "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0",
-                "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e",
-                "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d",
-                "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73",
-                "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59",
-                "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51",
-                "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355",
-                "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348",
-                "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e",
-                "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440",
-                "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675",
-                "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84",
-                "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046",
-                "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab",
-                "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712",
-                "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308",
-                "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315",
-                "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3",
-                "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008",
-                "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5",
-                "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2",
-                "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e",
-                "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7",
-                "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf",
-                "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab",
-                "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd",
-                "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf",
-                "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8",
-                "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb",
-                "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268",
-                "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d",
-                "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780",
-                "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716",
-                "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e",
-                "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528",
-                "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af",
-                "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7",
-                "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51"
+                "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f",
+                "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0",
+                "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd",
+                "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2",
+                "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4",
+                "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648",
+                "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be",
+                "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb",
+                "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160",
+                "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd",
+                "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a",
+                "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84",
+                "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e",
+                "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748",
+                "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825",
+                "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60",
+                "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957",
+                "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715",
+                "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317",
+                "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e",
+                "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283",
+                "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278",
+                "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9",
+                "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de",
+                "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369",
+                "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb",
+                "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189",
+                "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014",
+                "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323",
+                "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e",
+                "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49",
+                "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50",
+                "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d",
+                "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37",
+                "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39",
+                "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576",
+                "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a",
+                "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba",
+                "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7",
+                "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826",
+                "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467",
+                "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495",
+                "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc",
+                "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391",
+                "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0",
+                "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97",
+                "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c",
+                "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac",
+                "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369",
+                "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8",
+                "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2",
+                "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff",
+                "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a",
+                "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df",
+                "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f"
             ],
             "markers": "python_version == '3.11'",
-            "version": "==2.2.1"
+            "version": "==2.2.2"
         },
         "paho-mqtt": {
             "hashes": [
@@ -655,11 +655,11 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d",
-                "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"
+                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
+                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
             ],
             "index": "pypi",
-            "version": "==2.10.4"
+            "version": "==2.10.5"
         },
         "pydantic-core": {
             "hashes": [
@@ -824,11 +824,11 @@
         },
         "tzdata": {
             "hashes": [
-                "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc",
-                "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"
+                "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694",
+                "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"
             ],
             "markers": "python_version >= '2'",
-            "version": "==2024.2"
+            "version": "==2025.1"
         },
         "urllib3": {
             "hashes": [
@@ -1266,6 +1266,14 @@
             "index": "pypi",
             "version": "==2024.8.6"
         },
+        "id": {
+            "hashes": [
+                "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d",
+                "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==1.5.0"
+        },
         "idna": {
             "hashes": [
                 "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
@@ -1284,11 +1292,11 @@
         },
         "importlib-metadata": {
             "hashes": [
-                "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
-                "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"
+                "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e",
+                "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"
             ],
             "markers": "python_version < '3.12'",
-            "version": "==8.5.0"
+            "version": "==8.6.1"
         },
         "iniconfig": {
             "hashes": [
@@ -1431,11 +1439,11 @@
         },
         "more-itertools": {
             "hashes": [
-                "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef",
-                "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"
+                "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b",
+                "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"
             ],
-            "markers": "python_version >= '3.8'",
-            "version": "==10.5.0"
+            "markers": "python_version >= '3.9'",
+            "version": "==10.6.0"
         },
         "nh3": {
             "hashes": [
@@ -1475,14 +1483,6 @@
             "markers": "python_version >= '3.8'",
             "version": "==24.2"
         },
-        "pkginfo": {
-            "hashes": [
-                "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf",
-                "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"
-            ],
-            "markers": "python_version >= '3.8'",
-            "version": "==1.12.0"
-        },
         "pluggy": {
             "hashes": [
                 "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1",
@@ -1501,11 +1501,11 @@
         },
         "pygments": {
             "hashes": [
-                "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
-                "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"
+                "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f",
+                "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.18.0"
+            "version": "==2.19.1"
         },
         "pyproject-hooks": {
             "hashes": [
@@ -1532,6 +1532,65 @@
             "index": "pypi",
             "version": "==0.6"
         },
+        "pyyaml": {
+            "hashes": [
+                "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff",
+                "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48",
+                "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086",
+                "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e",
+                "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133",
+                "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5",
+                "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484",
+                "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee",
+                "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5",
+                "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68",
+                "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a",
+                "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf",
+                "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99",
+                "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8",
+                "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85",
+                "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19",
+                "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc",
+                "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a",
+                "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1",
+                "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317",
+                "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c",
+                "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631",
+                "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d",
+                "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652",
+                "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5",
+                "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e",
+                "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b",
+                "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8",
+                "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476",
+                "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706",
+                "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563",
+                "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237",
+                "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b",
+                "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083",
+                "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180",
+                "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425",
+                "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e",
+                "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f",
+                "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725",
+                "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183",
+                "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab",
+                "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774",
+                "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725",
+                "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e",
+                "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5",
+                "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d",
+                "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290",
+                "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44",
+                "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed",
+                "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4",
+                "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba",
+                "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12",
+                "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"
+            ],
+            "index": "pypi",
+            "version": "==6.0.2"
+        },
         "readme-renderer": {
             "hashes": [
                 "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151",
@@ -1590,11 +1649,11 @@
         },
         "setuptools": {
             "hashes": [
-                "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6",
-                "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"
+                "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6",
+                "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"
             ],
             "index": "pypi",
-            "version": "==75.6.0"
+            "version": "==75.8.0"
         },
         "snowballstemmer": {
             "hashes": [
@@ -1677,11 +1736,11 @@
         },
         "twine": {
             "hashes": [
-                "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27",
-                "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"
+                "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384",
+                "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"
             ],
             "index": "pypi",
-            "version": "==6.0.1"
+            "version": "==6.1.0"
         },
         "urllib3": {
             "hashes": [
diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py
index bc6940b7d034bcb85fec9f9c31c3b5a8aff0dcc3..a0b4bf60c43f2065ffd2f73f5010407fb0d20287 100644
--- a/lib/python/dbrepo/RestClient.py
+++ b/lib/python/dbrepo/RestClient.py
@@ -252,7 +252,7 @@ class RestClient:
                                 f'201 (CREATED): {response.text}')
 
     def update_user(self, user_id: str, theme: str, language: str, firstname: str = None, lastname: str = None,
-                    affiliation: str = None, orcid: str = None) -> User:
+                    affiliation: str = None, orcid: str = None) -> UserBrief:
         """
         Updates a user with given user id.
 
@@ -277,7 +277,7 @@ class RestClient:
                                                     lastname=lastname, affiliation=affiliation, orcid=orcid))
         if response.status_code == 202:
             body = response.json()
-            return User.model_validate(body)
+            return UserBrief.model_validate(body)
         if response.status_code == 400:
             raise MalformedError(f'Failed to update user: {response.text}')
         if response.status_code == 403:
@@ -287,15 +287,13 @@ class RestClient:
         raise ResponseCodeError(f'Failed to update user: response code: {response.status_code} is not '
                                 f'202 (ACCEPTED): {response.text}')
 
-    def update_user_password(self, user_id: str, password: str) -> User:
+    def update_user_password(self, user_id: str, password: str) -> None:
         """
         Updates the password of a user with given user id.
 
         :param user_id: The user id of the user that should be updated.
         :param password: The updated user password.
 
-        :returns: The user, if successful.
-
         :raises MalformedError: If the payload was rejected by the service.
         :raises ForbiddenError: If something went wrong with the authorization.
         :raises NotExistsError: If the user does not exist.
@@ -306,8 +304,7 @@ class RestClient:
         url = f'/api/user/{user_id}/password'
         response = self._wrapper(method="put", url=url, force_auth=True, payload=UpdateUserPassword(password=password))
         if response.status_code == 202:
-            body = response.json()
-            return User.model_validate(body)
+            return None
         if response.status_code == 400:
             raise MalformedError(f'Failed to update user password: {response.text}')
         if response.status_code == 403:
@@ -617,7 +614,7 @@ class RestClient:
 
     def create_table(self, database_id: int, name: str, is_public: bool, is_schema_public: bool,
                      columns: List[CreateTableColumn], constraints: CreateTableConstraints,
-                     description: str = None) -> Table:
+                     description: str = None) -> TableBrief:
         """
         Updates the database owner of a database with given database id.
 
@@ -645,7 +642,7 @@ class RestClient:
                                                      description=description, columns=columns, constraints=constraints))
         if response.status_code == 201:
             body = response.json()
-            return Table.model_validate(body)
+            return TableBrief.model_validate(body)
         if response.status_code == 400:
             raise MalformedError(f'Failed to create table: {response.text}')
         if response.status_code == 403:
@@ -871,7 +868,7 @@ class RestClient:
         raise ResponseCodeError(f'Failed to find view: response code: {response.status_code} is not '
                                 f'200 (OK): {response.text}')
 
-    def update_view(self, database_id: int, view_id: int, is_public: bool) -> View:
+    def update_view(self, database_id: int, view_id: int, is_public: bool) -> ViewBrief:
         """
         Get a view of a database with given database id and view id.
 
@@ -889,7 +886,7 @@ class RestClient:
         response = self._wrapper(method="put", url=url, payload=UpdateView(is_public=is_public))
         if response.status_code == 202:
             body = response.json()
-            return View.model_validate(body)
+            return ViewBrief.model_validate(body)
         if response.status_code == 403:
             raise ForbiddenError(f'Failed to update view: not allowed')
         if response.status_code == 404:
@@ -1091,7 +1088,7 @@ class RestClient:
         :raises ResponseCodeError: If something went wrong with the insert.
         """
         url = f'/api/database/{database_id}/table/{table_id}/data'
-        response = self._wrapper(method="post", url=url, force_auth=True, payload=CreateData(data=data))
+        response = self._wrapper(method="post", url=url, force_auth=True, payload=Tuple(data=data))
         if response.status_code == 201:
             return
         if response.status_code == 400:
@@ -1279,7 +1276,7 @@ class RestClient:
         :raises ResponseCodeError: If something went wrong with the update.
         """
         url = f'/api/database/{database_id}/table/{table_id}/data'
-        response = self._wrapper(method="put", url=url, force_auth=True, payload=UpdateData(data=data, keys=keys))
+        response = self._wrapper(method="put", url=url, force_auth=True, payload=TupleUpdate(data=data, keys=keys))
         if response.status_code == 202:
             return
         if response.status_code == 400:
@@ -1309,7 +1306,7 @@ class RestClient:
         :raises ResponseCodeError: If something went wrong with the deletion.
         """
         url = f'/api/database/{database_id}/table/{table_id}/data'
-        response = self._wrapper(method="delete", url=url, force_auth=True, payload=DeleteData(keys=keys))
+        response = self._wrapper(method="delete", url=url, force_auth=True, payload=TupleDelete(keys=keys))
         if response.status_code == 202:
             return
         if response.status_code == 400:
@@ -1770,13 +1767,13 @@ class RestClient:
         raise ResponseCodeError(f'Failed to update query: response code: {response.status_code} is not '
                                 f'202 (ACCEPTED): {response.text}')
 
-    def create_identifier(self, database_id: int, type: IdentifierType, titles: List[CreateIdentifierTitle],
+    def create_identifier(self, database_id: int, type: IdentifierType, titles: List[SaveIdentifierTitle],
                           publisher: str, creators: List[CreateIdentifierCreator], publication_year: int,
-                          descriptions: List[CreateIdentifierDescription] = None,
-                          funders: List[CreateIdentifierFunder] = None, licenses: List[License] = None,
+                          descriptions: List[SaveIdentifierDescription] = None,
+                          funders: List[SaveIdentifierFunder] = None, licenses: List[License] = None,
                           language: Language = None, subset_id: int = None, view_id: int = None, table_id: int = None,
                           publication_day: int = None, publication_month: int = None,
-                          related_identifiers: List[CreateRelatedIdentifier] = None) -> Identifier:
+                          related_identifiers: List[SaveRelatedIdentifier] = None) -> Identifier:
         """
         Create an identifier draft.
 
@@ -1831,12 +1828,12 @@ class RestClient:
                                 f'201 (CREATED): {response.text}')
 
     def save_identifier(self, identifier_id: int, database_id: int, type: IdentifierType,
-                        titles: List[CreateIdentifierTitle], publisher: str, creators: List[CreateIdentifierCreator],
-                        publication_year: int, descriptions: List[CreateIdentifierDescription] = None,
-                        funders: List[CreateIdentifierFunder] = None, licenses: List[License] = None,
+                        titles: List[SaveIdentifierTitle], publisher: str, creators: List[CreateIdentifierCreator],
+                        publication_year: int, descriptions: List[SaveIdentifierDescription] = None,
+                        funders: List[SaveIdentifierFunder] = None, licenses: List[License] = None,
                         language: Language = None, subset_id: int = None, view_id: int = None, table_id: int = None,
                         publication_day: int = None, publication_month: int = None,
-                        related_identifiers: List[CreateRelatedIdentifier] = None) -> Identifier:
+                        related_identifiers: List[SaveRelatedIdentifier] = None) -> Identifier:
         """
         Save an existing identifier and update the metadata attached to it.
 
diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py
index fa7eb063fc453c3dd8fabef04f141d07012c94a3..bd0d13dc1894d1a83891abdcdd6fb438de27f3f4 100644
--- a/lib/python/dbrepo/api/dto.py
+++ b/lib/python/dbrepo/api/dto.py
@@ -113,18 +113,18 @@ class ContainerBrief(BaseModel):
 class ColumnBrief(BaseModel):
     id: int
     name: str
-    alias: str
     database_id: int
     table_id: int
     internal_name: str
     type: ColumnType
+    alias: Optional[str] = None
 
 
 class TableBrief(BaseModel):
     id: int
     database_id: int
     name: str
-    description: Optional[str]
+    description: Optional[str] = None
     internal_name: str
     is_versioned: bool
     is_public: bool
@@ -419,7 +419,7 @@ class IdentifierTitle(BaseModel):
     type: Optional[TitleType] = None
 
 
-class CreateIdentifierTitle(BaseModel):
+class SaveIdentifierTitle(BaseModel):
     title: str
     language: Optional[Language] = None
     type: Optional[TitleType] = None
@@ -432,7 +432,7 @@ class IdentifierDescription(BaseModel):
     type: Optional[DescriptionType] = None
 
 
-class CreateIdentifierDescription(BaseModel):
+class SaveIdentifierDescription(BaseModel):
     description: str
     language: Optional[Language] = None
     type: Optional[DescriptionType] = None
@@ -448,7 +448,7 @@ class IdentifierFunder(BaseModel):
     award_title: Optional[str] = None
 
 
-class CreateIdentifierFunder(BaseModel):
+class SaveIdentifierFunder(BaseModel):
     funder_name: str
     funder_identifier: Optional[str] = None
     funder_identifier_type: Optional[str] = None
@@ -463,16 +463,16 @@ class License(BaseModel):
     description: str
 
 
-class CreateData(BaseModel):
+class Tuple(BaseModel):
     data: dict
 
 
-class UpdateData(BaseModel):
+class TupleUpdate(BaseModel):
     data: dict
     keys: dict
 
 
-class DeleteData(BaseModel):
+class TupleDelete(BaseModel):
     keys: dict
 
 
@@ -511,6 +511,7 @@ class CreateTableColumn(BaseModel):
     name: str
     type: ColumnType
     null_allowed: bool
+    description: Optional[str] = None
     concept_uri: Optional[str] = None
     unit_uri: Optional[str] = None
     index_length: Optional[int] = None
@@ -527,7 +528,26 @@ class CreateTableConstraints(BaseModel):
     foreign_keys: List[CreateForeignKey] = field(default_factory=list)
 
 
-class IdentifierCreator(BaseModel):
+class NameIdentifierSchemeType(str, Enum):
+    """
+    Enumeration of name identifier scheme types.
+    """
+    ORCID = "ORCID"
+    ROR = "ROR"
+    ISNI = "ISNI"
+    GRID = "GRID"
+
+
+class AffiliationIdentifierSchemeType(str, Enum):
+    """
+    Enumeration of affiliation identifier scheme types.
+    """
+    ROR = "ROR"
+    ISNI = "ISNI"
+    GRID = "GRID"
+
+
+class Creator(BaseModel):
     id: int
     creator_name: str
     firstname: Optional[str] = None
@@ -535,13 +555,24 @@ class IdentifierCreator(BaseModel):
     affiliation: Optional[str] = None
     name_type: Optional[str] = None
     name_identifier: Optional[str] = None
-    name_identifier_scheme: Optional[str] = None
+    name_identifier_scheme: Optional[NameIdentifierSchemeType] = None
     name_identifier_scheme_uri: Optional[str] = None
     affiliation_identifier: Optional[str] = None
     affiliation_identifier_scheme: Optional[str] = None
     affiliation_identifier_scheme_uri: Optional[str] = None
 
 
+class CreatorBrief(BaseModel):
+    id: int
+    creator_name: str
+    affiliation: Optional[str] = None
+    name_type: Optional[str] = None
+    name_identifier: Optional[str] = None
+    name_identifier_scheme: Optional[NameIdentifierSchemeType] = None
+    affiliation_identifier: Optional[str] = None
+    affiliation_identifier_scheme: Optional[str] = None
+
+
 class CreateIdentifierCreator(BaseModel):
     creator_name: str
     firstname: Optional[str] = None
@@ -563,7 +594,7 @@ class RelatedIdentifier(BaseModel):
     relation: RelatedIdentifierRelation
 
 
-class CreateRelatedIdentifier(BaseModel):
+class SaveRelatedIdentifier(BaseModel):
     value: str
     type: RelatedIdentifierType
     relation: RelatedIdentifierRelation
@@ -575,9 +606,9 @@ class CreateIdentifier(BaseModel):
     creators: List[CreateIdentifierCreator]
     publication_year: int
     publisher: str
-    titles: List[CreateIdentifierTitle]
-    descriptions: List[CreateIdentifierDescription]
-    funders: Optional[List[CreateIdentifierFunder]] = field(default_factory=list)
+    titles: List[SaveIdentifierTitle]
+    descriptions: List[SaveIdentifierDescription]
+    funders: Optional[List[SaveIdentifierFunder]] = field(default_factory=list)
     doi: Optional[str] = None
     language: Optional[str] = None
     licenses: Optional[List[License]] = field(default_factory=list)
@@ -587,7 +618,7 @@ class CreateIdentifier(BaseModel):
     query: Optional[str] = None
     query_normalized: Optional[str] = None
     execution: Optional[str] = None
-    related_identifiers: Optional[List[CreateRelatedIdentifier]] = field(default_factory=list)
+    related_identifiers: Optional[List[SaveRelatedIdentifier]] = field(default_factory=list)
     result_hash: Optional[str] = None
     result_number: Optional[int] = None
     publication_day: Optional[int] = None
@@ -602,7 +633,7 @@ class Identifier(BaseModel):
     status: IdentifierStatusType
     publication_year: int
     publisher: str
-    creators: List[IdentifierCreator]
+    creators: List[Creator]
     titles: List[IdentifierTitle]
     descriptions: List[IdentifierDescription]
     funders: Optional[List[IdentifierFunder]] = field(default_factory=list)
@@ -622,6 +653,21 @@ class Identifier(BaseModel):
     publication_month: Optional[int] = None
 
 
+class IdentifierBrief(BaseModel):
+    id: int
+    database_id: int
+    type: IdentifierType
+    owned_by: str
+    status: IdentifierStatusType
+    publication_year: int
+    publisher: str
+    titles: List[IdentifierTitle]
+    doi: Optional[str] = None
+    query_id: Optional[int] = None
+    table_id: Optional[int] = None
+    view_id: Optional[int] = None
+
+
 class View(BaseModel):
     id: int
     database_id: int
@@ -856,7 +902,7 @@ class Query(BaseModel):
     result_hash: str
     query_normalized: str
     result_number: Optional[int] = None
-    identifiers: List[Identifier] = field(default_factory=list)
+    identifiers: List[IdentifierBrief] = field(default_factory=list)
 
 
 class UpdateQuery(BaseModel):
@@ -950,15 +996,17 @@ class Table(BaseModel):
     avg_row_length: Optional[int] = None
 
 
-class TableMinimal(BaseModel):
-    id: int
-    database_id: int
-
-
-class ColumnMinimal(BaseModel):
+class DatabaseBrief(BaseModel):
     id: int
-    table_id: int
-    database_id: int
+    name: str
+    contact: UserBrief
+    owner_id: str
+    internal_name: str
+    is_public: bool
+    is_schema_public: bool
+    identifiers: Optional[List[IdentifierBrief]] = field(default_factory=list)
+    preview_image: Optional[str] = None
+    description: Optional[str] = None
 
 
 class Database(BaseModel):
@@ -973,37 +1021,25 @@ class Database(BaseModel):
     container: ContainerBrief
     identifiers: Optional[List[Identifier]] = field(default_factory=list)
     subsets: Optional[List[Identifier]] = field(default_factory=list)
+    preview_image: Optional[str] = None
     description: Optional[str] = None
     tables: Optional[List[Table]] = field(default_factory=list)
     views: Optional[List[View]] = field(default_factory=list)
-    image: Optional[str] = None
     accesses: Optional[List[DatabaseAccess]] = field(default_factory=list)
-    exchange_type: Optional[str] = None
-
-
-class DatabaseBrief(BaseModel):
-    id: int
-    name: str
-    internal_name: str
-    description: Optional[str] = None
-    is_public: bool
-    is_schema_public: bool
-    identifiers: Optional[List[Identifier]] = field(default_factory=list)
-    contact: UserBrief
-    owner_id: str
+    exchange_name: Optional[str] = None
 
 
 class Unique(BaseModel):
     id: int
-    table: TableMinimal
-    columns: List[ColumnMinimal]
+    table: TableBrief
+    columns: List[ColumnBrief]
 
 
 class ForeignKeyReference(BaseModel):
     id: int
-    foreign_key: ForeignKeyMinimal
-    column: ColumnMinimal
-    referenced_column: ColumnMinimal
+    foreign_key: ForeignKeyBrief
+    column: ColumnBrief
+    referenced_column: ColumnBrief
 
 
 class ReferenceType(str, Enum):
@@ -1017,7 +1053,7 @@ class ReferenceType(str, Enum):
     SET_DEFAULT = "set_default"
 
 
-class ForeignKeyMinimal(BaseModel):
+class ForeignKeyBrief(BaseModel):
     id: int
 
 
@@ -1025,8 +1061,8 @@ class ForeignKey(BaseModel):
     id: int
     name: str
     references: List[ForeignKeyReference]
-    table: TableMinimal
-    referenced_table: TableMinimal
+    table: TableBrief
+    referenced_table: TableBrief
     on_update: Optional[ReferenceType] = None
     on_delete: Optional[ReferenceType] = None
 
@@ -1041,8 +1077,8 @@ class CreateForeignKey(BaseModel):
 
 class PrimaryKey(BaseModel):
     id: int
-    table: TableMinimal
-    column: ColumnMinimal
+    table: TableBrief
+    column: ColumnBrief
 
 
 class Constraints(BaseModel):
diff --git a/lib/python/docs/index.rst b/lib/python/docs/index.rst
index 0a989f321fa9dbb644fba8c668cff807a1232826..b3c05fe3645e558aaa92a470c19be4d27db46add 100644
--- a/lib/python/docs/index.rst
+++ b/lib/python/docs/index.rst
@@ -6,7 +6,7 @@ Pandas `DataFrame <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame
 provides an object-oriented API as well as low-level access to DBRepo services.
 
 .. note::
-   The SDK has been implemented and documented for DBRepo version 1.6.1, earlier versions may be supported but are not tested for compatibility.
+   The SDK has been implemented and documented for DBRepo version 1.6.3, earlier versions may be supported but are not tested for compatibility.
 
 Quickstart
 ----------
diff --git a/lib/python/pyproject.toml b/lib/python/pyproject.toml
index 33d1e52cc0a967a56e7e0a9ce639e5ceb53b42c6..99f62c9a44dcdb10f63d03c97048a0676a1b1d02 100644
--- a/lib/python/pyproject.toml
+++ b/lib/python/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "dbrepo"
-version = "1.6.1"
+version = "1.6.3"
 description = "DBRepo Python Library"
 keywords = [
     "DBRepo",
diff --git a/lib/python/setup.py b/lib/python/setup.py
index 027b8a5bb628da1cd03378d59d44ff8dc507c9a7..dfe9a897cab556846dbf7dfb6ffb5303d0e77b03 100644
--- a/lib/python/setup.py
+++ b/lib/python/setup.py
@@ -2,7 +2,7 @@
 from distutils.core import setup
 
 setup(name="dbrepo",
-      version="1.6.1",
+      version="1.6.3",
       description="A library for communicating with DBRepo",
       url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/",
       author="Martin Weise",
diff --git a/lib/python/tests/conftest.py b/lib/python/tests/conftest.py
deleted file mode 100644
index 5270a5bfba0c614fc3e16b559879dd6209f440dc..0000000000000000000000000000000000000000
--- a/lib/python/tests/conftest.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import logging
-import uuid
-
-import pytest
-
-from dbrepo.RestClient import RestClient
-from dbrepo.api.dto import Database
-
-logging.basicConfig(level=logging.DEBUG)
-
-
-def pytest_configure(config):
-    TestKeyValue.username = str(uuid.uuid4()).replace("-", "")[0:10]
-    TestKeyValue.password = str(uuid.uuid4()).replace("-", "")[0:10]
-
-
-@pytest.fixture(scope='session', name='rest_client')
-def user_rest_client() -> RestClient:
-    TestKeyValue.user_id = RestClient().create_user(username=f'{TestKeyValue.username}',
-                                                    password=f'{TestKeyValue.password}',
-                                                    email=f'{TestKeyValue.username}@example.com').id
-    return RestClient(username=TestKeyValue.username, password=TestKeyValue.password)
-
-
-@pytest.fixture(scope='session', name='database')
-def database() -> Database:
-    name = str(uuid.uuid4()).replace("-", "")[0:10]
-    return RestClient(username=TestKeyValue.username,
-                      password=TestKeyValue.password).create_database(name=name, container_id=1, is_public=True,
-                                                                      is_schema_public=True)
-
-
-class TestKeyValue:
-    user_id: str = None
-    username: str = None
-    password: str = None
-    database_name: str = None
diff --git a/lib/python/tests/test_dtos.py b/lib/python/tests/test_dtos.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f05e24081b45deb662afed4a3b342803b6ce56a
--- /dev/null
+++ b/lib/python/tests/test_dtos.py
@@ -0,0 +1,94 @@
+import inspect
+import logging
+import sys
+import unittest
+from logging.config import dictConfig
+from math import floor
+
+from yaml import safe_load
+
+from dbrepo.api import dto
+
+logging.addLevelName(level=logging.NOTSET, levelName='TRACE')
+logging.basicConfig(level=logging.DEBUG)
+
+# logging configuration
+dictConfig({
+    'version': 1,
+    'formatters': {
+        'default': {
+            'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
+        },
+        'simple': {
+            'format': '[%(asctime)s] %(levelname)s: %(message)s',
+        },
+    },
+    'handlers': {'console': {
+        'class': 'logging.StreamHandler',
+        'stream': 'ext://sys.stdout',
+        'formatter': 'simple'  # default
+    }},
+    'root': {
+        'level': 'DEBUG',
+        'handlers': ['console']
+    }
+})
+
+
+class AnalyseUnitTest(unittest.TestCase):
+    schemas = None
+    models: [()] = []
+    found: int = 0
+    skipped: [str] = []
+
+    def setUp(self):
+        with open('../../.docs/.openapi/api.yaml') as fh:
+            self.schemas = safe_load(fh)['components']['schemas']
+            for name, obj in inspect.getmembers(sys.modules[dto.__name__]):
+                self.found += 1
+                if not inspect.isclass(obj):
+                    continue
+                if f'{name}Dto' not in self.schemas:
+                    logging.debug(f'skip model {name}: OpenAPI schema definition {name}Dto not found')
+                    self.skipped.append(f'{name}Dto')
+                    continue
+                self.models.append((name, obj))
+
+    def build_model(self, name: str, obj: any, definition: any) -> dict:
+        model_dict = dict()
+        for property in definition['properties']:
+            if 'example' in definition['properties'][property]:
+                if '$ref' not in definition['properties'][property]:
+                    model_dict[property] = definition['properties'][property]['example']
+                    continue
+                ref = definition['properties'][property]['$ref'][len('#/components/schemas/'):-3]
+                # recursive call
+                model_dict[property] = self.build_model(ref, self.get_model(ref), self.schemas[f'{ref}Dto'])
+                continue
+            if 'items' in definition['properties'][property]:
+                if '$ref' not in definition['properties'][property]['items']:
+                    continue
+                ref = definition['properties'][property]['items']['$ref'][len('#/components/schemas/'):-3]
+                # recursive call
+                model_dict[property] = [self.build_model(ref, self.get_model(ref), self.schemas[f'{ref}Dto'])]
+                continue
+            if '$ref' in definition['properties'][property]:
+                ref = definition['properties'][property]['$ref'][len('#/components/schemas/'):-3]
+                # recursive call
+                model_dict[property] = self.build_model(ref, self.get_model(ref), self.schemas[f'{ref}Dto'])
+        return model_dict
+
+    def get_model(self, ref: str):
+        for name, obj in self.models:
+            if name == ref:
+                return obj
+        return None
+
+    def test_dtos_succeeds(self):
+        logging.info(f'Found {self.found} model(s) in {dto.__name__}')
+        for name, obj in self.models:
+            logging.debug(f'building model: {name} against OpenAPI schema definition {name}Dto')
+            model = obj(**self.build_model(name, obj, self.schemas[f'{name}Dto']))
+        logging.warning(f'Unable to find {len(self.skipped)} OpenAPI schema definition(s): {self.skipped}')
+        logging.info(f'Coverage: {floor((1 - len(self.skipped) / self.found) * 100)}%')
+        pass
diff --git a/lib/python/tests/test_system_database.py b/lib/python/tests/test_system_database.py
deleted file mode 100644
index 902b95435b09c755fa33cd592fbd7a9c9ddc81ee..0000000000000000000000000000000000000000
--- a/lib/python/tests/test_system_database.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import unittest
-import uuid
-
-import pytest
-
-
-class UserUnitTest(unittest.TestCase):
-
-    @pytest.fixture(autouse=True)
-    def prepare_fixture(self, rest_client, database):
-        self.rest_client = rest_client
-        self.database = database
-
-    @pytest.mark.usefixtures("rest_client")
-    def test_create_database_succeeds(self):
-        name = str(uuid.uuid4()).replace("-", "")[0:10]
-        # test
-        response = self.rest_client.create_database(name=name, container_id=1,
-                                                    is_public=True, is_schema_public=True)
-        self.assertEqual(True, response.is_public)
-        self.assertEqual(True, response.is_schema_public)
-        self.assertEqual(None, response.description)
-
-    @pytest.mark.usefixtures("rest_client", "database")
-    def test_update_database_visibility_succeeds(self):
-        # test
-        response = self.rest_client.update_database_visibility(database_id=self.database.id, is_public=False,
-                                                               is_schema_public=False)
-        self.assertEqual(False, response.is_public)
-        self.assertEqual(False, response.is_schema_public)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/lib/python/tests/test_system_user.py b/lib/python/tests/test_system_user.py
deleted file mode 100644
index 350b34110274b4697f58cf6ce96168fb6682315c..0000000000000000000000000000000000000000
--- a/lib/python/tests/test_system_user.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import unittest
-import uuid
-
-import pytest
-
-from conftest import TestKeyValue
-from dbrepo.RestClient import RestClient
-
-
-class UserUnitTest(unittest.TestCase):
-
-    @pytest.fixture(autouse=True)
-    def prepare_fixture(self, rest_client):
-        self.rest_client = rest_client
-
-    def test_get_users_succeeds(self):
-        # test
-        response = RestClient().get_users()
-
-    def test_create_user_succeeds(self):
-        username = str(uuid.uuid4()).replace("-", "")[0:10]
-        password = str(uuid.uuid4()).replace("-", "")[0:10]
-        # test
-        response = RestClient().create_user(username=f'{username}', password=f'{password}',
-                                            email=f'{username}@example.com')
-        self.assertEqual(username, response.username)
-
-    @pytest.mark.usefixtures("rest_client")
-    def test_update_user_succeeds(self):
-        # test
-        response = self.rest_client.update_user(user_id=TestKeyValue.user_id, theme='dark', language='de',
-                                                firstname='Foo', lastname='Bar', affiliation='TU Wien',
-                                                orcid='https://orcid.org/0000-0003-4216-302X')
-        self.assertEqual('dark', response.attributes.theme)
-        self.assertEqual('Foo', response.given_name)
-        self.assertEqual('Bar', response.family_name)
-        self.assertEqual('TU Wien', response.attributes.affiliation)
-        self.assertEqual('https://orcid.org/0000-0003-4216-302X', response.attributes.orcid)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/lib/python/tests/test_unit_analyse.py b/lib/python/tests/test_unit_analyse.py
index a26d7aa8441fd716640ca1d71c65a26f45f154ff..5ca2b8301cbb04f9e896436909c97b4873842612 100644
--- a/lib/python/tests/test_unit_analyse.py
+++ b/lib/python/tests/test_unit_analyse.py
@@ -1,6 +1,5 @@
 import unittest
 import requests_mock
-import dataclasses
 
 from dbrepo.RestClient import RestClient
 
diff --git a/lib/python/tests/test_unit_database.py b/lib/python/tests/test_unit_database.py
index eeeea68832ac33e2f013a3c2deaa3d4eec33122c..203c296b9c86d9bca0fce4f3b433af298f6cd251 100644
--- a/lib/python/tests/test_unit_database.py
+++ b/lib/python/tests/test_unit_database.py
@@ -4,7 +4,7 @@ import requests_mock
 from pydantic_core import ValidationError
 
 from dbrepo.RestClient import RestClient
-from dbrepo.api.dto import Database, Container, Image, DatabaseAccess, AccessType, DatabaseBrief, UserBrief, \
+from dbrepo.api.dto import Database, DatabaseAccess, AccessType, DatabaseBrief, UserBrief, \
     ContainerBrief, ImageBrief
 from dbrepo.api.exceptions import ResponseCodeError, NotExistsError, ForbiddenError, MalformedError, AuthenticationError
 
@@ -28,7 +28,19 @@ class DatabaseUnitTest(unittest.TestCase):
                 contact=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'),
                 internal_name='test_abcd',
                 is_public=True,
-                is_schema_public=True)
+                is_schema_public=True,
+                container=ContainerBrief(
+                    id=1,
+                    name='MariaDB Galera 11.1.3',
+                    internal_name='mariadb',
+                    image=ImageBrief(
+                        id=1,
+                        name='mariadb',
+                        version='11.2.2',
+                        jdbc_method='mariadb'
+                    )
+                )
+            )
         ]
         with requests_mock.Mocker() as mock:
             # mock
diff --git a/lib/python/tests/test_unit_identifier.py b/lib/python/tests/test_unit_identifier.py
index 45b0a919e74d79d2420669a7036fcc87ae02b92a..8726d05ef23108c2a0a8fb9e8c4cd65052e19b1e 100644
--- a/lib/python/tests/test_unit_identifier.py
+++ b/lib/python/tests/test_unit_identifier.py
@@ -1,14 +1,12 @@
 import unittest
 
 import requests_mock
-import datetime
 
 from dbrepo.RestClient import RestClient
-
-from dbrepo.api.dto import Identifier, IdentifierType, CreateIdentifierTitle, CreateIdentifierCreator, \
-    IdentifierCreator, IdentifierTitle, IdentifierDescription, CreateIdentifierDescription, Language, \
-    CreateIdentifierFunder, CreateRelatedIdentifier, RelatedIdentifierRelation, RelatedIdentifierType, IdentifierFunder, \
-    RelatedIdentifier, UserBrief, IdentifierStatusType
+from dbrepo.api.dto import Identifier, IdentifierType, SaveIdentifierTitle, Creator, IdentifierTitle, \
+    IdentifierDescription, SaveIdentifierDescription, Language, SaveIdentifierFunder, SaveRelatedIdentifier, \
+    RelatedIdentifierRelation, RelatedIdentifierType, IdentifierFunder, RelatedIdentifier, UserBrief, \
+    IdentifierStatusType, CreateIdentifierCreator
 from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, AuthenticationError
 
 
@@ -29,7 +27,7 @@ class IdentifierUnitTest(unittest.TestCase):
                              related_identifiers=[
                                  RelatedIdentifier(id=7, value='10.12345/abc', relation=RelatedIdentifierRelation.CITES,
                                                    type=RelatedIdentifierType.DOI)],
-                             creators=[IdentifierCreator(id=5, creator_name='Carberry, Josiah')],
+                             creators=[Creator(id=5, creator_name='Carberry, Josiah')],
                              status=IdentifierStatusType.PUBLISHED,
                              owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'))
             # mock
@@ -38,14 +36,14 @@ class IdentifierUnitTest(unittest.TestCase):
             client = RestClient(username="a", password="b")
             response = client.create_identifier(
                 database_id=1, type=IdentifierType.VIEW,
-                titles=[CreateIdentifierTitle(title='Test Title')],
+                titles=[SaveIdentifierTitle(title='Test Title')],
                 publisher='TU Wien', publication_year=2024,
                 language=Language.EN,
-                funders=[CreateIdentifierFunder(funder_name='FWF')],
-                related_identifiers=[CreateRelatedIdentifier(value='10.12345/abc',
-                                                             relation=RelatedIdentifierRelation.CITES,
-                                                             type=RelatedIdentifierType.DOI)],
-                descriptions=[CreateIdentifierDescription(description='Test Description')],
+                funders=[SaveIdentifierFunder(funder_name='FWF')],
+                related_identifiers=[SaveRelatedIdentifier(value='10.12345/abc',
+                                                           relation=RelatedIdentifierRelation.CITES,
+                                                           type=RelatedIdentifierType.DOI)],
+                descriptions=[SaveIdentifierDescription(description='Test Description')],
                 creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')])
             self.assertEqual(exp, response)
 
@@ -58,8 +56,8 @@ class IdentifierUnitTest(unittest.TestCase):
                 client = RestClient(username="a", password="b")
                 response = client.create_identifier(
                     database_id=1, type=IdentifierType.VIEW,
-                    titles=[CreateIdentifierTitle(title='Test Title')],
-                    descriptions=[CreateIdentifierDescription(description='Test')],
+                    titles=[SaveIdentifierTitle(title='Test Title')],
+                    descriptions=[SaveIdentifierDescription(description='Test')],
                     publisher='TU Wien', publication_year=2024,
                     creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')])
             except MalformedError:
@@ -74,8 +72,8 @@ class IdentifierUnitTest(unittest.TestCase):
                 client = RestClient(username="a", password="b")
                 response = client.create_identifier(
                     database_id=1, type=IdentifierType.VIEW,
-                    titles=[CreateIdentifierTitle(title='Test Title')],
-                    descriptions=[CreateIdentifierDescription(description='Test')],
+                    titles=[SaveIdentifierTitle(title='Test Title')],
+                    descriptions=[SaveIdentifierDescription(description='Test')],
                     publisher='TU Wien', publication_year=2024,
                     creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')])
             except ForbiddenError:
@@ -90,8 +88,8 @@ class IdentifierUnitTest(unittest.TestCase):
                 client = RestClient(username="a", password="b")
                 response = client.create_identifier(
                     database_id=1, type=IdentifierType.VIEW,
-                    titles=[CreateIdentifierTitle(title='Test Title')],
-                    descriptions=[CreateIdentifierDescription(description='Test')],
+                    titles=[SaveIdentifierTitle(title='Test Title')],
+                    descriptions=[SaveIdentifierDescription(description='Test')],
                     publisher='TU Wien', publication_year=2024,
                     creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')])
             except NotExistsError:
@@ -105,8 +103,8 @@ class IdentifierUnitTest(unittest.TestCase):
             try:
                 response = RestClient().create_identifier(
                     database_id=1, type=IdentifierType.VIEW,
-                    titles=[CreateIdentifierTitle(title='Test Title')],
-                    descriptions=[CreateIdentifierDescription(description='Test')],
+                    titles=[SaveIdentifierTitle(title='Test Title')],
+                    descriptions=[SaveIdentifierDescription(description='Test')],
                     publisher='TU Wien', publication_year=2024,
                     creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')])
             except AuthenticationError:
@@ -127,7 +125,7 @@ class IdentifierUnitTest(unittest.TestCase):
                               related_identifiers=[RelatedIdentifier(id=7, value='10.12345/abc',
                                                                      relation=RelatedIdentifierRelation.CITES,
                                                                      type=RelatedIdentifierType.DOI)],
-                              creators=[IdentifierCreator(id=5, creator_name='Carberry, Josiah')],
+                              creators=[Creator(id=5, creator_name='Carberry, Josiah')],
                               status=IdentifierStatusType.PUBLISHED,
                               owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'))]
             # mock
diff --git a/lib/python/tests/test_unit_table.py b/lib/python/tests/test_unit_table.py
index 4c4ad2af6aabbe6a36689fe3a44b50b8f6f625dc..eccf8c2a59ee45c3341c4116678301e438f0089b 100644
--- a/lib/python/tests/test_unit_table.py
+++ b/lib/python/tests/test_unit_table.py
@@ -6,7 +6,7 @@ from pandas import DataFrame
 
 from dbrepo.RestClient import RestClient
 from dbrepo.api.dto import Table, CreateTableConstraints, Column, Constraints, ColumnType, ConceptBrief, UnitBrief, \
-    TableStatistics, ColumnStatistic, PrimaryKey, TableMinimal, ColumnMinimal, TableBrief, UserBrief
+    TableStatistics, ColumnStatistic, PrimaryKey, ColumnBrief, TableBrief, UserBrief
 from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, NameExistsError, \
     AuthenticationError, ExternalSystemError
 
@@ -14,35 +14,15 @@ from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError
 class TableUnitTest(unittest.TestCase):
 
     def test_create_table_succeeds(self):
-        exp = Table(id=2,
-                    name="Test",
-                    description="Test Table",
-                    database_id=1,
-                    internal_name="test",
-                    owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'),
-                    is_versioned=True,
-                    queue_name='test',
-                    routing_key='dbrepo.test_database_1234.test',
-                    is_public=True,
-                    is_schema_public=True,
-                    constraints=Constraints(uniques=[],
-                                            foreign_keys=[],
-                                            checks=[],
-                                            primary_key=[PrimaryKey(id=1,
-                                                                    table=TableMinimal(id=2, database_id=1),
-                                                                    column=ColumnMinimal(id=1, table_id=2,
-                                                                                         database_id=1))]),
-                    columns=[Column(id=1,
-                                    ord=0,
-                                    name="ID",
-                                    database_id=1,
-                                    table_id=2,
-                                    internal_name="id",
-                                    auto_generated=True,
-                                    is_primary_key=True,
-                                    type=ColumnType.BIGINT,
-                                    is_public=True,
-                                    is_null_allowed=False)])
+        exp = TableBrief(id=2,
+                         database_id=1,
+                         name="Test",
+                         description="Test Table",
+                         internal_name="test",
+                         owned_by='8638c043-5145-4be8-a3e4-4b79991b0a16',
+                         is_versioned=True,
+                         is_public=True,
+                         is_schema_public=True)
         with requests_mock.Mocker() as mock:
             # mock
             mock.post('/api/database/1/table', json=exp.model_dump(), status_code=201)
@@ -159,9 +139,20 @@ class TableUnitTest(unittest.TestCase):
                                                 foreign_keys=[],
                                                 checks=[],
                                                 primary_key=[PrimaryKey(id=1,
-                                                                        table=TableMinimal(id=2, database_id=1),
-                                                                        column=ColumnMinimal(id=1, table_id=2,
-                                                                                             database_id=1))]),
+                                                                        table=TableBrief(id=2, database_id=1,
+                                                                                         name='Other',
+                                                                                         internal_name='other',
+                                                                                         description=None,
+                                                                                         is_versioned=True,
+                                                                                         is_public=True,
+                                                                                         is_schema_public=True,
+                                                                                         owned_by='8638c043-5145-4be8-a3e4-4b79991b0a16'),
+                                                                        column=ColumnBrief(id=1, table_id=2,
+                                                                                           database_id=1,
+                                                                                           name='id',
+                                                                                           alias=None,
+                                                                                           internal_name='id',
+                                                                                           type=ColumnType.BIGINT))]),
                         columns=[Column(id=1,
                                         name="ID",
                                         ord=0,
diff --git a/lib/python/tests/test_unit_user.py b/lib/python/tests/test_unit_user.py
index 0d1e72088573af1921028daf9af1b3e1f092cac2..0e846b1b42e6ba935a2f204d09aa0920dce69626 100644
--- a/lib/python/tests/test_unit_user.py
+++ b/lib/python/tests/test_unit_user.py
@@ -125,8 +125,8 @@ class UserUnitTest(unittest.TestCase):
 
     def test_update_user_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin',
-                       attributes=UserAttributes(theme='dark'))
+            exp = UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin',
+                            attributes=UserAttributes(theme='dark'))
             # mock
             mock.put('http://localhost/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16', status_code=202,
                      json=exp.model_dump())
@@ -173,16 +173,12 @@ class UserUnitTest(unittest.TestCase):
 
     def test_update_user_password_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin',
-                       attributes=UserAttributes(theme='dark'))
             # mock
-            mock.put('http://localhost/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/password', status_code=202,
-                     json=exp.model_dump())
+            mock.put('http://localhost/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/password', status_code=202)
             # test
             client = RestClient(username="a", password="b")
             response = client.update_user_password(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16',
                                                    password='s3cr3t1n0rm4t10n')
-            self.assertEqual(exp, response)
 
     def test_update_user_password_not_allowed_fails(self):
         with requests_mock.Mocker() as mock:
diff --git a/make/build.mk b/make/build.mk
index 7311ed27167f72e4ffa4b8b7659127b90679d471..270b2cee6fd80b9dea9a475399081ae34ad65c91 100644
--- a/make/build.mk
+++ b/make/build.mk
@@ -14,23 +14,27 @@ build-data-service: ## Build the Data Service.
 build-metadata-service: ## Build the Metadata Service.
 	mvn -f ./dbrepo-metadata-service/pom.xml clean package -DskipTests
 
+.PHONY: build-auth-event-listener
+build-auth-event-listener: ## Build the Auth Service Event Listener.
+	mvn -f ./dbrepo-auth-service/listeners/pom.xml clean package -DskipTests
+
 .PHONY: build-ui
 build-ui: ## Build the UI.
 	bun --cwd ./dbrepo-ui build
 
 .PHONY: build-lib
 build-lib: ## Build the Python Library.
-	rm -f ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}.tar.gz
-	rm -f ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}.tar.gz
-	rm -f ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}.tar.gz
+	rm -rf ./dbrepo-analyse-service/venv/ ./dbrepo-analyse-service/Pipfile.lock ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}*
+	rm -rf ./dbrepo-search-service/venv/ ./dbrepo-search-service/Pipfile.lock ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}*
+	rm -rf ./dbrepo-search-service/init/venv/ ./dbrepo-search-service/init/Pipfile.lock ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}*
 	python3 -m build --sdist ./lib/python
 	python3 -m build --wheel ./lib/python
-	cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}.tar.gz
-	(cd ./dbrepo-analyse-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock)
-	cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}.tar.gz
-	(cd ./dbrepo-search-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock)
-	cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}.tar.gz
-	(cd ./dbrepo-search-service/init && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock)
+	cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-analyse-service/lib
+	(cd ./dbrepo-analyse-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev)
+	cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-search-service/lib
+	(cd ./dbrepo-search-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev)
+	cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-search-service/init/lib
+	(cd ./dbrepo-search-service/init && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev)
 
 .PHONY: build-helm
 build-helm: ## Build the DBRepo and DBRepo MariaDB Galera Helm Charts.
diff --git a/make/dev.mk b/make/dev.mk
index 0282dbbce287356e207822fdc9dbf1be7e26e0b8..d8da31086b3dfcba7f85aeeaa6db64564b87c036 100644
--- a/make/dev.mk
+++ b/make/dev.mk
@@ -1,7 +1,7 @@
 ##@ Development
 
 .PHONY: start-dev
-start-dev: build-images ## Start the development deployment.
+start-dev: build-images build-auth-event-listener ## Start the development deployment.
 	docker container stop dbrepo-gateway-service || true
 	docker container rm dbrepo-gateway-service || true
 	docker compose up -d
diff --git a/make/gen.mk b/make/gen.mk
index ed10c7e123e292816bd550aba66faf214dcfb81b..308a307b95534ea6bbf0f497244b64a5597061ae 100644
--- a/make/gen.mk
+++ b/make/gen.mk
@@ -1,11 +1,11 @@
 ##@ Generate
 
-.PHONY: gen-swagger-doc
-gen-swagger-doc: build-images ## Generate Swagger documentation and fetch.
+.PHONY: gen-openapi-doc
+gen-openapi-doc: build-images ## Generate Swagger documentation and fetch.
 	docker compose up -d
-	bash .docs/.swagger/swagger-generate.sh
+	bash .docs/.openapi/openapi-generate.sh
 	docker compose down
-	openapi-merge-cli --config .docs/.swagger/openapi-merge.json
+	openapi-merge-cli --config .docs/.openapi/openapi-merge.json
 
 .PHONY: gen-helm-doc
 gen-helm-doc: build-helm ## Generate Helm documentation and schema
diff --git a/sonar-project.properties b/sonar-project.properties
index d354d54608a75063e0000cd577469dba69ae5eec..4442bf46ff84667faa8f20672f21d14be29fef3e 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -2,7 +2,7 @@
 sonar.projectKey=fair-data-austria-db-repository_fda-services_a57fa043-ab99-4cdd-a721-162d9a916d77
 sonar.host.url=https://s39.datalab.tuwien.ac.at
 # project
-sonar.projectVersion=1.6.1
+sonar.projectVersion=1.6.3
 # general
 sonar.qualitygate.wait=true
 sonar.projectCreation.mainBranchName=master
diff --git a/yq b/yq
new file mode 100644
index 0000000000000000000000000000000000000000..5578822fb407e254544a2b532ef439174956ea45
--- /dev/null
+++ b/yq
@@ -0,0 +1,7043 @@
+openapi: 3.0.1
+info:
+  title: Database Repository Metadata Service API
+  description: Service that manages the metadata
+  contact:
+    name: Prof. Andreas Rauber
+    email: andreas.rauber@tuwien.ac.at
+  license:
+    name: Apache 2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0
+  version: 1.6.2
+externalDocs:
+  description: Sourcecode Documentation
+  url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6.2/system-services-metadata/
+servers:
+- url: http://localhost
+  description: Development instance
+- url: https://test.dbrepo.tuwien.ac.at
+  description: Staging instance
+paths:
+  /api/database:
+    get:
+      tags:
+      - database-endpoint
+      summary: List databases
+      description: "Lists all databases in the metadata database. Requests with HTTP\
+        \ method **GET** return the list of databases, requests with HTTP method **HEAD**\
+        \ only the number in the `X-Count` header."
+      operationId: list
+      parameters:
+      - name: internal_name
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "200":
+          description: List of databases
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of databases
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/DatabaseBriefDto"
+    post:
+      tags:
+      - database-endpoint
+      summary: Create database
+      description: Creates a database in the container with id. Requires roles `create-database`.
+      operationId: create_5
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseCreateDto"
+        required: true
+      responses:
+        "409":
+          description: Query store could not be created
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Database create query is malformed or image is not supported
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "423":
+          description: Database quota exceeded
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Database create permission is missing or grant permissions
+            at broker service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to fin container/user/database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created a new database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    head:
+      tags:
+      - database-endpoint
+      summary: List databases
+      description: "Lists all databases in the metadata database. Requests with HTTP\
+        \ method **GET** return the list of databases, requests with HTTP method **HEAD**\
+        \ only the number in the `X-Count` header."
+      operationId: list_1
+      parameters:
+      - name: internal_name
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "200":
+          description: List of databases
+          headers:
+            Access-Control-Expose-Headers:
+              description: Expose `X-Count` custom header
+              required: true
+              style: simple
+            X-Count:
+              description: Number of databases
+              required: true
+              style: simple
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/DatabaseBriefDto"
+  /api/database/{databaseId}/access/{userId}:
+    get:
+      tags:
+      - access-endpoint
+      summary: Find/Check access
+      description: "Finds or checks access of a user with given id to a database with\
+        \ given id. Requests with HTTP method **GET** return the access object, requests\
+        \ with HTTP method **HEAD** only the status. When the user has at least *READ*\
+        \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\
+        \ or `check-foreign-database-access`."
+      operationId: find
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "403":
+          description: No access to this database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found database access
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseAccessDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - access-endpoint
+      summary: Modify access
+      description: Modifies access of a user with given id to database with given
+        id. Requires role `update-database-access`.
+      operationId: update_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UpdateDatabaseAccessDto"
+        required: true
+      responses:
+        "404":
+          description: Database or user not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Modify access not permitted when no access is granted in the
+            first place
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Access could not be updated in the data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Modified access
+        "502":
+          description: Access could not be updated due to connection error in the
+            data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Modify access query or database connection is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    post:
+      tags:
+      - access-endpoint
+      summary: Give access
+      description: Give a user with given id access to some database with given id.
+        Requires role `create-database-access`.
+      operationId: create_8
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UpdateDatabaseAccessDto"
+        required: true
+      responses:
+        "404":
+          description: Database or user not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Access could not be created in the data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Failed giving access
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Granting access succeeded
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseAccessDto"
+        "400":
+          description: Granting access query or database connection is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Access could not be created due to connection error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - access-endpoint
+      summary: Delete access
+      description: Delete access of a user with id to a database with id. Requires
+        role `delete-database-access`.
+      operationId: revoke
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "403":
+          description: Revoke of access not permitted as no access was found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted access
+        "502":
+          description: Access could not be created due to connection error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "User, database with access was not found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Access could not be revoked in the data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Modify access query or database connection is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    head:
+      tags:
+      - access-endpoint
+      summary: Find/Check access
+      description: "Finds or checks access of a user with given id to a database with\
+        \ given id. Requests with HTTP method **GET** return the access object, requests\
+        \ with HTTP method **HEAD** only the status. When the user has at least *READ*\
+        \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\
+        \ or `check-foreign-database-access`."
+      operationId: find_1
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "403":
+          description: No access to this database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found database access
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseAccessDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user/{userId}:
+    get:
+      tags:
+      - user-endpoint
+      summary: Get user
+      description: Gets own user information from the metadata database. Requires
+        authentication. Foreign user information can only be obtained if additional
+        role `find-foreign-user` is present. Finding information about internal users
+        results in a 404 error.
+      operationId: find_2
+      parameters:
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      responses:
+        "404":
+          description: User was not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found user
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserDto"
+        "403":
+          description: Find user is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - user-endpoint
+      summary: Update user
+      description: Updates user with id. Requires role `modify-user-information`.
+      operationId: modify
+      parameters:
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UserUpdateDto"
+        required: true
+      responses:
+        "202":
+          description: Modified user information
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserDto"
+        "404":
+          description: Failed to find database/user in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Modify user query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to modify user metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user/{userId}/password:
+    put:
+      tags:
+      - user-endpoint
+      summary: Update user password
+      description: Updates password of user with id. Requires authentication.
+      operationId: password
+      parameters:
+      - name: userId
+        in: path
+        required: true
+        schema:
+          type: string
+          format: uuid
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UserPasswordDto"
+        required: true
+      responses:
+        "400":
+          description: Invalid password payload
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Modified user password
+        "403":
+          description: Not allowed to change foreign user password
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to get user in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/user in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to auth service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user/token:
+    put:
+      tags:
+      - user-endpoint
+      summary: Refresh token
+      description: Refreshes user token by refresh token.
+      operationId: refreshToken
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/RefreshTokenRequestDto"
+        required: true
+      responses:
+        "202":
+          description: Refreshed user token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TokenDto"
+        "403":
+          description: Not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Invalid refresh token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to auth service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    post:
+      tags:
+      - user-endpoint
+      summary: Create token
+      description: Creates a user token via the Auth Service.
+      operationId: getToken
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/LoginRequestDto"
+        required: true
+      responses:
+        "400":
+          description: Invalid login request
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not allowed to get token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find user in auth database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to get user in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Obtained user token
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TokenDto"
+        "428":
+          description: Account is not fully setup in auth service (requires password
+            change?)
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to auth service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/ontology/{ontologyId}:
+    get:
+      tags:
+      - ontology-endpoint
+      summary: Find ontology
+      description: Finds an ontology with id in the metadata database.
+      operationId: find_3
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Find one ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OntologyDto"
+    put:
+      tags:
+      - ontology-endpoint
+      summary: Update ontology
+      description: Updates an ontology with id. Requires role `update-ontology`.
+      operationId: update
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OntologyModifyDto"
+        required: true
+      responses:
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated ontology successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OntologyDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - ontology-endpoint
+      summary: Delete ontology
+      description: Deletes an ontology with given id. Requires role `delete-ontology`.
+      operationId: delete
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "202":
+          description: Deleted ontology successfully
+          content:
+            application/json: {}
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/message/{messageId}:
+    put:
+      tags:
+      - message-endpoint
+      summary: Update message
+      description: Updates a message with id. Requires role `update-maintenance-message`.
+      operationId: update_1
+      parameters:
+      - name: messageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/BannerMessageUpdateDto"
+        required: true
+      responses:
+        "202":
+          description: Updated message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/BannerMessageBriefDto"
+        "404":
+          description: Could not find message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - message-endpoint
+      summary: Delete message
+      description: Deletes a message with id. Requires role `delete-maintenance-message`.
+      operationId: delete_1
+      parameters:
+      - name: messageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Could not find message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted message
+          content:
+            application/json: {}
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/image/{imageId}:
+    get:
+      tags:
+      - image-endpoint
+      summary: Find image
+      description: Finds a container image in the metadata database.
+      operationId: findById
+      parameters:
+      - name: imageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found image
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ImageDto"
+    put:
+      tags:
+      - image-endpoint
+      summary: Update image
+      description: Updates container image in the metadata database. Requires role
+        `modify-image`.
+      operationId: update_2
+      parameters:
+      - name: imageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ImageChangeDto"
+        required: true
+      responses:
+        "404":
+          description: Image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated image successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ImageDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - image-endpoint
+      summary: Delete image
+      description: Deletes a container image in the metadata database. Requires role
+        `delete-image`.
+      operationId: delete_2
+      parameters:
+      - name: imageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "202":
+          description: Deleted image successfully
+        "404":
+          description: Image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/identifier/{identifierId}:
+    get:
+      tags:
+      - identifier-endpoint
+      summary: Find identifier
+      description: Finds an identifier with id. The response format depends on the
+        HTTP `Accept` header set on the request.
+      operationId: find_6
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: Accept
+        in: header
+        required: true
+        schema:
+          type: string
+      responses:
+        "200":
+          description: Found identifier successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+            application/ld+json:
+              schema:
+                $ref: "#/components/schemas/LdDatasetDto"
+            text/csv: {}
+            text/xml: {}
+            text/bibliography: {}
+            text/bibliography; style=apa: {}
+            text/bibliography; style=ieee: {}
+            text/bibliography; style=bibtex: {}
+        "502":
+          description: Connection to data service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: "Identifier could not be exported, the requested style is not\
+            \ known"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "409":
+          description: Exported resource was not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "410":
+          description: Failed to retrieve from S3 endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Identifier could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "406":
+          description: Failed to find acceptable representation
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to find in data service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    put:
+      tags:
+      - identifier-endpoint
+      summary: Save identifier
+      description: Saves an identifier with id as a draft identifier. Identifiers
+        can only be created for objects the user has at least *READ* access in the
+        associated database (requires role `create-identifier`) or for any object
+        in any database (requires role `create-foreign-identifier`).
+      operationId: save
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/IdentifierSaveDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Failed to find database, table or view"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Identifier form contains invalid request data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Saved identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+        "403":
+          description: Insufficient access rights or authorities
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - identifier-endpoint
+      summary: Delete identifier
+      description: Deletes an identifier with id. Requires role `delete-identifier`.
+      operationId: delete_3
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to delete in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Identifier or database could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted identifier
+        "403":
+          description: Deleting identifier not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/identifier/{identifierId}/publish:
+    put:
+      tags:
+      - identifier-endpoint
+      summary: Publish identifier
+      description: Publishes an identifier with id. A published identifier cannot
+        be changed anymore. Requires role `publish-identifier`.
+      operationId: publish
+      parameters:
+      - name: identifierId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Failed to find database, table or view"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Published identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+        "400":
+          description: Identifier form contains invalid request data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Insufficient access rights or authorities
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/visibility:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database visibility
+      description: Updates the database with id on the visibility. Only the database
+        owner can perform this operation. Requires role `modify-database-visibility`.
+      operationId: visibility
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseModifyVisibilityDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Visibility modified successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "400":
+          description: The visibility payload is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Visibility modification is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/view/{viewId}:
+    get:
+      tags:
+      - view-endpoint
+      summary: Get view
+      description: Gets a view with id in the metadata database.
+      operationId: find_7
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: Find view is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, view or user could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Find view successfully
+          headers:
+            X-Username:
+              description: The authentication username
+              style: simple
+            Access-Control-Expose-Headers:
+              description: Expose custom headers
+              style: simple
+            X-Type:
+              description: The JDBC connection type
+              style: simple
+            X-View:
+              description: The view internal name
+              style: simple
+            X-Database:
+              description: The database internal name
+              style: simple
+            X-Password:
+              description: The authentication password
+              style: simple
+            X-Host:
+              description: The database hostname
+              style: simple
+            X-Port:
+              description: The database port number
+              style: simple
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ViewDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - view-endpoint
+      summary: Update view
+      description: Updates a view with id. This can only be performed by the view
+        owner or database owner. Requires role `create-database-view`.
+      operationId: update_3
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ViewUpdateDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database or View could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Update not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Update view query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Update view successfully
+          content:
+            '*/*':
+              schema:
+                $ref: "#/components/schemas/ViewDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - view-endpoint
+      summary: Delete view
+      description: Deletes a view with id. Requires role `delete-database-view`.
+      operationId: delete_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: viewId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "423":
+          description: Delete view resulted in an invalid query statement
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, view or user could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Delete view successfully
+          content:
+            '*/*':
+              schema:
+                type: object
+        "400":
+          description: Delete view query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Deletion not allowed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}:
+    get:
+      tags:
+      - table-endpoint
+      summary: Find table
+      description: "Finds a table with id. When a table is hidden (i.e. when `is_public`\
+        \ is `false`), then the user needs to have at least read access and the role\
+        \ `find-table`. When the `system` role is present, the endpoint responds with\
+        \ additional connection metadata in the header."
+      operationId: findById_2
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Find table successfully
+          headers:
+            X-Username:
+              description: The authentication username
+              style: simple
+            X-Table:
+              description: The table internal name
+              style: simple
+            Access-Control-Expose-Headers:
+              description: Expose custom headers
+              style: simple
+            X-Type:
+              description: The JDBC connection type
+              style: simple
+            X-Database:
+              description: The database internal name
+              style: simple
+            X-Password:
+              description: The authentication password
+              style: simple
+            X-Host:
+              description: The database hostname
+              style: simple
+            X-Port:
+              description: The database port number
+              style: simple
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TableDto"
+        "503":
+          description: Failed to obtain queue information from broker service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Access to the database is forbidden
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Failed to establish connection with broker service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Table, database or container could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - table-endpoint
+      summary: Update table
+      description: Updates a table in the database with id. Requires role `update-table`.
+      operationId: update_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/TableUpdateDto"
+        required: true
+      responses:
+        "403":
+          description: Update table visibility not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Table could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated the table
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TableBriefDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Update table visibility payload is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    delete:
+      tags:
+      - table-endpoint
+      summary: Delete table
+      description: Deletes a table with id. Only the owner of a table can perform
+        this action (requires role `delete-table`) or anyone can delete a table (requires
+        role `delete-foreign-table`).
+      operationId: delete_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Access to the database is forbidden
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Delete table successfully
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Delete table query resulted in an invalid query statement
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Table, database or container could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/statistic:
+    put:
+      tags:
+      - table-endpoint
+      summary: Update statistics
+      description: "Updates basic statistical properties (min, max, mean, median,\
+        \ std.dev) for numerical columns in a table with id. This action can only\
+        \ be performed by the table owner. Requires role `update-table-statistic`."
+      operationId: updateStatistic
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Failed to map column statistic to known columns
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not the owner
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated table statistics successfully
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/column/{columnId}:
+    put:
+      tags:
+      - table-endpoint
+      summary: Update semantics
+      description: Updates column semantics of a table column with id. Only the table
+        owner with at least *READ* access to the associated database can update the
+        column semantics (requires role `modify-table-column-semantics`) or foreign
+        table columns if role `modify-foreign-table-column-semantics`.
+      operationId: updateColumn
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: columnId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ColumnSemanticsUpdateDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Access to the database is forbidden
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find user/table/database/ontology in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Updated column semantics successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ColumnDto"
+        "400":
+          description: Update semantic concept query is malformed or update unit of
+            measurement query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/owner:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database owner
+      description: Updates the database with id on the owner. Only the database owner
+        can perform this operation. Requires role `modify-database-owner`.
+      operationId: transfer
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseTransferDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Transfer of ownership was successful
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "403":
+          description: Transfer of ownership is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Owner payload is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/metadata/view:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database view schemas
+      description: Updates the database with id with generated metadata from view
+        that are not yet known to the database. Only the database owner can perform
+        this operation. Requires role `find-database`.
+      operationId: refreshViewMetadata
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Refreshed database views metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "403":
+          description: Refresh view metadata is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/metadata/table:
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database table schemas
+      description: Updates the database with id with generated metadata from tables
+        that are not yet known to the database. Only the database owner can perform
+        this operation. Requires role `find-database`.
+      operationId: refreshTableMetadata
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: Not allowed to refresh table metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to fin user/database in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Refreshed database tables metadata
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "400":
+          description: Failed to parse payload at search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/image:
+    get:
+      tags:
+      - database-endpoint
+      summary: Get database preview image
+      description: Gets the database with id on the preview image.
+      operationId: findPreviewImage
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Database or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: View of image was successful
+          content:
+            '*/*':
+              schema:
+                type: array
+                items:
+                  type: string
+                  format: byte
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    put:
+      tags:
+      - database-endpoint
+      summary: Update database preview image
+      description: Updates the database with id on the preview image. Only the database
+        owner can perform this operation. Requires role `modify-database-image`.
+      operationId: modifyImage
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DatabaseModifyImageDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Modify of image was successful
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "410":
+          description: File was not found in the Storage Service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Modify of image is not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/user:
+    get:
+      tags:
+      - user-endpoint
+      summary: List users
+      description: "Lists users known to the metadata database. Internal users are\
+        \ omitted from the result list. If the optional query parameter `username`\
+        \ is present, the result list can be filtered by matching this exact username."
+      operationId: findAll
+      parameters:
+      - name: username
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "200":
+          description: List users
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/UserBriefDto"
+    post:
+      tags:
+      - user-endpoint
+      summary: Create user
+      description: Creates a user in the auth service and metadata database. Requires
+        that no credentials are sent in the request.
+      operationId: create
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SignupRequestDto"
+        required: true
+      responses:
+        "403":
+          description: Internal authentication to the auth service is invalid
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Parameters are not well-formed (likely email)
+          content:
+            application/json: {}
+        "409":
+          description: User with username already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "417":
+          description: User with e-mail already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to create in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created user
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserDto"
+        "502":
+          description: Failed to create in auth service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Default role not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/ontology:
+    get:
+      tags:
+      - ontology-endpoint
+      summary: List ontologies
+      description: Lists all ontologies known to the metadata database.
+      operationId: findAll_2
+      responses:
+        "200":
+          description: List ontologies
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/OntologyBriefDto"
+    post:
+      tags:
+      - ontology-endpoint
+      summary: Create ontology
+      description: Creates an ontology in the metadata database. Requires role `create-ontology`.
+      operationId: create_1
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OntologyCreateDto"
+        required: true
+      responses:
+        "201":
+          description: Registered ontology successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OntologyDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/message:
+    get:
+      tags:
+      - message-endpoint
+      summary: List messages
+      description: "Lists messages known to the metadata database. Messages can be\
+        \ filtered be filtered with the optional `active` parameter. If set to *true*,\
+        \ only active messages (that is, messages whose end time has not been reached)\
+        \ will be returned. Otherwise only inactive messages are returned. If not\
+        \ set, active and inactive messages are returned."
+      operationId: list_2
+      parameters:
+      - name: active
+        in: query
+        required: false
+        schema:
+          type: boolean
+      responses:
+        "200":
+          description: List messages
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/BannerMessageDto"
+    post:
+      tags:
+      - message-endpoint
+      summary: Create message
+      description: Creates a message in the metadata database. Requires role `create-maintenance-message`.
+      operationId: create_2
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/BannerMessageCreateDto"
+        required: true
+      responses:
+        "201":
+          description: Created message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/BannerMessageBriefDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/image:
+    get:
+      tags:
+      - image-endpoint
+      summary: List images
+      description: Lists all container images known to the metadata database.
+      operationId: findAll_3
+      responses:
+        "200":
+          description: List images
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ImageBriefDto"
+    post:
+      tags:
+      - image-endpoint
+      summary: Create image
+      description: Creates a container image in the metadata database. Requires role
+        `create-image`.
+      operationId: create_3
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ImageCreateDto"
+        required: true
+      responses:
+        "409":
+          description: Image already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Image specification is invalid
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created image
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ImageDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/identifier:
+    get:
+      tags:
+      - identifier-endpoint
+      summary: List identifiers
+      description: Lists all identifiers known to the metadata database
+      operationId: findAll_4
+      parameters:
+      - name: dbid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: qid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: vid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: tid
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int64
+      - name: Accept
+        in: header
+        required: true
+        schema:
+          type: string
+      responses:
+        "200":
+          description: Found identifiers successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  type: string
+            application/ld+json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/LdDatasetDto"
+        "406":
+          description: "Identifier could not be exported, the requested style is not\
+            \ known"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    post:
+      tags:
+      - identifier-endpoint
+      summary: Create identifier
+      description: Create an identifier with id to create a draft identifier. Identifiers
+        can only be created for objects the user has at least *READ* access in the
+        associated database (requires role `create-identifier`) or for any object
+        in any database (requires role `create-foreign-identifier`).
+      operationId: create_4
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/IdentifierCreateDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Drafted identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+        "404":
+          description: "Failed to find database, table or view"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Identifier form contains invalid request data
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Insufficient access rights or authorities
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/view:
+    get:
+      tags:
+      - view-endpoint
+      summary: List views
+      description: Lists views known to the metadata database.
+      operationId: findAll_5
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Find views successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ViewBriefDto"
+        "404":
+          description: Database or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    post:
+      tags:
+      - view-endpoint
+      summary: Create view
+      description: Creates a view. This can only be performed by the database owner.
+        Requires role `create-database-view`.
+      operationId: create_6
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ViewCreateDto"
+        required: true
+      responses:
+        "423":
+          description: Create view resulted in an invalid query statement
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Create view successfully
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ViewBriefDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Credentials missing
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/user in metadata database.
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Create view query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table:
+    get:
+      tags:
+      - table-endpoint
+      summary: List tables
+      description: "Lists all tables known to the metadata database. When a database\
+        \ has a hidden schema (i.e. when `is_schema_public` is `false`), then the\
+        \ user needs to have at least read access and the role `list-tables`."
+      operationId: list_4
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "403":
+          description: List tables not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Database could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: List tables
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/TableBriefDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+    post:
+      tags:
+      - table-endpoint
+      summary: Create table
+      description: Creates a table in the database with id. Requires role `create-table`.
+      operationId: create_7
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/TableCreateDto"
+        required: true
+      responses:
+        "502":
+          description: Connection to search service failed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Create table not permitted
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created a new table
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/TableBriefDto"
+        "409":
+          description: Create table conflicts with existing table name
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, container or user could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "503":
+          description: Failed to save in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Create table query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/container:
+    get:
+      tags:
+      - container-endpoint
+      summary: List containers
+      description: List all containers in the metadata database.
+      operationId: findAll_6
+      parameters:
+      - name: limit
+        in: query
+        required: false
+        schema:
+          type: integer
+          format: int32
+      responses:
+        "200":
+          description: List containers
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ContainerBriefDto"
+    post:
+      tags:
+      - container-endpoint
+      summary: Create container
+      description: Creates a container in the metadata database. Requires role `create-container`.
+      operationId: create_9
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/ContainerCreateDto"
+        required: true
+      responses:
+        "400":
+          description: Container payload malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Container image or user could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "409":
+          description: Container name already exists
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "201":
+          description: Created a new container
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ContainerDto"
+        "403":
+          description: "Create container not permitted, need authority `create-container`"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/unit:
+    get:
+      tags:
+      - unit-endpoint
+      summary: List units
+      description: Lists units known to the metadata database.
+      operationId: findAll_1
+      responses:
+        "200":
+          description: Find all semantic units
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/UnitDto"
+  /api/ontology/{ontologyId}/entity:
+    get:
+      tags:
+      - ontology-endpoint
+      summary: Find entities
+      description: Finds semantic entities by label or uri in an ontology with id.
+        Requires role `execute-semantic-query`.
+      operationId: find_4
+      parameters:
+      - name: ontologyId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: label
+        in: query
+        required: false
+        schema:
+          type: string
+      - name: uri
+        in: query
+        required: false
+        schema:
+          type: string
+      responses:
+        "400":
+          description: Filter params are invalid
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Found entities
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/EntityDto"
+        "404":
+          description: Could not find ontology
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "422":
+          description: Ontology does not have rdf or sparql endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "417":
+          description: Generated query or uri is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/oai:
+    get:
+      tags:
+      - metadata-endpoint
+      summary: Get record
+      operationId: identify_1_1_1_1
+      parameters:
+      - name: verb
+        in: query
+      - name: parameters
+        in: query
+        required: true
+        schema:
+          $ref: "#/components/schemas/OaiListIdentifiersParameters"
+      responses:
+        "200":
+          description: List containers
+          content:
+            text/xml: {}
+  /api/message/message/{messageId}:
+    get:
+      tags:
+      - message-endpoint
+      summary: Find message
+      description: Finds a message with id in the metadata database.
+      operationId: find_5
+      parameters:
+      - name: messageId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Get messages
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/BannerMessageDto"
+        "404":
+          description: Could not find message
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/license:
+    get:
+      tags:
+      - license-endpoint
+      summary: List licenses
+      description: Lists licenses known to the metadata database.
+      operationId: list_3
+      responses:
+        "200":
+          description: List of licenses
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/LicenseDto"
+  /api/identifier/retrieve:
+    get:
+      tags:
+      - identifier-endpoint
+      summary: Retrieve PID metadata
+      description: "Retrieves Persistent Identifier (PID) metadata from external endpoints.\
+        \ Supported PIDs are: ORCID, ROR, DOI."
+      operationId: retrieve
+      parameters:
+      - name: url
+        in: query
+        required: true
+        schema:
+          type: string
+      responses:
+        "200":
+          description: Retrieved metadata from identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/IdentifierDto"
+        "404":
+          description: Failed to find metadata for identifier
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+  /api/database/{databaseId}:
+    get:
+      tags:
+      - database-endpoint
+      summary: Find database
+      description: Finds a database with id.
+      operationId: findById_1
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "503":
+          description: Failed to find queue information in broker service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "502":
+          description: Connection to the broker service could not be established
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Database found successfully
+          headers:
+            X-Username:
+              description: The authentication username
+              style: simple
+            Access-Control-Expose-Headers:
+              description: Expose custom headers
+              style: simple
+            X-Password:
+              description: The authentication password
+              style: simple
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DatabaseBriefDto"
+        "403":
+          description: Not allowed to view database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: "Database, user or exchange could not be found"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/suggest:
+    get:
+      tags:
+      - table-endpoint
+      summary: Suggest semantics
+      description: Suggests semantic concepts for a table. This action can only be
+        performed by the table owner. Requires role `table-semantic-analyse`.
+      operationId: analyseTable
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "417":
+          description: Generated query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "422":
+          description: Ontology does not have rdf or sparql endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "400":
+          description: Failed to parse statistic in search service
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "403":
+          description: Not the table owner.
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "404":
+          description: Failed to find database/table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Suggested table semantics successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/EntityDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/database/{databaseId}/table/{tableId}/column/{columnId}/suggest:
+    get:
+      tags:
+      - table-endpoint
+      summary: Suggest semantics
+      description: Suggests column semantics. Requires role `table-semantic-analyse`.
+      operationId: analyseTableColumn
+      parameters:
+      - name: databaseId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: tableId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      - name: columnId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "400":
+          description: Generated query is malformed
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "422":
+          description: Ontology does not have rdf or sparql endpoint
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "200":
+          description: Suggested table column semantics successfully
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/TableColumnEntityDto"
+        "404":
+          description: Failed to find database/table in metadata database
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/container/{containerId}:
+    get:
+      tags:
+      - container-endpoint
+      summary: Find container
+      description: Finds a container in the metadata database.
+      operationId: findById_3
+      parameters:
+      - name: containerId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "200":
+          description: Found container
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ContainerDto"
+        "404":
+          description: Container image could not be found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+    delete:
+      tags:
+      - container-endpoint
+      summary: Delete container
+      description: Deletes a container in the metadata database. Requires role `delete-container`.
+      operationId: delete_6
+      parameters:
+      - name: containerId
+        in: path
+        required: true
+        schema:
+          type: integer
+          format: int64
+      responses:
+        "404":
+          description: Container not found
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+        "202":
+          description: Deleted container
+        "403":
+          description: "Create container not permitted, need authority `delete-container`"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/ApiErrorDto"
+      security:
+      - bearerAuth: []
+      - basicAuth: []
+  /api/concept:
+    get:
+      tags:
+      - concept-endpoint
+      summary: List concepts
+      description: List all semantic concepts known to the metadata database
+      operationId: findAll_7
+      responses:
+        "200":
+          description: List concepts
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/ConceptDto"
+components:
+  schemas:
+    DatabaseBriefDto:
+      required:
+      - contact
+      - id
+      - internal_name
+      - is_public
+      - is_schema_public
+      - name
+      - owner_id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: Air Quality
+        description:
+          type: string
+          example: Air Quality
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierBriefDto"
+        contact:
+          $ref: "#/components/schemas/UserBriefDto"
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        owner_id:
+          type: string
+          format: uuid
+        preview_image:
+          type: string
+    IdentifierBriefDto:
+      required:
+      - created_by
+      - database_id
+      - id
+      - publication_year
+      - publisher
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        type:
+          type: string
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierTitleDto"
+        doi:
+          type: string
+          example: 10.1038/nphys1170
+        publisher:
+          type: string
+          example: TU Wien
+        status:
+          type: string
+          enum:
+          - draft
+          - published
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        view_id:
+          type: integer
+          format: int64
+          example: 1
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        created_by:
+          type: string
+          format: uuid
+    IdentifierTitleDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        title:
+          type: string
+          example: Airquality Demonstrator
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          enum:
+          - AlternativeTitle
+          - Subtitle
+          - TranslatedTitle
+          - Other
+    UserBriefDto:
+      required:
+      - id
+      - username
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+          example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4
+        username:
+          type: string
+          description: Only contains lowercase characters
+          example: jcarberry
+        name:
+          type: string
+          example: Josiah Carberry
+        orcid:
+          type: string
+          example: 0000-0002-1825-0097
+        qualified_name:
+          type: string
+          example: Josiah Carberry — @jcarberry
+        given_name:
+          type: string
+          example: Josiah
+        family_name:
+          type: string
+          example: Carberry
+    ApiErrorDto:
+      required:
+      - code
+      - message
+      - status
+      type: object
+      properties:
+        status:
+          type: string
+          example: NOT_FOUND
+          enum:
+          - 100 CONTINUE
+          - 101 SWITCHING_PROTOCOLS
+          - 102 PROCESSING
+          - 103 EARLY_HINTS
+          - 103 CHECKPOINT
+          - 200 OK
+          - 201 CREATED
+          - 202 ACCEPTED
+          - 203 NON_AUTHORITATIVE_INFORMATION
+          - 204 NO_CONTENT
+          - 205 RESET_CONTENT
+          - 206 PARTIAL_CONTENT
+          - 207 MULTI_STATUS
+          - 208 ALREADY_REPORTED
+          - 226 IM_USED
+          - 300 MULTIPLE_CHOICES
+          - 301 MOVED_PERMANENTLY
+          - 302 FOUND
+          - 302 MOVED_TEMPORARILY
+          - 303 SEE_OTHER
+          - 304 NOT_MODIFIED
+          - 305 USE_PROXY
+          - 307 TEMPORARY_REDIRECT
+          - 308 PERMANENT_REDIRECT
+          - 400 BAD_REQUEST
+          - 401 UNAUTHORIZED
+          - 402 PAYMENT_REQUIRED
+          - 403 FORBIDDEN
+          - 404 NOT_FOUND
+          - 405 METHOD_NOT_ALLOWED
+          - 406 NOT_ACCEPTABLE
+          - 407 PROXY_AUTHENTICATION_REQUIRED
+          - 408 REQUEST_TIMEOUT
+          - 409 CONFLICT
+          - 410 GONE
+          - 411 LENGTH_REQUIRED
+          - 412 PRECONDITION_FAILED
+          - 413 PAYLOAD_TOO_LARGE
+          - 413 REQUEST_ENTITY_TOO_LARGE
+          - 414 URI_TOO_LONG
+          - 414 REQUEST_URI_TOO_LONG
+          - 415 UNSUPPORTED_MEDIA_TYPE
+          - 416 REQUESTED_RANGE_NOT_SATISFIABLE
+          - 417 EXPECTATION_FAILED
+          - 418 I_AM_A_TEAPOT
+          - 419 INSUFFICIENT_SPACE_ON_RESOURCE
+          - 420 METHOD_FAILURE
+          - 421 DESTINATION_LOCKED
+          - 422 UNPROCESSABLE_ENTITY
+          - 423 LOCKED
+          - 424 FAILED_DEPENDENCY
+          - 425 TOO_EARLY
+          - 426 UPGRADE_REQUIRED
+          - 428 PRECONDITION_REQUIRED
+          - 429 TOO_MANY_REQUESTS
+          - 431 REQUEST_HEADER_FIELDS_TOO_LARGE
+          - 451 UNAVAILABLE_FOR_LEGAL_REASONS
+          - 500 INTERNAL_SERVER_ERROR
+          - 501 NOT_IMPLEMENTED
+          - 502 BAD_GATEWAY
+          - 503 SERVICE_UNAVAILABLE
+          - 504 GATEWAY_TIMEOUT
+          - 505 HTTP_VERSION_NOT_SUPPORTED
+          - 506 VARIANT_ALSO_NEGOTIATES
+          - 507 INSUFFICIENT_STORAGE
+          - 508 LOOP_DETECTED
+          - 509 BANDWIDTH_LIMIT_EXCEEDED
+          - 510 NOT_EXTENDED
+          - 511 NETWORK_AUTHENTICATION_REQUIRED
+        message:
+          type: string
+          example: Error message
+        code:
+          type: string
+          example: error.service.code
+    DatabaseAccessDto:
+      required:
+      - type
+      - user
+      type: object
+      properties:
+        user:
+          $ref: "#/components/schemas/UserBriefDto"
+        type:
+          type: string
+          enum:
+          - read
+          - write_own
+          - write_all
+    UserUpdateDto:
+      required:
+      - language
+      - theme
+      type: object
+      properties:
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Brown University
+        orcid:
+          type: string
+          example: 0000-0002-1825-0097
+        theme:
+          type: string
+          example: dark
+        language:
+          type: string
+          example: en
+    UserAttributesDto:
+      required:
+      - language
+      - theme
+      type: object
+      properties:
+        theme:
+          type: string
+          example: light
+        orcid:
+          type: string
+          example: https://orcid.org/0000-0002-1825-0097
+        affiliation:
+          type: string
+          example: Brown University
+        language:
+          type: string
+          example: en
+    UserDto:
+      required:
+      - attributes
+      - id
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+          example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4
+        name:
+          type: string
+          example: Josiah Carberry
+        attributes:
+          $ref: "#/components/schemas/UserAttributesDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        qualified_name:
+          type: string
+          example: Josiah Carberry — @jcarberry
+        given_name:
+          type: string
+          example: Josiah
+        family_name:
+          type: string
+          example: Carberry
+    UserPasswordDto:
+      required:
+      - password
+      type: object
+      properties:
+        password:
+          type: string
+    RefreshTokenRequestDto:
+      required:
+      - refresh_token
+      type: object
+      properties:
+        refresh_token:
+          type: string
+          example: refresh_token
+    TokenDto:
+      required:
+      - access_token
+      - expires_in
+      - id_token
+      - not-before-policy
+      - refresh_expires_in
+      - refresh_token
+      - scope
+      - session_state
+      - token_type
+      type: object
+      properties:
+        scope:
+          type: string
+        access_token:
+          type: string
+        expires_in:
+          type: integer
+          format: int64
+        refresh_token:
+          type: string
+        refresh_expires_in:
+          type: integer
+          format: int64
+        id_token:
+          type: string
+        session_state:
+          type: string
+        token_type:
+          type: string
+        not-before-policy:
+          type: integer
+          format: int64
+    OntologyModifyDto:
+      required:
+      - prefix
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: Ontology URI
+        prefix:
+          type: string
+          example: Ontology prefix
+        sparql_endpoint:
+          type: string
+          example: Ontology SPARQL endpoint
+        rdf_path:
+          type: string
+          example: rdf/om-2.0.rdf
+    OntologyDto:
+      required:
+      - id
+      - prefix
+      - rdf
+      - sparql
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+          example: http://www.wikidata.org/
+        prefix:
+          type: string
+          example: wd
+        sparql:
+          type: boolean
+          example: true
+        rdf:
+          type: boolean
+          example: false
+        uri_pattern:
+          type: string
+          example: http://www.wikidata.org/entity/.*
+        sparql_endpoint:
+          type: string
+          example: https://query.wikidata.org/sparql
+        rdf_path:
+          type: string
+          example: rdf/om-2.0.rdf
+    BannerMessageUpdateDto:
+      required:
+      - message
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+        display_start:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        display_end:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+    BannerMessageBriefDto:
+      required:
+      - message
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+    ImageChangeDto:
+      required:
+      - dialect
+      - driver_class
+      - jdbc_method
+      - registry
+      type: object
+      properties:
+        registry:
+          type: string
+          example: docker.io/library
+        defaultPort:
+          maximum: 65535
+          minimum: 1024
+          type: integer
+          format: int32
+          example: 5432
+        dialect:
+          type: string
+          example: Postgres
+        driver_class:
+          type: string
+          example: org.postgresql.Driver
+        jdbc_method:
+          type: string
+          example: postgresql
+    DataTypeDto:
+      required:
+      - display_name
+      - documentation
+      - is_buildable
+      - is_quoted
+      - value
+      type: object
+      properties:
+        value:
+          type: string
+          example: time
+        documentation:
+          type: string
+          example: https://mariadb.com/kb/en/time/
+        display_name:
+          type: string
+          example: TIME(fsp)
+        size_min:
+          type: integer
+          format: int32
+          example: 0
+        size_max:
+          type: integer
+          format: int32
+          example: 6
+        size_default:
+          type: integer
+          format: int32
+          example: 0
+        size_required:
+          type: boolean
+          example: false
+        d_min:
+          type: integer
+          format: int32
+        d_max:
+          type: integer
+          format: int32
+        d_default:
+          type: integer
+          format: int32
+        d_required:
+          type: boolean
+        data_hint:
+          type: string
+          example: "e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S"
+        type_hint:
+          type: string
+          example: "fsp=microsecond precision, min. 0, max. 6"
+        is_quoted:
+          type: boolean
+          description: frontend needs to quote this data type
+          example: false
+        is_buildable:
+          type: boolean
+          description: frontend can build this data type
+          example: true
+    ImageDto:
+      required:
+      - data_types
+      - default
+      - default_port
+      - dialect
+      - driver_class
+      - id
+      - jdbc_method
+      - name
+      - operators
+      - registry
+      - version
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        registry:
+          type: string
+          example: docker.io/library
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+          example: "10.5"
+        dialect:
+          type: string
+          example: org.hibernate.dialect.MariaDBDialect
+        operators:
+          type: array
+          items:
+            $ref: "#/components/schemas/OperatorDto"
+        driver_class:
+          type: string
+          example: org.mariadb.jdbc.Driver
+        jdbc_method:
+          type: string
+          example: mariadb
+        default:
+          type: boolean
+          example: false
+        default_port:
+          type: integer
+          format: int32
+          example: 3306
+        data_types:
+          type: array
+          items:
+            $ref: "#/components/schemas/DataTypeDto"
+    OperatorDto:
+      required:
+      - display_name
+      - documentation
+      - value
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        value:
+          type: string
+          example: XOR
+        documentation:
+          type: string
+          example: https://mariadb.com/kb/en/xor/
+        display_name:
+          type: string
+          example: XOR
+    CreatorSaveDto:
+      required:
+      - creator_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Wesleyan University
+        creator_name:
+          type: string
+          example: "Carberry, Josiah"
+        name_type:
+          type: string
+          example: Personal
+          enum:
+          - Personal
+          - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+          - ORCID
+          - ROR
+          - ISNI
+          - GRID
+        affiliation_identifier:
+          type: string
+          example: https://ror.org/04d836q62
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+          - ROR
+          - GRID
+          - ISNI
+    IdentifierFunderSaveDto:
+      required:
+      - funder_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        funder_name:
+          type: string
+          example: European Commission
+        funder_identifier:
+          type: string
+          example: http://doi.org/10.13039/501100000780
+        funder_identifier_type:
+          type: string
+          example: Crossref Funder ID
+          enum:
+          - Crossref Funder ID
+          - ROR
+          - GND
+          - ISNI
+          - Other
+        scheme_uri:
+          type: string
+          example: http://doi.org/
+        award_number:
+          type: string
+          example: "824087"
+        award_title:
+          type: string
+          example: EOSC-Life
+    IdentifierSaveDescriptionDto:
+      required:
+      - description
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        description:
+          type: string
+          example: "Air quality reports at Stephansplatz, Vienna"
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          example: Abstract
+          enum:
+          - Abstract
+          - Methods
+          - SeriesInformation
+          - TableOfContents
+          - TechnicalInfo
+          - Other
+    IdentifierSaveDto:
+      required:
+      - creators
+      - database_id
+      - id
+      - publication_year
+      - publisher
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        doi:
+          type: string
+          example: 10.1111/11111111
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierSaveTitleDto"
+        descriptions:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierSaveDescriptionDto"
+        funders:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierFunderSaveDto"
+        licenses:
+          type: array
+          items:
+            $ref: "#/components/schemas/LicenseDto"
+        publisher:
+          type: string
+          example: TU Wien
+        language:
+          type: string
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreatorSaveDto"
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+        view_id:
+          type: integer
+          format: int64
+        table_id:
+          type: integer
+          format: int64
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        related_identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/RelatedIdentifierSaveDto"
+    IdentifierSaveTitleDto:
+      required:
+      - id
+      - title
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        title:
+          type: string
+          example: Airquality Demonstrator
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          example: Subtitle
+          enum:
+          - AlternativeTitle
+          - Subtitle
+          - TranslatedTitle
+          - Other
+    LicenseDto:
+      required:
+      - identifier
+      - uri
+      type: object
+      properties:
+        identifier:
+          type: string
+          example: MIT
+        uri:
+          type: string
+          example: https://opensource.org/licenses/MIT
+        description:
+          type: string
+          example: "A short and simple permissive license with conditions only requiring\
+            \ preservation of copyright and license notices. Licensed works, modifications,\
+            \ and larger works may be distributed under different terms and without\
+            \ source code."
+    RelatedIdentifierSaveDto:
+      required:
+      - id
+      - relation
+      - type
+      - value
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        value:
+          type: string
+          example: 10.70124/dc4zh-9ce78
+        type:
+          type: string
+          example: DOI
+          enum:
+          - DOI
+          - URL
+          - URN
+          - ARK
+          - arXiv
+          - bibcode
+          - EAN13
+          - EISSN
+          - Handle
+          - IGSN
+          - ISBN
+          - ISTC
+          - LISSN
+          - LSID
+          - PMID
+          - PURL
+          - UPC
+          - w3id
+        relation:
+          type: string
+          example: Cites
+          enum:
+          - IsCitedBy
+          - Cites
+          - IsSupplementTo
+          - IsSupplementedBy
+          - IsContinuedBy
+          - Continues
+          - IsDescribedBy
+          - Describes
+          - HasMetadata
+          - IsMetadataFor
+          - HasVersion
+          - IsVersionOf
+          - IsNewVersionOf
+          - IsPreviousVersionOf
+          - IsPartOf
+          - HasPart
+          - IsPublishedIn
+          - IsReferencedBy
+          - References
+          - IsDocumentedBy
+          - Documents
+          - IsCompiledBy
+          - Compiles
+          - IsVariantFormOf
+          - IsOriginalFormOf
+          - IsIdenticalTo
+          - IsReviewedBy
+          - Reviews
+          - IsDerivedFrom
+          - IsSourceOf
+          - IsRequiredBy
+          - Requires
+          - IsObsoletedBy
+          - Obsoletes
+    CreatorDto:
+      required:
+      - creator_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        firstname:
+          type: string
+          example: Josiah
+        lastname:
+          type: string
+          example: Carberry
+        affiliation:
+          type: string
+          example: Brown University
+        creator_name:
+          type: string
+          example: "Carberry, Josiah"
+        name_type:
+          type: string
+          example: Personal
+          enum:
+          - Personal
+          - Organizational
+        name_identifier:
+          type: string
+          example: 0000-0002-1825-0097
+        name_identifier_scheme:
+          type: string
+          example: ORCID
+          enum:
+          - ORCID
+          - ROR
+          - ISNI
+          - GRID
+        name_identifier_scheme_uri:
+          type: string
+          example: https://orcid.org/
+        affiliation_identifier:
+          type: string
+          example: https://ror.org/05gq02987
+        affiliation_identifier_scheme:
+          type: string
+          example: ROR
+          enum:
+          - ROR
+          - GRID
+          - ISNI
+        affiliation_identifier_scheme_uri:
+          type: string
+          example: https://ror.org/
+    IdentifierDescriptionDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        description:
+          type: string
+          example: "Air quality reports at Stephansplatz, Vienna"
+        language:
+          type: string
+          example: en
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        type:
+          type: string
+          example: Abstract
+          enum:
+          - Abstract
+          - Methods
+          - SeriesInformation
+          - TableOfContents
+          - TechnicalInfo
+          - Other
+    IdentifierDto:
+      required:
+      - creators
+      - database_id
+      - id
+      - owner
+      - publication_year
+      - publisher
+      - query
+      - query_hash
+      - query_normalized
+      - titles
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        type:
+          type: string
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierTitleDto"
+        descriptions:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDescriptionDto"
+        funders:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierFunderDto"
+        query:
+          type: string
+          example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\
+            \ = \"09:STEF\""
+        execution:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        doi:
+          type: string
+          example: 10.1038/nphys1170
+        publisher:
+          type: string
+          example: TU Wien
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        language:
+          type: string
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        licenses:
+          type: array
+          items:
+            $ref: "#/components/schemas/LicenseDto"
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreatorDto"
+        status:
+          type: string
+          enum:
+          - draft
+          - published
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        view_id:
+          type: integer
+          format: int64
+          example: 1
+        query_normalized:
+          type: string
+          example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\
+            \ = \"09:STEF\""
+        related_identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/RelatedIdentifierDto"
+        query_hash:
+          type: string
+          description: query hash in sha512
+        result_hash:
+          type: string
+          example: 34fe82cda2c53f13f8d90cfd7a3469e3a939ff311add50dce30d9136397bf8e5
+        result_number:
+          type: integer
+          format: int64
+          example: 1
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+    IdentifierFunderDto:
+      required:
+      - funder_name
+      - id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        funder_name:
+          type: string
+          example: European Commission
+        funder_identifier:
+          type: string
+          example: http://doi.org/10.13039/501100000780
+        funder_identifier_type:
+          type: string
+          example: Crossref Funder ID
+          enum:
+          - Crossref Funder ID
+          - ROR
+          - GND
+          - ISNI
+          - Other
+        scheme_uri:
+          type: string
+          example: http://doi.org/
+        award_number:
+          type: string
+          example: "824087"
+        award_title:
+          type: string
+          example: EOSC-Life
+    RelatedIdentifierDto:
+      required:
+      - id
+      - relation
+      - type
+      - value
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        value:
+          type: string
+          example: 10.70124/dc4zh-9ce78
+        type:
+          type: string
+          example: DOI
+          enum:
+          - DOI
+          - URL
+          - URN
+          - ARK
+          - arXiv
+          - bibcode
+          - EAN13
+          - EISSN
+          - Handle
+          - IGSN
+          - ISBN
+          - ISTC
+          - LISSN
+          - LSID
+          - PMID
+          - PURL
+          - UPC
+          - w3id
+        relation:
+          type: string
+          example: Cites
+          enum:
+          - IsCitedBy
+          - Cites
+          - IsSupplementTo
+          - IsSupplementedBy
+          - IsContinuedBy
+          - Continues
+          - IsDescribedBy
+          - Describes
+          - HasMetadata
+          - IsMetadataFor
+          - HasVersion
+          - IsVersionOf
+          - IsNewVersionOf
+          - IsPreviousVersionOf
+          - IsPartOf
+          - HasPart
+          - IsPublishedIn
+          - IsReferencedBy
+          - References
+          - IsDocumentedBy
+          - Documents
+          - IsCompiledBy
+          - Compiles
+          - IsVariantFormOf
+          - IsOriginalFormOf
+          - IsIdenticalTo
+          - IsReviewedBy
+          - Reviews
+          - IsDerivedFrom
+          - IsSourceOf
+          - IsRequiredBy
+          - Requires
+          - IsObsoletedBy
+          - Obsoletes
+    DatabaseModifyVisibilityDto:
+      required:
+      - is_public
+      - is_schema_public
+      type: object
+      properties:
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ViewUpdateDto:
+      required:
+      - is_public
+      - is_schema_public
+      type: object
+      properties:
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ViewColumnDto:
+      required:
+      - auto_generated
+      - database_id
+      - id
+      - internal_name
+      - is_null_allowed
+      - name
+      - ord
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Date
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Column comment
+        database_id:
+          type: integer
+          format: int64
+        ord:
+          type: integer
+          format: int32
+          example: 0
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: mdb_date
+        auto_generated:
+          type: boolean
+          example: false
+        index_length:
+          type: integer
+          format: int64
+        length:
+          type: integer
+          format: int64
+        type:
+          type: string
+          example: string
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+        is_null_allowed:
+          type: boolean
+          example: false
+    ViewDto:
+      required:
+      - columns
+      - database_id
+      - id
+      - internal_name
+      - name
+      - owner
+      - query
+      - query_hash
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: Air Quality
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDto"
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ViewColumnDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        database_id:
+          type: integer
+          format: int64
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        initial_view:
+          type: boolean
+          description: True if it is the default view for the database
+          example: true
+        query_hash:
+          type: string
+          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
+    TableUpdateDto:
+      required:
+      - is_public
+      - is_schema_public
+      type: object
+      properties:
+        description:
+          maxLength: 180
+          minLength: 0
+          type: string
+          example: Air Quality in Austria
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    TableBriefDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - is_public
+      - is_schema_public
+      - is_versioned
+      - name
+      - owned_by
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: Air Quality
+        description:
+          type: string
+          example: Air Quality in Austria
+        database_id:
+          type: integer
+          format: int64
+        internal_name:
+          type: string
+          example: air_quality
+        is_versioned:
+          type: boolean
+          example: true
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        owned_by:
+          type: string
+          format: uuid
+    ColumnSemanticsUpdateDto:
+      type: object
+      properties:
+        concept_uri:
+          type: string
+        unit_uri:
+          type: string
+    ColumnDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - is_null_allowed
+      - name
+      - ord
+      - table_id
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: Given Name
+        alias:
+          type: string
+          example: firstname
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        mean:
+          type: number
+          example: 45.4
+        median:
+          type: number
+          example: 51
+        concept:
+          $ref: "#/components/schemas/ConceptBriefDto"
+        unit:
+          $ref: "#/components/schemas/UnitBriefDto"
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Column comment
+        enums:
+          type: array
+          items:
+            type: string
+        sets:
+          type: array
+          items:
+            type: string
+        database_id:
+          type: integer
+          format: int64
+          example: 2
+        table_id:
+          type: integer
+          format: int64
+          example: 3
+        ord:
+          type: integer
+          format: int32
+          example: 0
+        internal_name:
+          maxLength: 64
+          minLength: 0
+          type: string
+          example: given_name
+        index_length:
+          type: integer
+          format: int64
+          example: 255
+        length:
+          type: integer
+          format: int64
+          example: 255
+        type:
+          type: string
+          example: varchar
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+        data_length:
+          type: integer
+          format: int64
+          example: 34300
+        max_data_length:
+          type: integer
+          format: int64
+          example: 34300
+        num_rows:
+          type: integer
+          format: int64
+          example: 32
+        val_min:
+          type: number
+          example: 0
+        val_max:
+          type: number
+          example: 100
+        std_dev:
+          type: number
+          example: 5.32
+        is_null_allowed:
+          type: boolean
+          example: false
+    ConceptBriefDto:
+      required:
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 23
+        uri:
+          type: string
+          example: http://www.wikidata.org/entity/Q202444
+        name:
+          type: string
+          example: given name
+        description:
+          type: string
+          example: "name typically used to differentiate people from the same family,\
+            \ clan, or other social group who have a common last name"
+    UnitBriefDto:
+      required:
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 34
+        uri:
+          type: string
+          example: http://www.wikidata.org/entity/Q1422583
+        name:
+          type: string
+          example: importance
+        description:
+          type: string
+          example: "subjective magnitude of value, meaning, or purpose"
+    DatabaseTransferDto:
+      required:
+      - id
+      type: object
+      properties:
+        id:
+          type: string
+          format: uuid
+    DatabaseModifyImageDto:
+      type: object
+      properties:
+        key:
+          type: string
+    UpdateDatabaseAccessDto:
+      required:
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - read
+          - write_own
+          - write_all
+    SignupRequestDto:
+      required:
+      - email
+      - password
+      - username
+      type: object
+      properties:
+        username:
+          pattern: "^[a-z0-9]{3,}$"
+          type: string
+          example: user
+        email:
+          type: string
+          example: user@example.com
+        password:
+          type: string
+    LoginRequestDto:
+      required:
+      - password
+      - username
+      type: object
+      properties:
+        username:
+          type: string
+          example: user
+        password:
+          type: string
+    OntologyCreateDto:
+      required:
+      - prefix
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: Ontology URI
+        prefix:
+          type: string
+          example: Ontology prefix
+        sparql_endpoint:
+          type: string
+          example: Ontology SPARQL endpoint
+    BannerMessageCreateDto:
+      required:
+      - message
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+        display_start:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        display_end:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+    ImageCreateDto:
+      required:
+      - default_port
+      - dialect
+      - driver_class
+      - is_default
+      - jdbc_method
+      - name
+      - registry
+      - version
+      type: object
+      properties:
+        registry:
+          type: string
+          example: docker.io/library
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+        dialect:
+          type: string
+        is_default:
+          type: boolean
+          example: false
+        driver_class:
+          type: string
+        jdbc_method:
+          type: string
+        default_port:
+          maximum: 65535
+          minimum: 1024
+          type: integer
+          format: int32
+    IdentifierCreateDto:
+      required:
+      - creators
+      - database_id
+      - publication_year
+      - publisher
+      - titles
+      - type
+      type: object
+      properties:
+        type:
+          type: string
+          example: database
+          enum:
+          - database
+          - subset
+          - table
+          - view
+        doi:
+          type: string
+          example: 10.1111/11111111
+        titles:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierSaveTitleDto"
+        descriptions:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierSaveDescriptionDto"
+        funders:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierFunderSaveDto"
+        licenses:
+          type: array
+          items:
+            $ref: "#/components/schemas/LicenseDto"
+        publisher:
+          type: string
+          example: TU Wien
+        language:
+          type: string
+          enum:
+          - ab
+          - aa
+          - af
+          - ak
+          - sq
+          - am
+          - ar
+          - an
+          - hy
+          - as
+          - av
+          - ae
+          - ay
+          - az
+          - bm
+          - ba
+          - eu
+          - be
+          - bn
+          - bh
+          - bi
+          - bs
+          - br
+          - bg
+          - my
+          - ca
+          - km
+          - ch
+          - ce
+          - ny
+          - zh
+          - cu
+          - cv
+          - kw
+          - co
+          - cr
+          - hr
+          - cs
+          - da
+          - dv
+          - nl
+          - dz
+          - en
+          - eo
+          - et
+          - ee
+          - fo
+          - fj
+          - fi
+          - fr
+          - ff
+          - gd
+          - gl
+          - lg
+          - ka
+          - de
+          - ki
+          - el
+          - kl
+          - gn
+          - gu
+          - ht
+          - ha
+          - he
+          - hz
+          - hi
+          - ho
+          - hu
+          - is
+          - io
+          - ig
+          - id
+          - ia
+          - ie
+          - iu
+          - ik
+          - ga
+          - it
+          - ja
+          - jv
+          - kn
+          - kr
+          - ks
+          - kk
+          - rw
+          - kv
+          - kg
+          - ko
+          - kj
+          - ku
+          - ky
+          - lo
+          - la
+          - lv
+          - lb
+          - li
+          - ln
+          - lt
+          - lu
+          - mk
+          - mg
+          - ms
+          - ml
+          - mt
+          - gv
+          - mi
+          - mr
+          - mh
+          - ro
+          - mn
+          - na
+          - nv
+          - nd
+          - ng
+          - ne
+          - se
+          - "no"
+          - nb
+          - nn
+          - ii
+          - oc
+          - oj
+          - or
+          - om
+          - os
+          - pi
+          - pa
+          - ps
+          - fa
+          - pl
+          - pt
+          - qu
+          - rm
+          - rn
+          - ru
+          - sm
+          - sg
+          - sa
+          - sc
+          - sr
+          - sn
+          - sd
+          - si
+          - sk
+          - sl
+          - so
+          - st
+          - nr
+          - es
+          - su
+          - sw
+          - ss
+          - sv
+          - tl
+          - ty
+          - tg
+          - ta
+          - tt
+          - te
+          - th
+          - bo
+          - ti
+          - to
+          - ts
+          - tn
+          - tr
+          - tk
+          - tw
+          - ug
+          - uk
+          - ur
+          - uz
+          - ve
+          - vi
+          - vo
+          - wa
+          - cy
+          - fy
+          - wo
+          - xh
+          - yi
+          - yo
+          - za
+          - zu
+        creators:
+          type: array
+          items:
+            $ref: "#/components/schemas/CreatorSaveDto"
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        query_id:
+          type: integer
+          format: int64
+        view_id:
+          type: integer
+          format: int64
+        table_id:
+          type: integer
+          format: int64
+        publication_day:
+          type: integer
+          format: int32
+          example: 15
+        publication_month:
+          type: integer
+          format: int32
+          example: 12
+        publication_year:
+          type: integer
+          format: int32
+          example: 2022
+        related_identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/RelatedIdentifierSaveDto"
+    DatabaseCreateDto:
+      required:
+      - container_id
+      - is_public
+      - is_schema_public
+      - name
+      type: object
+      properties:
+        name:
+          type: string
+          example: Air Quality
+        container_id:
+          type: integer
+          format: int64
+          example: 1
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ViewCreateDto:
+      required:
+      - is_public
+      - is_schema_public
+      - name
+      - query
+      type: object
+      properties:
+        name:
+          maxLength: 63
+          minLength: 1
+          type: string
+          example: Air Quality
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality`
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ViewBriefDto:
+      required:
+      - database_id
+      - id
+      - internal_name
+      - name
+      - query
+      - query_hash
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: Air Quality
+        query:
+          type: string
+          example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC
+        database_id:
+          type: integer
+          format: int64
+        internal_name:
+          type: string
+          example: air_quality
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        initial_view:
+          type: boolean
+          description: True if it is the default view for the database
+          example: true
+        query_hash:
+          type: string
+          example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916
+        owned_by:
+          type: string
+          format: uuid
+    ColumnCreateDto:
+      required:
+      - name
+      - null_allowed
+      - type
+      type: object
+      properties:
+        name:
+          type: string
+          example: Date
+        type:
+          type: string
+          example: string
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+        size:
+          type: integer
+          format: int64
+          example: 255
+        d:
+          type: integer
+          format: int64
+          example: 0
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Formatted as YYYY-MM-dd
+        enums:
+          type: array
+          description: "enum values, only considered when type = ENUM"
+          items:
+            type: string
+            description: "enum values, only considered when type = ENUM"
+        sets:
+          type: array
+          description: "set values, only considered when type = SET"
+          items:
+            type: string
+            description: "set values, only considered when type = SET"
+        index_length:
+          type: integer
+          format: int64
+        null_allowed:
+          type: boolean
+          example: true
+        concept_uri:
+          type: string
+        unit_uri:
+          type: string
+    ConstraintsCreateDto:
+      required:
+      - checks
+      - foreign_keys
+      - primary_key
+      - uniques
+      type: object
+      properties:
+        uniques:
+          type: array
+          items:
+            type: array
+            items:
+              type: string
+        checks:
+          uniqueItems: true
+          type: array
+          items:
+            type: string
+        foreign_keys:
+          type: array
+          items:
+            $ref: "#/components/schemas/ForeignKeyCreateDto"
+        primary_key:
+          uniqueItems: true
+          type: array
+          items:
+            type: string
+    ForeignKeyCreateDto:
+      required:
+      - columns
+      - referenced_columns
+      - referenced_table
+      type: object
+      properties:
+        columns:
+          type: array
+          items:
+            type: string
+        referenced_table:
+          type: string
+        referenced_columns:
+          type: array
+          items:
+            type: string
+        on_update:
+          type: string
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+        on_delete:
+          type: string
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+    TableCreateDto:
+      required:
+      - columns
+      - constraints
+      - is_public
+      - is_schema_public
+      - name
+      type: object
+      properties:
+        name:
+          maxLength: 64
+          minLength: 1
+          type: string
+          example: Air Quality
+        description:
+          maxLength: 180
+          minLength: 0
+          type: string
+          example: Air Quality in Austria
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnCreateDto"
+        constraints:
+          $ref: "#/components/schemas/ConstraintsCreateDto"
+        is_public:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+    ContainerCreateDto:
+      required:
+      - host
+      - image_id
+      - name
+      - privileged_password
+      - privileged_username
+      - quota
+      type: object
+      properties:
+        name:
+          type: string
+          example: Air Quality
+        host:
+          type: string
+          description: Hostname of container
+        port:
+          type: integer
+          description: Port of container
+          format: int32
+        quota:
+          type: integer
+          format: int64
+          example: 50
+        image_id:
+          type: integer
+          description: Image ID
+          format: int64
+        ui_host:
+          type: string
+        ui_port:
+          type: integer
+          format: int32
+        privileged_username:
+          type: string
+          description: Username of privileged user
+          example: root
+        privileged_password:
+          type: string
+          description: Password of privileged user
+    ContainerDto:
+      required:
+      - count
+      - id
+      - image
+      - internal_name
+      - name
+      - quota
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: Air Quality
+        image:
+          $ref: "#/components/schemas/ImageDto"
+        quota:
+          type: integer
+          format: int64
+          example: 50
+        count:
+          type: integer
+          format: int64
+          example: 10
+        last_retrieved:
+          type: string
+          format: date-time
+        internal_name:
+          type: string
+          example: data-db
+        ui_host:
+          type: string
+        ui_port:
+          type: integer
+          format: int32
+    ColumnBriefDto:
+      required:
+      - column_type
+      - database_id
+      - id
+      - internal_name
+      - name
+      - table_id
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: date
+        alias:
+          type: string
+        database_id:
+          type: integer
+          format: int64
+        table_id:
+          type: integer
+          format: int64
+        internal_name:
+          type: string
+          example: mdb_date
+        column_type:
+          type: string
+          example: date
+          enum:
+          - char
+          - varchar
+          - binary
+          - varbinary
+          - tinyblob
+          - tinytext
+          - text
+          - blob
+          - mediumtext
+          - mediumblob
+          - longtext
+          - longblob
+          - enum
+          - set
+          - serial
+          - bit
+          - tinyint
+          - bool
+          - smallint
+          - mediumint
+          - int
+          - bigint
+          - float
+          - double
+          - decimal
+          - date
+          - datetime
+          - timestamp
+          - time
+          - year
+    UnitDto:
+      required:
+      - columns
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+        name:
+          type: string
+        description:
+          type: string
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnBriefDto"
+    OntologyBriefDto:
+      required:
+      - id
+      - prefix
+      - rdf
+      - sparql
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+          example: http://www.wikidata.org/
+        prefix:
+          type: string
+          example: wd
+        sparql:
+          type: boolean
+          example: true
+        rdf:
+          type: boolean
+          example: false
+        uri_pattern:
+          type: string
+          example: http://www.wikidata.org/entity/.*
+    EntityDto:
+      required:
+      - label
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: https://www.wikidata.org/entity/Q1686799
+        label:
+          type: string
+          example: Apache Jena
+        description:
+          type: string
+          example: open source semantic web framework for Java
+    OaiListIdentifiersParameters:
+      type: object
+      properties:
+        metadataPrefix:
+          type: string
+        from:
+          type: string
+        until:
+          type: string
+        set:
+          type: string
+        resumptionToken:
+          type: string
+        fromDate:
+          type: string
+          format: date-time
+        untilDate:
+          type: string
+          format: date-time
+        parametersString:
+          type: string
+    BannerMessageDto:
+      required:
+      - id
+      - message
+      - type
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        type:
+          type: string
+          enum:
+          - error
+          - warning
+          - info
+        message:
+          type: string
+          example: Maintenance starts on 8am on Monday
+        link:
+          type: string
+          example: https://example.com
+        link_text:
+          type: string
+          example: More
+        display_start:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+        display_end:
+          type: string
+          format: date-time
+          example: 2021-03-12T15:26:21Z
+    ImageBriefDto:
+      required:
+      - default
+      - id
+      - jdbc_method
+      - name
+      - version
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: mariadb
+        version:
+          type: string
+          example: "10.5"
+        jdbc_method:
+          type: string
+          example: mariadb
+        default:
+          type: boolean
+          example: false
+    LdCreatorDto:
+      required:
+      - '@type'
+      - name
+      type: object
+      properties:
+        name:
+          type: string
+        sameAs:
+          type: string
+        givenName:
+          type: string
+        familyName:
+          type: string
+        '@type':
+          type: string
+    LdDatasetDto:
+      required:
+      - '@context'
+      - '@type'
+      - citation
+      - creator
+      - description
+      - hasPart
+      - identifier
+      - name
+      - temporalCoverage
+      - url
+      - version
+      type: object
+      properties:
+        name:
+          type: string
+        description:
+          type: string
+        url:
+          type: string
+        identifier:
+          type: array
+          items:
+            type: string
+        license:
+          type: string
+        creator:
+          type: array
+          items:
+            $ref: "#/components/schemas/LdCreatorDto"
+        citation:
+          type: string
+        hasPart:
+          type: array
+          items:
+            $ref: "#/components/schemas/LdDatasetDto"
+        temporalCoverage:
+          type: string
+        version:
+          type: string
+          format: date-time
+        '@context':
+          type: string
+        '@type':
+          type: string
+    ConstraintsDto:
+      type: object
+      properties:
+        uniques:
+          type: array
+          items:
+            $ref: "#/components/schemas/UniqueDto"
+        checks:
+          uniqueItems: true
+          type: array
+          items:
+            type: string
+        foreign_keys:
+          type: array
+          items:
+            $ref: "#/components/schemas/ForeignKeyDto"
+        primary_key:
+          uniqueItems: true
+          type: array
+          items:
+            $ref: "#/components/schemas/PrimaryKeyDto"
+    ForeignKeyBriefDto:
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+    ForeignKeyDto:
+      required:
+      - name
+      - referenced_table
+      - references
+      - table
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+        references:
+          type: array
+          items:
+            $ref: "#/components/schemas/ForeignKeyReferenceDto"
+        table:
+          $ref: "#/components/schemas/TableBriefDto"
+        referenced_table:
+          $ref: "#/components/schemas/TableBriefDto"
+        on_update:
+          type: string
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+        on_delete:
+          type: string
+          enum:
+          - restrict
+          - cascade
+          - set_null
+          - no_action
+          - set_default
+    ForeignKeyReferenceDto:
+      required:
+      - column
+      - foreign_key
+      - referenced_column
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        column:
+          $ref: "#/components/schemas/ColumnBriefDto"
+        foreign_key:
+          $ref: "#/components/schemas/ForeignKeyBriefDto"
+        referenced_column:
+          $ref: "#/components/schemas/ColumnBriefDto"
+    PrimaryKeyDto:
+      required:
+      - column
+      - table
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        table:
+          $ref: "#/components/schemas/TableBriefDto"
+        column:
+          $ref: "#/components/schemas/ColumnBriefDto"
+    TableDto:
+      required:
+      - columns
+      - constraints
+      - database_id
+      - id
+      - internal_name
+      - is_public
+      - is_schema_public
+      - is_versioned
+      - name
+      - owner
+      - queue_name
+      - routing_key
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+          example: Air Quality
+        alias:
+          type: string
+        identifiers:
+          type: array
+          items:
+            $ref: "#/components/schemas/IdentifierDto"
+        owner:
+          $ref: "#/components/schemas/UserBriefDto"
+        description:
+          maxLength: 2048
+          minLength: 0
+          type: string
+          example: Air Quality in Austria
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnDto"
+        constraints:
+          $ref: "#/components/schemas/ConstraintsDto"
+        last_retrieved:
+          type: string
+          format: date-time
+        database_id:
+          type: integer
+          format: int64
+        internal_name:
+          type: string
+          example: air_quality
+        is_versioned:
+          type: boolean
+          example: true
+        is_schema_public:
+          type: boolean
+          example: true
+        queue_name:
+          type: string
+          example: air_quality
+        queue_type:
+          type: string
+          example: quorum
+        routing_key:
+          type: string
+          example: dbrepo.1.2
+        is_public:
+          type: boolean
+          example: true
+        num_rows:
+          type: integer
+          format: int64
+          example: 5
+        data_length:
+          type: integer
+          description: in bytes
+          format: int64
+          example: 16384
+        max_data_length:
+          type: integer
+          description: in bytes
+          format: int64
+          example: 0
+        avg_row_length:
+          type: integer
+          description: in bytes
+          format: int64
+          example: 3276
+    UniqueDto:
+      required:
+      - columns
+      - id
+      - name
+      - table
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+        table:
+          $ref: "#/components/schemas/TableBriefDto"
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnDto"
+    TableColumnEntityDto:
+      required:
+      - column_id
+      - database_id
+      - table_id
+      - uri
+      type: object
+      properties:
+        uri:
+          type: string
+          example: https://www.wikidata.org/entity/Q1686799
+        label:
+          type: string
+          example: Apache Jena
+        description:
+          type: string
+          example: open source semantic web framework for Java
+        database_id:
+          type: integer
+          format: int64
+          example: 1
+        table_id:
+          type: integer
+          format: int64
+          example: 1
+        column_id:
+          type: integer
+          format: int64
+          example: 1
+    ContainerBriefDto:
+      required:
+      - count
+      - hash
+      - id
+      - image
+      - internal_name
+      - name
+      - quota
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        hash:
+          type: string
+          example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50
+        name:
+          type: string
+          example: Air Quality
+        image:
+          $ref: "#/components/schemas/ImageBriefDto"
+        quota:
+          type: integer
+          format: int32
+          example: 50
+        count:
+          type: integer
+          format: int32
+          example: 10
+        internal_name:
+          type: string
+          example: air-quality
+    ConceptDto:
+      required:
+      - columns
+      - id
+      - uri
+      type: object
+      properties:
+        id:
+          type: integer
+          format: int64
+        uri:
+          type: string
+        name:
+          type: string
+        description:
+          type: string
+        columns:
+          type: array
+          items:
+            $ref: "#/components/schemas/ColumnBriefDto"
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+    bearerAuth:
+      type: http
+      scheme: bearer
+      bearerFormat: JWT