diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml
index 1b826fedfdaa47fe087d255dff50723d1dc9e25d..1d92839127f3d43db210f8fa1e24b2501a35852a 100644
--- a/.docker/docker-compose.yml
+++ b/.docker/docker-compose.yml
@@ -84,6 +84,12 @@ services:
       - ./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
+<<<<<<< Updated upstream
+=======
+      - ./config/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar
+    ports:
+      - "8080:8080"
+>>>>>>> Stashed changes
     environment:
       KEYCLOAK_ENABLE_HTTPS: "false"
       KEYCLOAK_ENABLE_STATISTICS: "true"
@@ -92,6 +98,9 @@ services:
       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
       interval: 10s
@@ -105,11 +114,39 @@ services:
     logging:
       driver: json-file
 
+<<<<<<< Updated upstream
+=======
+  dbrepo-auth-service-init:
+    init: true
+    restart: "no"
+    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}
+      AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}
+      METADATA_DB: "${METADATA_DB:-dbrepo}"
+      METADATA_DB_PASSWORD: "${METADATA_DB_PASSWORD:-dbrepo}"
+      METADATA_USERNAME: "root"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+    depends_on:
+      dbrepo-auth-service:
+        condition: service_healthy
+      dbrepo-metadata-db:
+        condition: service_healthy
+    logging:
+      driver: json-file
+
+>>>>>>> Stashed changes
   dbrepo-metadata-service:
     restart: "no"
     container_name: dbrepo-metadata-service
     hostname: metadata-service
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
+>>>>>>> Stashed changes
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
@@ -172,7 +209,11 @@ services:
     restart: "no"
     container_name: dbrepo-analyse-service
     hostname: analyse-service
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
+>>>>>>> Stashed changes
     environment:
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
@@ -225,7 +266,11 @@ services:
     restart: "no"
     container_name: dbrepo-search-db
     hostname: search-db
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.3
+>>>>>>> Stashed changes
     healthcheck:
       test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP
       interval: 10s
@@ -249,7 +294,11 @@ services:
     restart: "no"
     container_name: dbrepo-search-service
     hostname: search-service
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
+>>>>>>> Stashed changes
     environment:
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
@@ -292,7 +341,11 @@ services:
     restart: "no"
     container_name: dbrepo-ui
     hostname: ui
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
+>>>>>>> Stashed changes
     environment:
       NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}"
       NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}"
@@ -360,7 +413,11 @@ services:
     init: true
     container_name: dbrepo-search-service-init
     hostname: search-service-init
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
+>>>>>>> Stashed changes
     environment:
       METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}
       OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db}
@@ -414,7 +471,15 @@ services:
     restart: "no"
     container_name: dbrepo-dashboard-service
     hostname: dashboard-service
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.3
+    ports:
+      - "3000:3000"
+    volumes:
+      - dashboard-service-data:/opt/bitnami/grafana/data
+>>>>>>> Stashed changes
     environment:
       LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}"
       LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}"
@@ -435,7 +500,11 @@ services:
     init: true
     container_name: dbrepo-storage-service-init
     hostname: storage-service-init
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
+>>>>>>> Stashed changes
     environment:
       WEED_CLUSTER_SW_MASTER: "${STORAGE_SERVICE_MASTER_ENDPOINT:-storage-service:9333}"
       S3_BUCKET: "${S3_BUCKET:-dbrepo}"
@@ -475,7 +544,11 @@ services:
     restart: "no"
     container_name: dbrepo-data-service
     hostname: data-service
+<<<<<<< Updated upstream
     image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.4.7
+=======
+    image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
+>>>>>>> Stashed changes
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f571fba1d16722ed56e3152dbe634272ebcbd284..16b1ef00c8f8878983faa12ca55a4bfa9cc7a774 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -32,6 +32,95 @@ stages:
   - verify
   - scan
 
+<<<<<<< Updated upstream
+=======
+lint-docker-compose:
+  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:
+    - "bash .scripts/check-compose.sh"
+    - "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'"
+    - "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 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 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 IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'"
+    - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-ui'"
+    - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-upload-service'"
+
+lint-helm-chart:
+  image: docker.io/alpine:${ALPINE_VERSION}
+  stage: lint
+  before_script:
+    - apk --no-cache add helm git bash
+    - cp ./helm/dbrepo/values.schema.json ./CI_values.schema.json
+    - helm plugin install https://github.com/losisin/helm-values-schema-json.git
+    - helm dependency update ./helm/seaweedfs
+    - helm package ./helm/seaweedfs --destination ./build
+    - helm dependency update ./helm/dbrepo
+  script:
+    - bash .scripts/check-helm.sh
+    - helm lint ./helm/dbrepo
+    - helm schema -input ./helm/dbrepo/values.yaml -output ./helm/dbrepo/values.schema.json
+    - diff ./CI_values.schema.json ./helm/dbrepo/values.schema.json
+    - diff ./dbrepo-metadata-db/1_setup-schema.sql ./helm/dbrepo/files/01-setup-schema.sql
+    - diff ./dbrepo-auth-service/listeners/target/create-event-listener.jar ./helm/dbrepo/files/create-event-listener.jar
+  artifacts:
+    when: always
+    paths:
+      - ./helm/dbrepo/values.schema.json
+    expire_in: 1 days
+
+lint-helm-readme:
+  image: docker.io/node:${NODE_VERSION}-alpine${ALPINE_VERSION}
+  stage: lint
+  before_script:
+    - apk --no-cache add alpine-sdk bash git
+    - cp ./helm/dbrepo/README.md ./CI_README.md
+    - git clone https://github.com/bitnami/readme-generator-for-helm
+    - (cd ./readme-generator-for-helm && npm install && npm install -g pkg && pkg . -o /usr/local/sbin/readme-generator)
+  script:
+    - readme-generator --readme ./helm/dbrepo/README.md --values ./helm/dbrepo/values.yaml
+    - diff ./CI_README.md ./helm/dbrepo/README.md
+  artifacts:
+    when: always
+    paths:
+      - ./helm/dbrepo/README.md
+    expire_in: 1 days
+
+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}"
+
+>>>>>>> Stashed changes
 build-metadata-service:
   image: maven:3-openjdk-17
   stage: build
diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock
index bcff34a23efb2e4a660fb11c850aba569369e918..771c2b474b94c937d15f4afd9411f399a1db1816 100644
--- a/dbrepo-analyse-service/Pipfile.lock
+++ b/dbrepo-analyse-service/Pipfile.lock
@@ -1,7 +1,11 @@
 {
     "_meta": {
         "hash": {
+<<<<<<< Updated upstream
             "sha256": "9e1fb16b1632a76b8a2fb6ac372b92556c573a7246bd37dd32813559bb27c8d9"
+=======
+            "sha256": "9cc4c161729b642069bbf4ab379c0f4a9122035afcb3ac7b5b1bfc13281f76aa"
+>>>>>>> Stashed changes
         },
         "pipfile-spec": 6,
         "requires": {
@@ -440,7 +444,11 @@
         },
         "dbrepo": {
             "hashes": [
+<<<<<<< Updated upstream
                 "sha256:84607677b0826bb9b2fa120aacdf56d16c8d9ae423f435b2bd2c22b1c965a33c"
+=======
+                "sha256:7f98329f08d1da6fe45da8130cfb3ebd6e947a4101d46f92b31d7204b29a153d"
+>>>>>>> Stashed changes
             ],
             "markers": "python_version >= '3.11'",
             "path": "./lib/dbrepo-1.4.7.tar.gz"
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..d9c6af3e4a3f6a722cc5d1248c9aafd04a41cbda
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..3e302ea2286d2d6548e9917019397abab93a22e0
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz differ
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..221bdd325f056ff953e0a44a46773470eb08e91e
Binary files /dev/null and b/dbrepo-auth-service/listeners/target/create-event-listener.jar differ
diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile
index bd6d428695f2b85126a0a1b4dea604667510198c..c136386d345a5aca8879212309106ed540f5b1ce 100644
--- a/dbrepo-data-service/Dockerfile
+++ b/dbrepo-data-service/Dockerfile
@@ -6,22 +6,26 @@ LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 FROM maven:3-openjdk-17 AS build
 LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 
+<<<<<<< Updated upstream
 COPY ./pom.xml ./
 
 RUN mvn -fn -B dependency:go-offline
 
+=======
+>>>>>>> Stashed changes
 COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien
 
 COPY ./querystore ./querystore
 COPY ./report ./report
 COPY ./rest-service ./rest-service
 COPY ./services ./services
+COPY ./pom.xml ./
 
 # Make sure it compiles
 RUN mvn clean package -DskipTests
 
 ###### THIRD STAGE ######
-FROM amazoncorretto:17-alpine3.19 AS runtime
+FROM amazoncorretto:17-alpine3.21 AS runtime
 LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 
 RUN apk add --no-cache curl bash jq
@@ -30,7 +34,7 @@ WORKDIR /app
 
 USER 1001
 
-COPY --from=build --chown=1001 ./rest-service/target/rest-service-*.jar ./data-service.jar
+COPY --from=build --chown=1001 ./rest-service/target/data-service.jar ./data-service.jar
 
 # non-root port
 EXPOSE 8080
diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml
index 6517de47460bdf48ad1f31397a1e67416e3dbc31..38125987c8e9c729352c8346abd8da11f23991f1 100644
--- a/dbrepo-data-service/pom.xml
+++ b/dbrepo-data-service/pom.xml
@@ -249,6 +249,7 @@
     </dependencies>
 
     <build>
+        <finalName>data-service</finalName>
         <resources>
             <resource>
                 <directory>${basedir}/src/main/resources</directory>
diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile
index 74e82043731ab8970c2d42b58032f2b5e5b00f3c..18b77afe428e2a93472e1b7fd191187f1bbfaba1 100644
--- a/dbrepo-metadata-service/Dockerfile
+++ b/dbrepo-metadata-service/Dockerfile
@@ -1,5 +1,9 @@
 ###### FIRST STAGE ######
+<<<<<<< Updated upstream
 FROM maven:3-openjdk-17 AS build
+=======
+FROM maven:3-amazoncorretto-17-alpine AS build
+>>>>>>> Stashed changes
 LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 
 COPY ./pom.xml ./
@@ -12,7 +16,11 @@ COPY ./rest-service/pom.xml ./rest-service/
 COPY ./services/pom.xml ./services/
 COPY ./test/pom.xml ./test/
 
+<<<<<<< Updated upstream
 RUN mvn verify -B -fn
+=======
+RUN mvn dependency:go-offline
+>>>>>>> Stashed changes
 
 COPY ./api ./api
 COPY ./entities ./entities
@@ -27,7 +35,7 @@ COPY ./test ./test
 RUN mvn clean install -DskipTests
 
 ###### SECOND STAGE ######
-FROM amazoncorretto:17-alpine3.19 AS runtime
+FROM amazoncorretto:17-alpine3.21 AS runtime
 LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 
 RUN apk add --no-cache curl bash jq
@@ -36,9 +44,9 @@ WORKDIR /app
 
 USER 1001
 
-COPY --from=build --chown=1001 ./rest-service/target/dbrepo-metadata-service-rest-service-*.jar ./metadata-service.jar
+COPY --from=build --chown=1001 ./rest-service/target/metadata-service.jar ./metadata-service.jar
 
 # non-root port
 EXPOSE 8080
 
-ENTRYPOINT ["java", "-Dlog4j2.formatMsgNoLookups=true",  "-jar", "./metadata-service.jar"]
+ENTRYPOINT ["java", "-jar", "./metadata-service.jar"]
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 7e46b80c1cfc745b158f6bffffd02bdd617a1987..d767e25a1647cf9aa2758e87297ba98a49656c7d 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
@@ -14,6 +14,10 @@ import java.time.Instant;
 @Getter
 @Setter
 @Builder
+<<<<<<< Updated upstream
+=======
+@EqualsAndHashCode(callSuper = false)
+>>>>>>> Stashed changes
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
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 dcdb1b944893b63fee80c385aad735d443b43c8a..ca464f33ba477296c3f88a95c588d0877d5f2c38 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
@@ -18,6 +18,10 @@ import java.util.List;
 @Getter
 @Setter
 @Builder
+<<<<<<< Updated upstream
+=======
+@EqualsAndHashCode(callSuper = false)
+>>>>>>> Stashed changes
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
@@ -59,6 +63,14 @@ public class DatabaseDto {
 
     @ToString.Exclude
     @NotNull
+<<<<<<< Updated upstream
+=======
+    @JsonProperty("is_schema_public")
+    @Schema(example = "true")
+    private Boolean isSchemaPublic;
+
+    @NotNull
+>>>>>>> Stashed changes
     private ContainerDto container;
 
     private List<DatabaseAccessDto> accesses;
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 30f16448d36462da23dc27ba38512f61dab58b25..96dfaff1ed0e2b6cae422e99ff86f866043bc93a 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
@@ -19,6 +19,10 @@ import java.util.UUID;
 @Getter
 @Setter
 @Builder
+<<<<<<< Updated upstream
+=======
+@EqualsAndHashCode(callSuper = false)
+>>>>>>> Stashed changes
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
@@ -64,6 +68,7 @@ public class ViewDto {
     @Schema(example = "7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916")
     private String queryHash;
 
+<<<<<<< Updated upstream
     @NotNull
     @Schema(example = "2021-03-12T15:26:21Z")
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
@@ -71,6 +76,10 @@ public class ViewDto {
 
     @JsonIgnore
     private UUID createdBy;
+=======
+    @ToString.Exclude
+    private DatabaseDto database;
+>>>>>>> Stashed changes
 
     @NotNull
     private UserDto creator;
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 a512cf8010195e5c107f35d8d2756251460bca62..794ec747b824d7c084aff2b1adf15bfcb246c52d 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
@@ -21,6 +21,10 @@ import java.util.UUID;
 @Getter
 @Setter
 @Builder
+<<<<<<< Updated upstream
+=======
+@EqualsAndHashCode(callSuper = false)
+>>>>>>> Stashed changes
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
@@ -110,8 +114,13 @@ public class TableDto {
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
     private Instant created;
 
+<<<<<<< Updated upstream
     @NotNull
     private List<ColumnDto> columns;
+=======
+    @ToString.Exclude
+    private DatabaseDto database;
+>>>>>>> Stashed changes
 
     @NotNull
     private ConstraintsDto constraints;
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 00a866bfd2923cc1ae88abc8273cd2d4b912295e..eef0eb5cc0f9d20a7f2d521c07729456253f822c 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
@@ -12,6 +12,10 @@ import java.util.UUID;
 @Getter
 @Setter
 @Builder
+<<<<<<< Updated upstream
+=======
+@EqualsAndHashCode(callSuper = false)
+>>>>>>> Stashed changes
 @NoArgsConstructor
 @AllArgsConstructor
 @Jacksonized
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java
index 7545260ce1a83f2a39b7900e9b29de5e0a4bedde..203b6ccd6abdfdd37b76f5c0a4590b42b295eb05 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java
@@ -61,7 +61,10 @@ public class Container {
     @Column
     private String uiAdditionalFlags;
 
+<<<<<<< Updated upstream
     @ToString.Exclude
+=======
+>>>>>>> Stashed changes
     @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
     @JoinColumns({
             @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false)
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java
index 08f6bd9426a8906d4edc4863ecc6f3540cb39448..cc7df44e9384333dcd3835bbf2d759ae15fb1a22 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java
@@ -23,7 +23,7 @@ import java.util.UUID;
 
 @Data
 @Entity
-@Builder
+@Builder(toBuilder = true)
 @Log4j2
 @ToString
 @AllArgsConstructor
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
index 841dbde754a09a5fdd51cec7872ae4c8a4e5e946..3122eb22195cc8de969d3aac7103acc31d3bcd32 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java
@@ -119,6 +119,14 @@ public class TableColumn implements Comparable<TableColumn> {
     @Column(name = "std_dev")
     private BigDecimal stdDev;
 
+<<<<<<< Updated upstream
+=======
+    @CreatedDate
+    @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP default NOW()")
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
+    private Instant created;
+
+>>>>>>> Stashed changes
     @LastModifiedDate
     @Column(columnDefinition = "TIMESTAMP")
     private Instant lastModified;
diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml
index a2de622dcacd12a615c2d8dc0f536df88ebc87dd..dfecd7779409533e7a85bff9b71350af02e9ad9a 100644
--- a/dbrepo-metadata-service/pom.xml
+++ b/dbrepo-metadata-service/pom.xml
@@ -96,6 +96,10 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>
         <!-- Open API -->
         <dependency>
             <groupId>org.springdoc</groupId>
@@ -268,6 +272,7 @@
     </dependencies>
 
     <build>
+        <finalName>metadata-service</finalName>
         <resources>
             <resource>
                 <directory>${basedir}/src/main/resources</directory>
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java
index d68185102a00e33419ae8cf2c4250c0775082a23..2cf18262d3069f6369026e64508a687f3d2e419a 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java
@@ -4,7 +4,7 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 @ResponseStatus(code = HttpStatus.BAD_GATEWAY, reason = "error.search.connection")
-public class SearchServiceConnectionException extends Exception {
+public class SearchServiceConnectionException extends RuntimeException {
 
     public SearchServiceConnectionException(String msg) {
         super(msg);
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java
index aef3ae7f7cd75db6ec7ed59f95980f2c8e021c2b..528b3aadd1e0cdd0ea9ef6c19374f29b8d62ab15 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java
@@ -4,7 +4,7 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
 @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.search.invalid")
-public class SearchServiceException extends Exception {
+public class SearchServiceException extends RuntimeException {
 
     public SearchServiceException(String message) {
         super(message);
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 738e30d4e48aba2dc52703d0ca2bd3cb53b2b63a..7c706ca18bcd430f1a0b7d569e37a9e9b86ba1af 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,12 @@
 package at.tuwien.endpoints;
 
+<<<<<<< Updated upstream
 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.TableBriefDto;
+>>>>>>> Stashed changes
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
@@ -351,10 +356,73 @@ public class TableEndpoint {
         endpointValidator.validateOnlyAccess(database, principal, true);
         endpointValidator.validateColumnCreateConstraints(data);
         final Table table = tableService.createTable(database, data, principal);
+<<<<<<< Updated upstream
         final TableDto dto = metadataMapper.customTableToTableDto(table);
         log.info("Created table with id {}", dto.getId());
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(dto);
+=======
+        return ResponseEntity.status(HttpStatus.CREATED)
+                .body(metadataMapper.tableToTableBriefDto(table));
+    }
+
+    @PutMapping("/{tableId}")
+    @Transactional(rollbackFor = {Exception.class})
+    @PreAuthorize("hasAuthority('update-table')")
+    @Observed(name = "dbrepo_table_update")
+    @Operation(summary = "Update table",
+            description = "Updates a table in the database with id. Requires role `update-table`.",
+            security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "202",
+                    description = "Updated the table",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = TableBriefDto.class))}),
+            @ApiResponse(responseCode = "400",
+                    description = "Update table visibility payload is malformed",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "403",
+                    description = "Update table visibility not permitted",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "404",
+                    description = "Table could not be found",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "502",
+                    description = "Connection to search service failed",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "503",
+                    description = "Failed to save in search service",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
+    })
+    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={}",
+                databaseId, data.getIsPublic(), data.getIsSchemaPublic(), principal.getName());
+        final Database database = databaseService.findById(databaseId);
+        final Table table = tableService.findById(database, tableId);
+        if (!table.getOwner().getId().equals(getId(principal))) {
+            log.error("Failed to update table: not owner");
+            throw new NotAllowedException("Failed to update table: not owner");
+        }
+        return ResponseEntity.accepted()
+                .body(metadataMapper.tableToTableBriefDto(
+                        tableService.updateTable(table, data)));
+>>>>>>> Stashed changes
     }
 
     @GetMapping("/{tableId}")
diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json b/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json
deleted file mode 100644
index 3779d12cbe32b67fa163cf6b0285b9e01f7dc681..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json
+++ /dev/null
@@ -1,15 +0,0 @@
-[
-  {
-    "name": "",
-    "size": {
-      "min": 0,
-      "required": true
-    },
-    "d": {
-      "required": false
-    },
-    "documentation": "https://mariadb.com/kb/en/bigint/",
-    "quoted": false,
-    "buildable": true
-  }
-]
\ No newline at end of file
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 aa1c9d4f056f61680aeb341f2cebafdbe262a2b5..148b2d31b80a65718806a2afbc05e4c4ab40d7cd 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
@@ -37,7 +37,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest {
     @Test
     public void update_succeeds() throws DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException {
+<<<<<<< Updated upstream
         final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.ACCEPTED)
+=======
+        final ResponseEntity<DatabaseDto> mock = ResponseEntity.accepted()
+>>>>>>> Stashed changes
                 .build();
 
         /* mock */
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 648bb6ab290b319a817aba31d49310d43416e4a3..9ce405b4f208313412fcaebfdc5c047f94b0c4cb 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
@@ -38,8 +38,7 @@ import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 @ExtendWith(SpringExtension.class)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@@ -138,8 +137,14 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
         /* mock */
         when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)))
                 .thenReturn(mock);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         dataCiteIdentifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_DTO);
@@ -153,8 +158,14 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
         doThrow(HttpClientErrorException.BadRequest.class)
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference));
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         assertThrows(MalformedException.class, () -> {
@@ -170,8 +181,14 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
         doThrow(RestClientException.class)
                 .when(restTemplate)
                 .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference));
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         assertThrows(DataServiceConnectionException.class, () -> {
@@ -330,8 +347,14 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest {
             IdentifierNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* 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 1e7633b851f9c052fd8fe60d14193698565421f3..a5e00468b99a086390937213a31f9f02737bc628 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
@@ -88,6 +88,263 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
+<<<<<<< Updated upstream
+=======
+    public void updatePassword_succeeds() throws DataServiceException, DatabaseNotFoundException,
+            DataServiceConnectionException {
+
+        /* mock */
+        when(databaseRepository.findAllAtLestReadAccessDesc(USER_1_ID))
+                .thenReturn(List.of(DATABASE_1));
+        doNothing()
+                .when(dataServiceGateway)
+                .updateDatabase(eq(DATABASE_1_ID), any(UpdateUserPasswordDto.class));
+
+        /* test */
+        databaseService.updatePassword(DATABASE_1, USER_1);
+    }
+
+    @Test
+    public void modifyImage_succeeds() throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException {
+        final byte[] image = new byte[]{1, 2, 3, 4, 5};
+
+        /* mock */
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.modifyImage(DATABASE_1, image);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void modifyImage_searchServiceNotFound_fails() throws SearchServiceException, DatabaseNotFoundException,
+            SearchServiceConnectionException {
+        final byte[] image = new byte[]{1, 2, 3, 4, 5};
+
+        /* mock */
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doThrow(DatabaseNotFoundException.class)
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            databaseService.modifyImage(DATABASE_1, image);
+        });
+    }
+
+    @Test
+    public void modifyImage_searchServiceConnection_fails() throws SearchServiceException, DatabaseNotFoundException,
+            SearchServiceConnectionException {
+        final byte[] image = new byte[]{1, 2, 3, 4, 5};
+
+        /* mock */
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doThrow(SearchServiceConnectionException.class)
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        assertThrows(SearchServiceConnectionException.class, () -> {
+            databaseService.modifyImage(DATABASE_1, image);
+        });
+    }
+
+    @Test
+    public void updateViewMetadata_empty_succeeds() throws SearchServiceException, DataServiceException,
+            QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException,
+            DataServiceConnectionException, ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceGateway.getViewSchemas(DATABASE_1_ID))
+                .thenReturn(List.of());
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.updateViewMetadata(DATABASE_1);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void updateViewMetadata_searchServiceConnection_fails() throws SearchServiceException, DataServiceException,
+            DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException,
+            ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceGateway.getViewSchemas(DATABASE_1_ID))
+                .thenReturn(List.of());
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doThrow(SearchServiceConnectionException.class)
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        assertThrows(SearchServiceConnectionException.class, () -> {
+            databaseService.updateViewMetadata(DATABASE_1);
+        });
+    }
+
+    @Test
+    public void updateViewMetadata_searchServiceNotFound_fails() throws SearchServiceException, DataServiceException,
+            DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException,
+            ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceGateway.getViewSchemas(DATABASE_1_ID))
+                .thenReturn(List.of());
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doThrow(DatabaseNotFoundException.class)
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            databaseService.updateViewMetadata(DATABASE_1);
+        });
+    }
+
+    @Test
+    public void updateViewMetadata_oneMissing_succeeds() throws SearchServiceException, DataServiceException,
+            QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException,
+            DataServiceConnectionException, ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceGateway.getViewSchemas(DATABASE_1_ID))
+                .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO, VIEW_4_DTO)); /* <<< */
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.updateViewMetadata(DATABASE_1);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void updateViewMetadata_allKnown_succeeds() throws SearchServiceException, DataServiceException,
+            QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException,
+            DataServiceConnectionException, ViewNotFoundException {
+
+        /* mock */
+        when(dataServiceGateway.getViewSchemas(DATABASE_1_ID))
+                .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)); /* <<< */
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.updateViewMetadata(DATABASE_1);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void updateTableMetadata_empty_succeeds() throws TableNotFoundException, SearchServiceException,
+            MalformedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException,
+            SearchServiceConnectionException, DataServiceConnectionException {
+
+        /* mock */
+        when(dataServiceGateway.getTableSchemas(DATABASE_1_ID))
+                .thenReturn(List.of());
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.updateTableMetadata(DATABASE_1);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void updateTableMetadata_allKnown_succeeds() throws TableNotFoundException, SearchServiceException,
+            MalformedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException,
+            SearchServiceConnectionException, DataServiceConnectionException {
+
+        /* mock */
+        when(dataServiceGateway.getTableSchemas(DATABASE_1_ID))
+                .thenReturn(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO));
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.updateTableMetadata(DATABASE_1);
+        assertNotNull(response);
+    }
+
+    @Test
+    public void updateTableMetadata_oneMissing_succeeds() throws TableNotFoundException, SearchServiceException,
+            MalformedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException,
+            SearchServiceConnectionException, DataServiceConnectionException {
+
+        /* mock */
+        when(dataServiceGateway.getTableSchemas(DATABASE_1_ID))
+                .thenReturn(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO, TABLE_5_DTO));
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final Database response = databaseService.updateTableMetadata(DATABASE_1);
+        assertNotNull(response);
+        final Optional<Table> optional = response.getTables()
+                .stream()
+                .filter(t -> t.getInternalName().equals(TABLE_5_INTERNALNAME))
+                .findFirst();
+        assertTrue(optional.isPresent());
+        final Table table = optional.get();
+        table.getColumns()
+                .forEach(column -> {
+                    assertNotNull(column.getTable());
+                    assertEquals(TABLE_5_ID, column.getTable().getId());
+                });
+        table.getConstraints()
+                .getUniques()
+                .forEach(uk -> {
+                    assertNotNull(uk.getTable());
+                    assertEquals(TABLE_5_ID, uk.getTable().getId());
+                });
+        table.getConstraints()
+                .getForeignKeys()
+                .forEach(fk -> {
+                    assertNotNull(fk.getTable());
+                    assertEquals(TABLE_5_ID, fk.getTable().getId());
+                });
+        table.getConstraints()
+                .getPrimaryKey()
+                .forEach(pk -> {
+                    assertNotNull(pk.getTable());
+                    assertEquals(TABLE_5_ID, pk.getTable().getId());
+                    assertEquals(TABLE_5_COLUMNS.get(0), pk.getColumn());
+                });
+    }
+
+    @Test
+>>>>>>> Stashed changes
     public void find_succeeds() throws DatabaseNotFoundException {
 
         /* mock */
@@ -272,8 +529,14 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest {
             ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException {
 
         /* mock */
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
         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 246ae7de1a4beb7a55f4cadf13f142b48ef995fd..1c44828ea73878740ee665936490ee11ddc3ba12 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
@@ -35,6 +35,7 @@ import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.when;
 
 @Log4j2
@@ -174,8 +175,14 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
         /* mock */
         when(dataServiceGateway.findQuery(IDENTIFIER_5_DATABASE_ID, IDENTIFIER_5_QUERY_ID))
                 .thenReturn(QUERY_2_DTO);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_2_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         identifierService.save(DATABASE_2, USER_2, IDENTIFIER_5_SAVE_DTO);
@@ -284,8 +291,14 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest {
             SearchServiceConnectionException {
 
         /* mock */
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         identifierService.delete(IDENTIFIER_1);
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 7aa22159c395046548324a714d7d8274fc8114af..59ab266765863c7e812722b14c607b10b957ac5a 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,16 @@
 package at.tuwien.service;
 
+<<<<<<< Updated upstream
 import at.tuwien.api.database.table.TableCreateDto;
 import at.tuwien.api.database.table.columns.ColumnCreateDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
 import at.tuwien.api.database.table.constraints.ConstraintsCreateDto;
+=======
+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.database.table.constraints.CreateTableConstraintsDto;
+>>>>>>> Stashed changes
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
@@ -107,8 +114,14 @@ public class TableServicePersistenceTest extends AbstractUnitTest {
         doNothing()
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, request);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* 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 551a6c350a95e1c9a22fb55d72e04530386cb522..7bae3ac6df8f8ae5c2dabe891ffdf71fa76b36f9 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
@@ -106,12 +106,161 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(Optional.empty());
 
         /* test */
+<<<<<<< Updated upstream
+=======
+        assertThrows(TableNotFoundException.class, () -> {
+            tableService.findByName(DATABASE_3, TABLE_1_INTERNAL_NAME);
+        });
+    }
+
+    @Test
+    public void updateStatistics_succeeds() throws TableNotFoundException, DataServiceException,
+            DataServiceConnectionException, SearchServiceException, DatabaseNotFoundException,
+            SearchServiceConnectionException, MalformedException {
+
+        /* mock */
+        when(dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_STATISTIC_DTO);
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        tableService.updateStatistics(TABLE_8);
+    }
+
+    @Test
+    public void updateStatistics_searchServiceNotFound_fails() throws TableNotFoundException, DataServiceException,
+            DataServiceConnectionException, SearchServiceException, DatabaseNotFoundException,
+            SearchServiceConnectionException {
+
+        /* mock */
+        when(dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_STATISTIC_DTO);
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doThrow(DatabaseNotFoundException.class)
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+>>>>>>> Stashed changes
         assertThrows(DatabaseNotFoundException.class, () -> {
             tableService.findByName(DATABASE_3_ID, TABLE_1_INTERNALNAME);
         });
     }
 
     @Test
+<<<<<<< Updated upstream
+=======
+    public void updateStatistics_searchServiceConnection_fails() throws TableNotFoundException, DataServiceException,
+            DataServiceConnectionException, SearchServiceException, DatabaseNotFoundException,
+            SearchServiceConnectionException {
+
+        /* mock */
+        when(dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(TABLE_8_STATISTIC_DTO);
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doThrow(SearchServiceConnectionException.class)
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        assertThrows(SearchServiceConnectionException.class, () -> {
+            tableService.updateStatistics(TABLE_8);
+        });
+    }
+
+    @Test
+    public void updateStatistics_columnNotFound_fails() throws TableNotFoundException, DataServiceException,
+            DataServiceConnectionException {
+        final TableStatisticDto mock = TableStatisticDto.builder()
+                .columns(new HashMap<>() {{
+                    put("unknown_column", ColumnStatisticDto.builder()
+                            .min(BigDecimal.valueOf(11.2))
+                            .max(BigDecimal.valueOf(23.1))
+                            .mean(BigDecimal.valueOf(13.5333))
+                            .median(BigDecimal.valueOf(11.4))
+                            .stdDev(BigDecimal.valueOf(4.2952))
+                            .build());
+                }})
+                .build();
+
+        /* mock */
+        when(dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID))
+                .thenReturn(mock);
+
+        /* test */
+        assertThrows(MalformedException.class, () -> {
+            tableService.updateStatistics(TABLE_8);
+        });
+    }
+
+    @Test
+    public void update_known_succeeds() throws SearchServiceException, MalformedException, DataServiceException,
+            DatabaseNotFoundException, OntologyNotFoundException, SearchServiceConnectionException,
+            SemanticEntityNotFoundException, DataServiceConnectionException, UnitNotFoundException,
+            ConceptNotFoundException {
+        final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
+                .unitUri(UNIT_1_URI)
+                .conceptUri(CONCEPT_1_URI)
+                .build();
+
+        /* mock */
+        when(unitService.find(UNIT_1_URI))
+                .thenReturn(UNIT_1);
+        when(conceptService.find(CONCEPT_1_URI))
+                .thenReturn(CONCEPT_1);
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request);
+        assertNotNull(response.getUnit());
+        assertNotNull(response.getConcept());
+    }
+
+    @Test
+    public void update_unknown_succeeds() throws SearchServiceException, MalformedException, DataServiceException,
+            DatabaseNotFoundException, OntologyNotFoundException, SearchServiceConnectionException,
+            SemanticEntityNotFoundException, DataServiceConnectionException, UnitNotFoundException,
+            ConceptNotFoundException {
+        final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder()
+                .unitUri(UNIT_1_URI)
+                .conceptUri(CONCEPT_1_URI)
+                .build();
+
+        /* mock */
+        doThrow(UnitNotFoundException.class)
+                .when(unitService)
+                .find(UNIT_1_URI);
+        when(entityService.findOneByUri(UNIT_1_URI))
+                .thenReturn(UNIT_1_ENTITY_DTO);
+        doThrow(ConceptNotFoundException.class)
+                .when(conceptService)
+                .find(CONCEPT_1_URI);
+        when(entityService.findOneByUri(CONCEPT_1_URI))
+                .thenReturn(CONCEPT_1_ENTITY_DTO);
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_1);
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+
+        /* test */
+        final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request);
+        assertNotNull(response.getUnit());
+        assertNotNull(response.getConcept());
+    }
+
+    @Test
+>>>>>>> Stashed changes
     public void createTable_succeeds() throws DataServiceException, DataServiceConnectionException,
             UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException,
             SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException,
@@ -125,8 +274,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class));
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL);
@@ -162,8 +317,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class));
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, request, USER_1_PRINCIPAL);
@@ -215,8 +376,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
                 .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class));
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         assertThrows(MalformedException.class, () -> {
@@ -238,8 +405,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         doNothing()
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, TABLE_3_CREATE_DTO);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL);
@@ -259,8 +432,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         doThrow(DataServiceException.class)
                 .when(dataServiceGateway)
                 .createTable(DATABASE_1_ID, TABLE_5_CREATE_DTO);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         assertThrows(DataServiceException.class, () -> {
@@ -357,8 +536,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         doNothing()
                 .when(dataServiceGateway)
                 .deleteTable(DATABASE_1_ID, TABLE_1_ID);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         tableService.deleteTable(TABLE_1);
@@ -373,8 +558,14 @@ public class TableServiceUnitTest extends AbstractUnitTest {
         doNothing()
                 .when(dataServiceGateway)
                 .deleteTable(DATABASE_1_ID, TABLE_4_ID);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         tableService.deleteTable(TABLE_4);
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..c4c8b8bd8c944b8d4769c30250d59e73cf6a858e 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
@@ -88,8 +88,14 @@ public class ViewServicePersistenceTest extends AbstractUnitTest {
         doNothing()
                 .when(dataServiceGateway)
                 .deleteView(DATABASE_1_ID, VIEW_1_ID);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* 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..44a0a78d9e17528616173794613edc6f49b3807f 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
@@ -61,8 +61,14 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(VIEW_1_DTO);
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         final View response = viewService.create(DATABASE_1, USER_1, request);
@@ -116,8 +122,14 @@ public class ViewServiceUnitTest extends AbstractUnitTest {
                 .deleteView(DATABASE_1_ID, VIEW_1_ID);
         when(databaseRepository.save(any(Database.class)))
                 .thenReturn(DATABASE_1);
+<<<<<<< Updated upstream
         when(searchServiceGateway.update(any(Database.class)))
                 .thenReturn(DATABASE_1_DTO);
+=======
+        doNothing()
+                .when(searchServiceGateway)
+                .update(any(Database.class));
+>>>>>>> Stashed changes
 
         /* test */
         viewService.delete(VIEW_1);
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
index 0bcace730e7753b1dd21d2e1d4a91f47bda6b9f3..1559281af3462181248e492b5facb2bc89429388 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -1,15 +1,27 @@
 package at.tuwien.config;
 
+import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.auth.InternalRequestInterceptor;
+import at.tuwien.exception.AccountNotSetupException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.CredentialsInvalidException;
 import at.tuwien.gateway.KeycloakGateway;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
+import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
+import org.springframework.web.reactive.function.client.WebClient;
 import org.springframework.web.util.DefaultUriBuilderFactory;
 
+import java.util.List;
+
 @Log4j2
 @Getter
 @Configuration
@@ -89,4 +101,27 @@ public class GatewayConfig {
         return restTemplate;
     }
 
+    @Bean
+    public WebClient webClient() {
+        return WebClient.builder()
+                .baseUrl(searchEndpoint)
+                .filter(internalFilter())
+                .build();
+    }
+
+    private ExchangeFilterFunction internalFilter() {
+        return (request, next) -> {
+            final HttpHeaders headers = request.headers();
+            headers.setAccept(List.of(MediaType.APPLICATION_JSON));
+            try {
+                final TokenDto token = keycloakGateway.obtainUserToken(getSystemUsername(), getSystemPassword());
+                headers.setBearerAuth(token.getAccessToken());
+                return next.exchange(request);
+            } catch (AuthServiceConnectionException | CredentialsInvalidException | AccountNotSetupException e) {
+                log.error("Failed to obtain token for internal user: {}", e.getMessage());
+            }
+            return next.exchange(request);
+        };
+    }
+
 }
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..16a6c731b1907eddbbed22fd5f43ddd556659ee5 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,21 @@
 package at.tuwien.gateway;
 
+<<<<<<< Updated upstream
 import at.tuwien.api.database.DatabaseDto;
+=======
+>>>>>>> Stashed changes
 import at.tuwien.entities.database.Database;
-import at.tuwien.exception.*;
+import at.tuwien.exception.DatabaseNotFoundException;
+import at.tuwien.exception.SearchServiceConnectionException;
+import at.tuwien.exception.SearchServiceException;
 
 public interface SearchServiceGateway {
 
+<<<<<<< Updated upstream
     DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException;
+=======
+    void update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException;
+>>>>>>> Stashed changes
 
     void delete(Long databaseId) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException;
 }
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 d97483beb1cac9e590b43a2cdf409067f8eb4d74..f2bed1f846476c58ba903b5ccd8d60bd48a56c0c 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
@@ -11,29 +11,39 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.*;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
+import org.springframework.web.reactive.function.client.WebClient;
 
 @Log4j2
 @Service
 public class SearchServiceGatewayImpl implements SearchServiceGateway {
 
+    private final WebClient webClient;
     private final RestTemplate restTemplate;
     private final GatewayConfig gatewayConfig;
     private final MetadataMapper metadataMapper;
 
     @Autowired
-    public SearchServiceGatewayImpl(@Qualifier("searchServiceRestTemplate") RestTemplate restTemplate,
+    public SearchServiceGatewayImpl(WebClient webClient, @Qualifier("searchServiceRestTemplate") RestTemplate restTemplate,
                                     GatewayConfig gatewayConfig, MetadataMapper metadataMapper) {
+        this.webClient = webClient;
         this.restTemplate = restTemplate;
         this.gatewayConfig = gatewayConfig;
         this.metadataMapper = metadataMapper;
     }
 
     @Override
+<<<<<<< Updated upstream
     public DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException {
+=======
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public void update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException {
+>>>>>>> Stashed changes
         final ResponseEntity<DatabaseDto> response;
         final HttpHeaders headers = new HttpHeaders();
         headers.set("Accept", "application/json");
@@ -42,7 +52,11 @@ 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<>(
+<<<<<<< Updated upstream
                     metadataMapper.customDatabaseToDatabaseDto(database), headers), DatabaseDto.class);
+=======
+                    metadataMapper.databaseToDatabaseDto(database), headers), DatabaseDto.class);
+>>>>>>> Stashed changes
         } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable |
                  HttpServerErrorException.InternalServerError e) {
             log.error("Failed to update database: {}", e.getMessage());
@@ -58,7 +72,6 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway {
             log.error("Failed to update database: response code is not 202");
             throw new SearchServiceException("Failed to update database: response code is not 202");
         }
-        return response.getBody();
     }
 
     @Override
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 4866fea2c10b8afa3bb4f93f2eedb3d2aa8f1ad7..34fd6d0fcb093fb64d2878f2dc0940e0dfbac3dc 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
@@ -2,8 +2,13 @@ package at.tuwien.service.impl;
 
 import at.tuwien.api.database.table.TableCreateDto;
 import at.tuwien.api.database.table.TableStatisticDto;
+<<<<<<< Updated upstream
 import at.tuwien.api.database.table.columns.ColumnCreateDto;
+=======
+import at.tuwien.api.database.table.TableUpdateDto;
+>>>>>>> Stashed changes
 import at.tuwien.api.database.table.columns.ColumnStatisticDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
 import at.tuwien.config.RabbitConfig;
 import at.tuwien.entities.database.Database;
@@ -21,6 +26,7 @@ import at.tuwien.service.*;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.security.Principal;
@@ -94,11 +100,15 @@ public class TableServiceImpl implements TableService {
     }
 
     @Override
+<<<<<<< Updated upstream
     @Transactional
     public Table createTable(Database database, TableCreateDto data, Principal principal) throws DataServiceException,
+=======
+    @Transactional(propagation = Propagation.REQUIRED)
+    public Table createTable(Database database, CreateTableDto data, Principal principal) throws DataServiceException,
+>>>>>>> Stashed changes
             DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException,
-            TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException,
-            OntologyNotFoundException, SemanticEntityNotFoundException {
+            TableExistsException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException {
         final User owner = userService.findByUsername(principal.getName());
         /* map table */
         final Table table = Table.builder()
@@ -256,9 +266,8 @@ public class TableServiceImpl implements TableService {
 
     @Override
     @Transactional
-    public void updateStatistics(Table table) throws SearchServiceException,
-            DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException,
-            DataServiceException, DataServiceConnectionException {
+    public void updateStatistics(Table table) throws MalformedException, TableNotFoundException, DataServiceException,
+            DataServiceConnectionException, DatabaseNotFoundException {
         final TableStatisticDto statistic = dataServiceGateway.getTableStatistics(table.getTdbid(), table.getId());
         if (statistic == null) {
             return;
@@ -289,7 +298,6 @@ public class TableServiceImpl implements TableService {
         /* update in open search service */
         searchServiceGateway.update(database);
         log.info("Updated statistics for the table and {} column(s)", table.getColumns().size());
-        log.trace("updated statistics: {}", table);
     }
 
 }
diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock
index 123e864f6dd050a838ae2c7e9137a4d7b3f1e27f..e4917444da8eb3659bda8af0326e082fad0835a9 100644
--- a/dbrepo-search-service/Pipfile.lock
+++ b/dbrepo-search-service/Pipfile.lock
@@ -1,7 +1,11 @@
 {
     "_meta": {
         "hash": {
+<<<<<<< Updated upstream
             "sha256": "491e5f6ada48e8af417dfa7d6a0b4d98ccf9b9072df53b44d8de014b687fc80c"
+=======
+            "sha256": "2ff9fc673f1fb1e5dc272aa711f4e730088fa0188b44449db042abf99b6c4db7"
+>>>>>>> Stashed changes
         },
         "pipfile-spec": 6,
         "requires": {
@@ -388,9 +392,15 @@
         },
         "dbrepo": {
             "hashes": [
+<<<<<<< Updated upstream
                 "sha256:84607677b0826bb9b2fa120aacdf56d16c8d9ae423f435b2bd2c22b1c965a33c"
             ],
             "path": "./lib/dbrepo-1.4.7.tar.gz"
+=======
+                "sha256:7f98329f08d1da6fe45da8130cfb3ebd6e947a4101d46f92b31d7204b29a153d"
+            ],
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
+>>>>>>> Stashed changes
         },
         "docker": {
             "hashes": [
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..d9c6af3e4a3f6a722cc5d1248c9aafd04a41cbda
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..3e302ea2286d2d6548e9917019397abab93a22e0
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.3-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..d9c6af3e4a3f6a722cc5d1248c9aafd04a41cbda
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..3e302ea2286d2d6548e9917019397abab93a22e0
Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts
index 3d87e68d4febed8b825a56b1aada946bd6b0f4d5..9670f16e56d61192b8be1ca8cd8380c2cbb470cc 100644
--- a/dbrepo-ui/composables/table-service.ts
+++ b/dbrepo-ui/composables/table-service.ts
@@ -230,13 +230,6 @@ export const useTableService = (): any => {
     }
   }
 
-  function isOwner(table: TableDto, user: UserDto) {
-    if (!table || !user) {
-      return false
-    }
-    return table.owner.id === user.id
-  }
-
   function tableNameToInternalName(name: string) {
     return name.normalize('NFKD')
       .toLowerCase()
@@ -271,7 +264,6 @@ export const useTableService = (): any => {
     suggest,
     prepareColumns,
     prepareConstraints,
-    isOwner,
     tableNameToInternalName
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue
index 432b14e21a60968048440da6f0084eb535aa06a7..9d6acbcf4b2999e6c1728962c11b1691c18b7ec8 100644
--- a/dbrepo-ui/pages/database/[database_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/info.vue
@@ -112,8 +112,16 @@
                 v-if="access"
                 :title="$t('pages.database.connection.title')"
                 density="compact">
+<<<<<<< Updated upstream
                 <pre
                   class="pb-1">{{ jdbcString }}</pre>
+=======
+                <div>
+                  <UserBadge
+                    :user="database.owner"
+                    :other-user="cacheUser" />
+                </div>
+>>>>>>> Stashed changes
               </v-list-item>
               <v-list-item
                 v-if="database.contact"
@@ -122,7 +130,7 @@
                 <div>
                   <UserBadge
                     :user="database.contact"
-                    :other-user="user" />
+                    :other-user="cacheUser" />
                 </div>
               </v-list-item>
             </v-list>
@@ -181,6 +189,7 @@
   </div>
 </template>
 
+<<<<<<< Updated upstream
 <script setup>
 const config = useRuntimeConfig()
 const { database_id } = useRoute().params
@@ -191,6 +200,8 @@ if (data.value) {
   useServerSeoMeta(identifierService.databaseToServerSeoMeta(data.value))
 }
 </script>
+=======
+>>>>>>> Stashed changes
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
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 9da3e1c9fd9774ca61be0be90af9a7050d6fba3c..32862334e8718ab82e64e20ce6e05b1440f8e020 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
@@ -83,6 +83,9 @@ export default {
     table () {
       return this.cacheStore.getTable
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     title () {
       if (!this.table) {
         return this.$t('pages.table.import.title')
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 0221c64df232721f3a81b6bf2641ad37ce6fbf32..90ca284f0af300859cba5f713ce848bfdf192048 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
@@ -152,6 +152,8 @@
     </v-card>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
+  <pre>table={{ table }}</pre>
+  <pre>access={{ access }}</pre>
 </template>
 
 <script setup>
@@ -234,14 +236,35 @@ export default {
     roles () {
       return this.userStore.getRoles
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canRead () {
-      if (this.database && this.database.is_public) {
+      if (!this.database || !this.access || this.database.is_public) {
         return true
       }
+<<<<<<< Updated upstream
       if (!this.user || !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)
+    },
+    canViewInfo () {
+      if (this.error || !this.table) {
+        return false
+      }
+      if (this.table.is_public || this.table.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
+>>>>>>> Stashed changes
     },
     canWrite () {
       if (!this.table || !this.user || !this.access) {
@@ -255,9 +278,12 @@ export default {
       }
       return formatTimestampUTCLabel(this.table.created)
     },
+<<<<<<< Updated upstream
     access () {
       return this.userStore.getAccess
     },
+=======
+>>>>>>> Stashed changes
     hasDescription () {
       return this.table && this.table.description
     },
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
new file mode 100644
index 0000000000000000000000000000000000000000..90a03e649b52e42e02a9b65331f653ab44d34e07
--- /dev/null
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
@@ -0,0 +1,329 @@
+<template>
+  <div
+    v-if="canUpdateTable">
+    <TableToolbar />
+    <v-window
+      v-model="tab">
+      <v-window-item>
+        <v-form
+          ref="form"
+          v-model="valid"
+          autocomplete="off"
+          @submit.prevent="submit">
+          <v-card
+            variant="flat"
+            rounded="0"
+            :title="$t('pages.table.settings.title')"
+            :subtitle="$t('pages.table.settings.subtitle')">
+            <v-card-text>
+              <v-row>
+                <v-col
+                  md="8">
+                  <v-textarea
+                    v-model="modify.description"
+                    rows="2"
+                    :rules="[
+                      v => max(v, 180) || ($t('validation.max-length') + 180),
+                    ]"
+                    clearable
+                    counter="180"
+                    persistent-counter
+                    persistent-hint
+                    :variant="inputVariant"
+                    :hint="$t('pages.table.subpages.import.description.hint')"
+                    :label="$t('pages.table.subpages.import.description.label')"/>
+                </v-col>
+              </v-row>
+              <v-row
+                dense>
+                <v-col
+                  md="4">
+                  <v-select
+                    v-model="modify.is_public"
+                    :items="dataOptions"
+                    persistent-hint
+                    :variant="inputVariant"
+                    required
+                    :rules="[
+                      v => v !== null || $t('validation.required')
+                    ]"
+                    :label="$t('pages.database.resource.data.label')"
+                    :hint="$t('pages.database.resource.data.hint', { resource: 'table' })" />
+                </v-col>
+                <v-col
+                  md="4">
+                  <v-select
+                    v-model="modify.is_schema_public"
+                    :items="schemaOptions"
+                    persistent-hint
+                    :variant="inputVariant"
+                    required
+                    :rules="[
+                      v => v !== null || $t('validation.required')
+                    ]"
+                    :label="$t('pages.database.resource.schema.label')"
+                    :hint="$t('pages.database.resource.schema.hint', { resource: 'table', schema: 'columns' })" />
+                </v-col>
+              </v-row>
+              <v-row>
+                <v-col>
+                  <v-btn
+                    id="database"
+                    variant="flat"
+                    size="small"
+                    :disabled="!valid || !isChange"
+                    :color="buttonColor"
+                    :loading="loading"
+                    type="submit"
+                    :text="$t('navigation.modify')"
+                    @click="update" />
+                </v-col>
+              </v-row>
+            </v-card-text>
+          </v-card>
+        </v-form>
+        <v-divider
+          v-if="canDropTable" />
+        <v-card
+          v-if="canDropTable"
+          variant="flat"
+          rounded="0"
+          :title="$t('pages.table.delete.title')"
+          :subtitle="$t('pages.table.delete.subtitle', { table: table.internal_name })">
+          <v-card-text>
+            <v-row>
+              <v-col
+                md="8">
+                <v-btn
+                  size="small"
+                  variant="flat"
+                  color="error"
+                  @click="askDelete">
+                  {{ $t('navigation.delete')}}
+                </v-btn>
+              </v-col>
+            </v-row>
+          </v-card-text>
+        </v-card>
+      </v-window-item>
+    </v-window>
+    <v-breadcrumbs
+      :items="items"
+      class="pa-0 mt-2" />
+  </div>
+</template>
+
+<script>
+import TableToolbar from '@/components/table/TableToolbar.vue'
+import { useCacheStore } from '@/stores/cache.js'
+import { max } from '@/utils'
+
+export default {
+  components: {
+    TableToolbar
+  },
+  data () {
+    return {
+      tab: 0,
+      valid: false,
+      loading: false,
+      modify: {
+        description: null,
+        is_public: null,
+        is_schema_public: null
+      },
+      dataOptions: [
+        { title: this.$t('pages.database.resource.data.enabled'), value: true },
+        { title: this.$t('pages.database.resource.data.disabled'), value: false },
+      ],
+      schemaOptions: [
+        { title: this.$t('pages.database.resource.schema.enabled'), value: true },
+        { title: this.$t('pages.database.resource.schema.disabled'), value: false },
+      ],
+      items: [
+        {
+          title: this.$t('navigation.databases'),
+          to: '/database'
+        },
+        {
+          title: `${this.$route.params.database_id}`,
+          to: `/database/${this.$route.params.database_id}/info`
+        },
+        {
+          title: this.$t('navigation.tables'),
+          to: `/database/${this.$route.params.database_id}/table`
+        },
+        {
+          title: `${this.$route.params.table_id}`,
+          to: `/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}`
+        },
+        {
+          title: this.$t('navigation.settings'),
+          to: `/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/settings`,
+          disabled: true
+        }
+      ],
+      headers: [
+        { value: 'internal_name', title: this.$t('pages.table.subpages.schema.internal-name.title') },
+        { value: 'type', title: this.$t('pages.table.subpages.schema.column-type.title') },
+        { value: 'extra', title: this.$t('pages.table.subpages.schema.extra.title') },
+        { value: 'column_concept', title: this.$t('pages.table.subpages.schema.concept.title') },
+        { value: 'column_unit', title: this.$t('pages.table.subpages.schema.unit.title') },
+        { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') },
+        { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
+      ],
+      dateColumns: [],
+      cacheStore: useCacheStore()
+    }
+  },
+  computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
+    table () {
+      return this.cacheStore.getTable
+    },
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    isChange () {
+      if (!this.table) {
+        return false
+      }
+      if (this.table.is_public !== this.modify.is_public) {
+        return true
+      }
+      return this.table.is_schema_public !== this.modify.is_schema_public
+    },
+    canUpdateTable () {
+      if (!this.cacheUser || !this.table || !this.access || !this.roles || !this.roles.includes('update-table')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
+    },
+    canDropTable () {
+      if (!this.roles || !this.table || !this.cacheUser) {
+        return false
+      }
+      if (this.roles.includes('delete-foreign-table')) {
+        return true
+      }
+      return this.table.owner.id === this.cacheUser.uid && this.roles.includes('delete-table') && this.table.identifiers.length === 0
+    },
+    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
+    },
+    buttonColor () {
+      return !this.isChange ? null : 'warning'
+    }
+  },
+  mounted() {
+    if (!this.table) {
+      return
+    }
+    this.modify.is_public = this.table.is_public
+    this.modify.is_schema_public = this.table.is_schema_public
+    this.modify.description = this.table.description
+  },
+  methods: {
+    max,
+    submit () {
+      this.$refs.form.validate()
+    },
+    extra (column) {
+      if (column.type === 'float') {
+        return `precision=${column.size}`
+      } else if (['decimal', 'double'].includes(column.type)) {
+        let extra = ''
+        if (column.size !== null) {
+          extra += `size=${column.size}`
+        }
+        if (column.d !== null) {
+          if (extra.length > 0) {
+            extra += ', '
+          }
+          extra += `d=${column.d}`
+        }
+        return extra
+      } else if (column.type === 'enum') {
+        return `(${column.enums.join(', ')})`
+      } else if (column.type === 'set') {
+        return `(${column.sets.join(', ')})`
+      } else if (['int', 'char', 'varchar', 'binary', 'varbinary', 'tinyint', 'size="small"int', 'mediumint', 'bigint'].includes(column.type)) {
+        return column.size !== null ? `size=${column.size}` : ''
+      }
+      return null
+    },
+    closed (event) {
+      const { success } = event
+      console.debug('closed dialog', event)
+      if (success) {
+        const toast = useToastInstance()
+        toast.success(this.$t('success.table.semantics'))
+        this.cacheStore.reloadTable()
+      }
+      this.dialogSemantic = false
+    },
+    update () {
+      this.loading = true
+      const tableService = useTableService()
+      tableService.update(this.$route.params.database_id, this.$route.params.table_id, this.modify)
+        .then(() => {
+          this.loading = false
+          const toast = useToastInstance()
+          toast.success(this.$t('success.table.updated', { table: this.table.internal_name }))
+          this.$emit('close', { success: true })
+          this.cacheStore.reloadTable()
+        })
+        .catch(({ code }) => {
+          this.loading = false
+          const toast = useToastInstance()
+          if (typeof code !== 'string') {
+            return
+          }
+          toast.error(this.$t(code))
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    },
+    askDelete () {
+      if (!confirm(this.$t('pages.table.delete.subtitle', { table: this.table.internal_name }))) {
+        return
+      }
+      this.loadingDelete = true
+      const tableService = useTableService()
+      tableService.remove(this.database.id, this.table.id)
+        .then(() => {
+          console.info('Deleted table with id ', this.table.id)
+          this.cacheStore.reloadDatabase()
+          const toast = useToastInstance()
+          toast.success('Successfully deleted table with id ' + this.table.id)
+          this.$router.push(`/database/${this.$route.params.database_id}/table`)
+        })
+        .catch(({code, message}) => {
+          const toast = useToastInstance()
+          if (typeof code !== 'string') {
+            return
+          }
+          toast.error(this.$t(code))
+        })
+        .finally(() => {
+          this.loadingDelete = false
+        })
+    }
+  }
+}
+</script>
diff --git a/dbrepo-ui/pages/database/[database_id]/view/create.vue b/dbrepo-ui/pages/database/[database_id]/view/create.vue
index 839b79e243d4ceb7903e8a81ee9da0306d29697a..bdb9e4e7056ab97dbabb77abaf1be456c695d1c8 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue
@@ -1,12 +1,20 @@
 <template>
+<<<<<<< Updated upstream
   <div v-if="canCreateView">
     <Builder mode="view" />
+=======
+  <div
+    v-if="canCreateView">
+    <Builder
+      mode="view" />
+>>>>>>> Stashed changes
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
 
 <script>
 import Builder from '@/components/subset/Builder.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -33,7 +41,11 @@ export default {
           disabled: true
         }
       ],
+<<<<<<< Updated upstream
       userStore: useUserStore()
+=======
+      cacheStore: useCacheStore()
+>>>>>>> Stashed changes
     }
   },
   computed: {
@@ -44,7 +56,7 @@ export default {
       return this.userStore.getRoles
     },
     canCreateView () {
-      if (!this.roles) {
+      if (!this.roles || !this.access) {
         return false
       }
       return this.roles.includes('create-database-view')
diff --git a/dbrepo-ui/pages/database/[database_id]/view/index.vue b/dbrepo-ui/pages/database/[database_id]/view/index.vue
index dc87510ae887285ac36fc647e8f2a172cb708784..7ee5736216b79d84dd94eb386bafd91e6d7ed855 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/index.vue
@@ -1,5 +1,10 @@
 <template>
+<<<<<<< Updated upstream
   <div>
+=======
+  <div
+    v-if="canViewViews">
+>>>>>>> Stashed changes
     <DatabaseToolbar />
     <v-window v-model="tab">
       <ViewList />
@@ -39,8 +44,29 @@ export default {
     }
   },
   computed: {
+<<<<<<< Updated upstream
     tab () {
       return 1
+=======
+    database () {
+      return this.cacheStore.getDatabase
+    },
+    access () {
+      return this.cacheStore.getAccess
+    },
+    canViewViews () {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_schema_public || this.database.is_public) {
+        return true
+      }
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
+>>>>>>> Stashed changes
     }
   },
   mounted () {
diff --git a/dbrepo-ui/pages/user/index.vue b/dbrepo-ui/pages/user/index.vue
index e729d9086f2be6604c2b9d0222c00acc79297f85..d53b2f42cc8bd7966db208242ad0a8b1736b3428 100644
--- a/dbrepo-ui/pages/user/index.vue
+++ b/dbrepo-ui/pages/user/index.vue
@@ -2,6 +2,9 @@
   <div />
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import { useUserStore } from '@/stores/user'
 
diff --git a/docker-compose.yml b/docker-compose.yml
index 86c47b6af9cf29978dbb01b92481a586e3f3b7e0..2f6d10f1c49ffdb2b23241db3f1da3a265aaa74c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -20,8 +20,6 @@ services:
       - metadata-db-data:/bitnami/mariadb
       - ./dbrepo-metadata-db/1_setup-schema.sql:/docker-entrypoint-initdb.d/1_setup-schema.sql
       - ./dbrepo-metadata-db/2_setup-data.sql:/docker-entrypoint-initdb.d/2_setup-data.sql
-    ports:
-      - "3306:3306"
     environment:
       MARIADB_DATABASE: "${METADATA_DB:-dbrepo}"
       MARIADB_ROOT_PASSWORD: "${METADATA_DB_PASSWORD:-dbrepo}"
@@ -118,7 +116,7 @@ services:
       context: ./dbrepo-metadata-service
       network: host
     ports:
-      - "9099:8080"
+      - "9099:18080"
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
diff --git a/helm/dbrepo/files/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar
new file mode 100644
index 0000000000000000000000000000000000000000..221bdd325f056ff953e0a44a46773470eb08e91e
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 557d99072513ec0330848d467db2501982853c0e..5e645184f8c8ba43dd7a4439593015a5a5b7768c 100644
--- a/helm/dbrepo/templates/auth-configmap.yaml
+++ b/helm/dbrepo/templates/auth-configmap.yaml
@@ -4,6 +4,9 @@ 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 | nindent 4 }}
 data:
   KC_HOSTNAME_PATH: "/api/auth"
   KC_HOSTNAME_ADMIN_URL: "{{ .Values.gateway }}/api/auth"
diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml
index 68c2e4e06fed820f6c5858efdce9bcf97550fada..5adce66ac803347cefc626687b9e113364ad7c7d 100644
--- a/helm/dbrepo/values.yaml
+++ b/helm/dbrepo/values.yaml
@@ -115,7 +115,20 @@ authservice:
   ## @skip authservice.extraVolumeMounts
   extraVolumeMounts:
     - name: config-map
+<<<<<<< Updated upstream
       mountPath: /opt/bitnami/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/
+>>>>>>> Stashed changes
   ## @skip authservice.replicaCount The number of replicas.
   replicaCount: 2
 
@@ -126,6 +139,7 @@ datadb:
   enabled: true
   ## @skip datadb.fullnameOverride
   fullnameOverride: data-db
+<<<<<<< Updated upstream
   database:
     image:
       ## @param datadb.database.image.debug Set the logging level to `trace`. Otherwise, set to `info`.
@@ -143,6 +157,46 @@ datadb:
       replicationUser: replication
       ## @param datadb.auth.replicationPassword The database replication user password
       replicationPassword: replication
+=======
+  ## @param datadb.host The hostname for the microservices.
+  host: data-db
+  ## @param datadb.extraFlags Extra flags to ensure the query store works as intended, ref https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/api/data-db/#data
+  extraFlags: "--character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci"
+  rootUser:
+    ## @param datadb.rootUser.user The root username.
+    user: root
+    ## @param datadb.rootUser.password The root user password.
+    password: dbrepo
+  db:
+    ## @param datadb.db.name The database name.
+    name: dbrepo
+  galera:
+    mariabackup:
+      ## @param datadb.galera.mariabackup.user The database backup username.
+      user: backup
+      ## @param datadb.galera.mariabackup.password The database backup user password
+      password: backup
+  ## @param datadb.jdbcExtraArgs The extra arguments for JDBC connections in the microservices.
+  jdbcExtraArgs: ""
+  metrics:
+    ## @skip datadb.metrics.enabled The Prometheus settings.
+    enabled: true
+  ## @param datadb.replicaCount The number of cluster nodes, should be uneven i.e. 2n+1
+  replicaCount: 3
+  resources:
+    resources:
+      limits:
+        cpu: 750m
+        ephemeral-storage: 2Gi
+        memory: 1536Mi
+      requests:
+        cpu: 500m
+        ephemeral-storage: 50Mi
+        memory: 1000Mi
+  persistence:
+    ## @param datadb.persistence.enabled Enable persistent storage.
+    enabled: true
+>>>>>>> Stashed changes
 
 ## @section Search Database
 
diff --git a/make/dev.mk b/make/dev.mk
index 76c05989eb224c0ca0625f4d380f6467b8688f2f..3ede2683dfdcb62e5e5a16ce29c0de67513ae5ba 100644
--- a/make/dev.mk
+++ b/make/dev.mk
@@ -27,4 +27,9 @@ package-config: ## Package the config files
 	cp ./dbrepo-gateway-service/dbrepo.conf ./.docker/config
 	cp ./dbrepo-metric-db/prometheus.yml ./.docker/config
 	cp ./dbrepo-storage-service/s3_config.json ./.docker/config
+<<<<<<< Updated upstream
+=======
+	cp ./dbrepo-upload-service/pre-create.sh ./.docker/config
+	cp ./dbrepo-auth-service/listeners/target/create-event-listener.jar ./.docker/config
+>>>>>>> Stashed changes
 	cd ./.docker && tar czf ./dist.tar.gz ./docker-compose.yml ./.env ./config