Repository: apache/streampipes
Pull request #2961 (2024-06-26 18:53:24)

chore: Reduce complexity of couchdb persistence layer
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You under the Apache License, Version 2.0
  ~ (the "License"); you may not use this file except in compliance with
  ~ the License.  You may obtain a copy of the License at
  ~
  ~    http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  ~
  -->

  <!--
Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
1. If this is your first time, please read our contributor guidelines:
    - https://streampipes.apache.org/community/get-involved/
    - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
4. Please write your PR title to summarize what this PR proposes/fixes.
5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar.
6. Be sure to keep the PR description updated to reflect all changes.
7. If possible, provide a concise example to reproduce the issue for a faster review.
8. Make sure tests pass via `mvn clean install`.
9. (Optional) If the contribution is large, please file an Apache ICLA
    - http://apache.org/licenses/icla.pdf
-->

### Purpose
<!--
Please clarify what changes you are proposing and describe how those changes will address the issue.
Furthermore, describe potential consequences the changes might have.
-->

First PR to reduce complexity of the storage layer by harmonizing the interfaces. I also introduced a new interface `Storable` which makes sure that consistent ID descriptors are used for items stored in the document storage.

For some resources (e.g., `Dashboard`), the default serialized ID has changed (e.g., from `couchDbId` to `elementId` for better consistency), we need to check if this affects the Python or Go client.

### Remarks
<!--
Is there anything left we need to pay attention on?
Are there some references that might be important? E.g. links to Confluence, or discussions
on the mailing list or GitHub.
-->
PR introduces (a) breaking change(s): <yes/no>

PR introduces (a) deprecation(s): <yes/no>



Patch:
diff --git a/pom.xml b/pom.xml
index 6e57309277..4aee27daea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -95,7 +95,7 @@
         <micrometer-prometheus.version>1.12.0</micrometer-prometheus.version>
         <micrometer-observation.version>1.12.0</micrometer-observation.version>
         <mqtt-client.version>1.12</mqtt-client.version>
-        <nats.version>2.18.0</nats.version>
+        <nats.version>2.19.1</nats.version>
         <netty.version>4.1.72.Final</netty.version>
         <okhttp.version>3.13.1</okhttp.version>
         <opencsv.version>5.9</opencsv.version>
diff --git a/streampipes-client-python/poetry.lock b/streampipes-client-python/poetry.lock
index 62c217f9af..1cccd6e5a4 100644
--- a/streampipes-client-python/poetry.lock
+++ b/streampipes-client-python/poetry.lock
@@ -1777,12 +1777,12 @@ files = [
 
 [[package]]
 name = "nats-py"
-version = "2.7.2"
+version = "2.8.0"
 description = "NATS client for Python"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "nats-py-2.7.2.tar.gz", hash = "sha256:0c97b4a57bed0ef1ff9ae6c19bc115ec7ca8ede5ab3e001fd00a377056a547cf"},
+    {file = "nats_py-2.8.0.tar.gz", hash = "sha256:e998dcacd711db3b90b469dcdd96c526cc56c421bad27be0f5f40e88005a7c44"},
 ]
 
 [package.extras]
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java
index 40eb818c2a..d6cac01c7d 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java
@@ -23,7 +23,7 @@ import org.apache.streampipes.dataexplorer.utils.DataExplorerUtils;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.datalake.DataLakeMeasureSchemaUpdateStrategy;
 import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.storage.api.IDataLakeStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -34,9 +34,9 @@ import java.util.stream.Stream;
 
 public class DataExplorerSchemaManagement implements IDataExplorerSchemaManagement {
 
-  IDataLakeStorage dataLakeStorage;
+  CRUDStorage<String, DataLakeMeasure> dataLakeStorage;
 
-  public DataExplorerSchemaManagement(IDataLakeStorage dataLakeStorage) {
+  public DataExplorerSchemaManagement(CRUDStorage<String, DataLakeMeasure> dataLakeStorage) {
     this.dataLakeStorage = dataLakeStorage;
   }
 
@@ -47,7 +47,7 @@ public class DataExplorerSchemaManagement implements IDataExplorerSchemaManageme
 
   @Override
   public DataLakeMeasure getById(String elementId) {
-    return dataLakeStorage.findOne(elementId);
+    return dataLakeStorage.getElementById(elementId);
   }
 
   /**
@@ -92,7 +92,7 @@ public class DataExplorerSchemaManagement implements IDataExplorerSchemaManageme
    * Returns the existing measure that has the provided measure name
    */
   private Optional<DataLakeMeasure> getExistingMeasureByName(String measureName) {
-    return dataLakeStorage.getAllDataLakeMeasures()
+    return dataLakeStorage.findAll()
                           .stream()
                           .filter(m -> m.getMeasureName()
                                         .equals(measureName))
@@ -107,8 +107,8 @@ public class DataExplorerSchemaManagement implements IDataExplorerSchemaManageme
 
   @Override
   public void deleteMeasurement(String elementId) {
-    if (dataLakeStorage.findOne(elementId) != null) {
-      dataLakeStorage.deleteDataLakeMeasure(elementId);
+    if (dataLakeStorage.getElementById(elementId) != null) {
+      dataLakeStorage.deleteElementById(elementId);
     } else {
       throw new IllegalArgumentException("Could not find measure with this ID");
     }
@@ -116,14 +116,14 @@ public class DataExplorerSchemaManagement implements IDataExplorerSchemaManageme
 
   @Override
   public boolean deleteMeasurementByName(String measureName) {
-    var measureToDeleteOpt = dataLakeStorage.getAllDataLakeMeasures()
+    var measureToDeleteOpt = dataLakeStorage.findAll()
                                             .stream()
                                             .filter(measurement -> measurement.getMeasureName()
                                                                                .equals(measureName))
                                             .findFirst();
 
     return measureToDeleteOpt.map(measure -> {
-      dataLakeStorage.deleteDataLakeMeasure(measure.getElementId());
+      dataLakeStorage.deleteElementById(measure.getElementId());
       return true;
     }
     ).orElse(false);
@@ -131,18 +131,18 @@ public class DataExplorerSchemaManagement implements IDataExplorerSchemaManageme
 
   @Override
   public void updateMeasurement(DataLakeMeasure measure) {
-    var existingMeasure = dataLakeStorage.findOne(measure.getElementId());
+    var existingMeasure = dataLakeStorage.getElementById(measure.getElementId());
     if (existingMeasure != null) {
       measure.setRev(existingMeasure.getRev());
-      dataLakeStorage.updateDataLakeMeasure(measure);
+      dataLakeStorage.updateElement(measure);
     } else {
-      dataLakeStorage.storeDataLakeMeasure(measure);
+      dataLakeStorage.persist(measure);
     }
   }
 
   private void setSchemaVersionAndStoreMeasurement(DataLakeMeasure measure) {
     measure.setSchemaVersion(DataLakeMeasure.CURRENT_SCHEMA_VERSION);
-    dataLakeStorage.storeDataLakeMeasure(measure);
+    dataLakeStorage.persist(measure);
   }
 
   /**
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/utils/DataExplorerUtils.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/utils/DataExplorerUtils.java
index a0b5125653..b9c5942fd9 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/utils/DataExplorerUtils.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/utils/DataExplorerUtils.java
@@ -28,6 +28,6 @@ public class DataExplorerUtils {
     return StorageDispatcher.INSTANCE
         .getNoSqlStore()
         .getDataLakeStorage()
-        .getAllDataLakeMeasures();
+        .findAll();
   }
 }
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
index 9ce7713c3b..35354044f8 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
@@ -33,18 +33,18 @@ public class DashboardResolver extends AbstractResolver<DashboardModel> {
 
   @Override
   public DashboardModel findDocument(String resourceId) {
-    return getNoSqlStore().getDashboardStorage().getDashboard(resourceId);
+    return getNoSqlStore().getDashboardStorage().getElementById(resourceId);
   }
 
   @Override
   public DashboardModel modifyDocumentForExport(DashboardModel doc) {
-    doc.setCouchDbRev(null);
+    doc.setRev(null);
     return doc;
   }
 
   @Override
   protected boolean existsDoc(DashboardModel doc) {
-    return Objects.nonNull(doc) && doc.getCouchDbId() != null;
+    return Objects.nonNull(doc) && doc.getElementId() != null;
   }
 
   @Override
@@ -54,12 +54,12 @@ public class DashboardResolver extends AbstractResolver<DashboardModel> {
 
   @Override
   public ExportItem convert(DashboardModel document) {
-    return new ExportItem(document.getCouchDbId(), document.getName(), true);
+    return new ExportItem(document.getElementId(), document.getName(), true);
   }
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getDashboardStorage().storeDashboard(deserializeDocument(document));
+    getNoSqlStore().getDashboardStorage().persist(deserializeDocument(document));
   }
 
   @Override
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java
index 2c50b6ca7f..73632e97e3 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java
@@ -28,7 +28,7 @@ public class DashboardWidgetResolver extends AbstractResolver<DashboardWidgetMod
 
   @Override
   public DashboardWidgetModel findDocument(String resourceId) {
-    return getNoSqlStore().getDashboardWidgetStorage().getDashboardWidget(resourceId);
+    return getNoSqlStore().getDashboardWidgetStorage().getElementById(resourceId);
   }
 
   @Override
@@ -44,12 +44,12 @@ public class DashboardWidgetResolver extends AbstractResolver<DashboardWidgetMod
 
   @Override
   public ExportItem convert(DashboardWidgetModel document) {
-    return new ExportItem(document.getId(), document.getVisualizationName(), true);
+    return new ExportItem(document.getElementId(), document.getVisualizationName(), true);
   }
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getDashboardWidgetStorage().storeDashboardWidget(deserializeDocument(document));
+    getNoSqlStore().getDashboardWidgetStorage().persist(deserializeDocument(document));
   }
 
   @Override
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
index 499c3503b4..a20aa0b2a9 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
@@ -49,7 +49,7 @@ public class DataSourceResolver extends AbstractResolver<SpDataStream> {
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getDataStreamStorage().createElement(deserializeDocument(document));
+    getNoSqlStore().getDataStreamStorage().persist(deserializeDocument(document));
   }
 
   public void writeDocument(String document,
@@ -60,7 +60,7 @@ public class DataSourceResolver extends AbstractResolver<SpDataStream> {
         overrideProtocol(dataStream.getEventGrounding());
       }
     }
-    getNoSqlStore().getDataStreamStorage().createElement(dataStream);
+    getNoSqlStore().getDataStreamStorage().persist(dataStream);
   }
 
   @Override
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java
index e9f5317081..59513bb543 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java
@@ -34,18 +34,18 @@ public class DataViewResolver extends AbstractResolver<DashboardModel> {
 
   @Override
   public DashboardModel findDocument(String resourceId) {
-    return getNoSqlStore().getDataExplorerDashboardStorage().getDashboard(resourceId);
+    return getNoSqlStore().getDataExplorerDashboardStorage().getElementById(resourceId);
   }
 
   @Override
   public DashboardModel modifyDocumentForExport(DashboardModel doc) {
-    doc.setCouchDbRev(null);
+    doc.setRev(null);
     return doc;
   }
 
   @Override
   protected boolean existsDoc(DashboardModel doc) {
-    return Objects.nonNull(doc) && doc.getCouchDbId() != null;
+    return Objects.nonNull(doc) && doc.getElementId() != null;
   }
 
   @Override
@@ -55,12 +55,12 @@ public class DataViewResolver extends AbstractResolver<DashboardModel> {
 
   @Override
   public ExportItem convert(DashboardModel document) {
-    return new ExportItem(document.getCouchDbId(), document.getName(), true);
+    return new ExportItem(document.getElementId(), document.getName(), true);
   }
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getDataExplorerDashboardStorage().storeDashboard(deserializeDocument(document));
+    getNoSqlStore().getDataExplorerDashboardStorage().persist(deserializeDocument(document));
   }
 
   @Override
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java
index a39926a0ac..a1b004b19e 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java
@@ -28,7 +28,7 @@ public class DataViewWidgetResolver extends AbstractResolver<DataExplorerWidgetM
 
   @Override
   public DataExplorerWidgetModel findDocument(String resourceId) {
-    return getNoSqlStore().getDataExplorerWidgetStorage().getDataExplorerWidget(resourceId);
+    return getNoSqlStore().getDataExplorerWidgetStorage().getElementById(resourceId);
   }
 
   @Override
@@ -44,12 +44,12 @@ public class DataViewWidgetResolver extends AbstractResolver<DataExplorerWidgetM
 
   @Override
   public ExportItem convert(DataExplorerWidgetModel document) {
-    return new ExportItem(document.getId(), document.getWidgetId(), true);
+    return new ExportItem(document.getElementId(), document.getWidgetId(), true);
   }
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getDataExplorerWidgetStorage().storeDataExplorerWidget(deserializeDocument(document));
+    getNoSqlStore().getDataExplorerWidgetStorage().persist(deserializeDocument(document));
   }
 
   @Override
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
index 91c55c5a1b..e94012c91d 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
@@ -28,7 +28,7 @@ public class MeasurementResolver extends AbstractResolver<DataLakeMeasure> {
 
   @Override
   public DataLakeMeasure findDocument(String resourceId) {
-    return getNoSqlStore().getDataLakeStorage().findOne(resourceId);
+    return getNoSqlStore().getDataLakeStorage().getElementById(resourceId);
   }
 
   @Override
@@ -49,7 +49,7 @@ public class MeasurementResolver extends AbstractResolver<DataLakeMeasure> {
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getDataLakeStorage().storeDataLakeMeasure(deserializeDocument(document));
+    getNoSqlStore().getDataLakeStorage().persist(deserializeDocument(document));
   }
 
   @Override
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java b/streampipes-model/src/main/java/org/apache/streampipes/model/api/Storable.java
similarity index 66%
rename from streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java
rename to streampipes-model/src/main/java/org/apache/streampipes/model/api/Storable.java
index 25e387d978..a9081f000d 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/api/Storable.java
@@ -16,21 +16,15 @@
  *
  */
 
-package org.apache.streampipes.storage.api;
+package org.apache.streampipes.model.api;
 
-import org.apache.streampipes.model.datalake.DataLakeMeasure;
+public interface Storable {
 
-import java.util.List;
+  String getRev();
 
-public interface IDataLakeStorage {
+  void setRev(String rev);
 
-  boolean storeDataLakeMeasure(DataLakeMeasure measure);
+  String getElementId();
 
-  List<DataLakeMeasure> getAllDataLakeMeasures();
-
-  DataLakeMeasure findOne(String id);
-
-  void updateDataLakeMeasure(DataLakeMeasure measure);
-
-  void deleteDataLakeMeasure(String id);
+  void setElementId(String elementId);
 }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java b/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java
index 7c6c21129c..46806a68a8 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java
@@ -20,12 +20,13 @@ package org.apache.streampipes.model.base;
 
 
 import org.apache.streampipes.model.SpDataStream;
+import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.extensions.ExtensionAssetType;
 import org.apache.streampipes.model.extensions.ExtensionItemDescription;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 import org.apache.streampipes.model.util.ServiceDefinitionUtil;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import com.google.gson.annotations.SerializedName;
 
@@ -40,13 +41,13 @@ import java.util.Objects;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
 @TsModel
-public abstract class NamedStreamPipesEntity implements Serializable {
+public abstract class NamedStreamPipesEntity implements Storable, Serializable {
 
   private static final long serialVersionUID = -98951691820519795L;
 
   protected @SerializedName("_id") String elementId;
 
-  @JsonProperty("_rev")
+  @JsonAlias("_rev")
   protected @SerializedName("_rev") String rev;
 
   protected String dom;
@@ -172,18 +173,22 @@ public abstract class NamedStreamPipesEntity implements Serializable {
     this.internallyManaged = internallyManaged;
   }
 
+  @Override
   public String getRev() {
     return rev;
   }
 
+  @Override
   public void setRev(String rev) {
     this.rev = rev;
   }
 
+  @Override
   public String getElementId() {
     return elementId;
   }
 
+  @Override
   public void setElementId(String elementId) {
     this.elementId = elementId;
   }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
index 5ef0f8e095..0b53f974a5 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
@@ -18,9 +18,10 @@
 
 package org.apache.streampipes.model.dashboard;
 
+import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.google.gson.annotations.SerializedName;
 
@@ -28,31 +29,37 @@ import com.google.gson.annotations.SerializedName;
     @JsonSubTypes.Type(DashboardWidgetModel.class),
     @JsonSubTypes.Type(DataExplorerWidgetModel.class)
 })
-public abstract class DashboardEntity {
+public abstract class DashboardEntity implements Storable {
 
-  @JsonProperty("_id")
-  private @SerializedName("_id") String id;
+  @JsonAlias("_id")
+  @SerializedName("_id")
+  private String elementId;
 
-  @JsonProperty("_rev")
-  private @SerializedName("_rev") String rev;
+  @JsonAlias("_rev")
+  @SerializedName("_rev")
+  private String rev;
 
   public DashboardEntity() {
     super();
   }
 
-  public String getId() {
-    return id;
-  }
-
-  public void setId(String id) {
-    this.id = id;
-  }
-
+  @Override
   public String getRev() {
     return rev;
   }
 
+  @Override
   public void setRev(String rev) {
     this.rev = rev;
   }
+
+  @Override
+  public String getElementId() {
+    return elementId;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.elementId = elementId;
+  }
 }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
index 5c001011c9..9cd6e11365 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
@@ -18,9 +18,10 @@
 
 package org.apache.streampipes.model.dashboard;
 
+import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonAlias;
 import com.google.gson.annotations.SerializedName;
 
 import java.util.HashMap;
@@ -28,13 +29,15 @@ import java.util.List;
 import java.util.Map;
 
 @TsModel
-public class DashboardModel {
+public class DashboardModel implements Storable {
 
-  @JsonProperty("_id")
-  private @SerializedName("_id") String couchDbId;
+  @JsonAlias("_id")
+  @SerializedName("_id")
+  private String elementId;
 
-  @JsonProperty("_rev")
-  private @SerializedName("_rev") String couchDbRev;
+  @JsonAlias("_rev")
+  @SerializedName("_rev")
+  private String rev;
 
   private String id;
   private String name;
@@ -51,22 +54,6 @@ public class DashboardModel {
     this.dashboardGeneralSettings = new HashMap<>();
   }
 
-  public String getCouchDbId() {
-    return couchDbId;
-  }
-
-  public void setCouchDbId(String couchDbId) {
-    this.couchDbId = couchDbId;
-  }
-
-  public String getCouchDbRev() {
-    return couchDbRev;
-  }
-
-  public void setCouchDbRev(String couchDbRev) {
-    this.couchDbRev = couchDbRev;
-  }
-
   public String getId() {
     return id;
   }
@@ -122,4 +109,28 @@ public class DashboardModel {
   public void setDashboardGeneralSettings(Map<String, Object> dashboardGeneralSettings) {
     this.dashboardGeneralSettings = dashboardGeneralSettings;
   }
+
+  @Override
+  public String getRev() {
+    return this.rev;
+  }
+
+  @Override
+  public void setRev(String rev) {
+    this.rev = rev;
+  }
+
+  @Override
+  public String getElementId() {
+    return this.elementId;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.elementId = elementId;
+  }
+
+  public String getCouchDbId() {
+    return this.elementId;
+  }
 }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
index 2d9441b283..92a3c881df 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
@@ -18,27 +18,27 @@
 
 package org.apache.streampipes.model.datalake;
 
+import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.model.shared.annotation.TsIgnore;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 
+import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import com.google.gson.annotations.SerializedName;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
 @TsModel
-public class DataLakeMeasure {
+public class DataLakeMeasure implements Storable {
 
   public static final String CURRENT_SCHEMA_VERSION = "1.1";
   public static final String ASSERTION_ERROR_MESSAGE = "timestamp field requires a stream prefix (e.g. s0::timestamp)";
   private static final String STREAM_PREFIX_DELIMITER = "::";
 
-  @JsonProperty("elementId")
   protected @SerializedName("_id") String elementId;
 
-  @JsonProperty("_rev")
+  @JsonAlias("_rev")
   private @SerializedName("_rev") String rev;
 
   private String measureName;
@@ -150,18 +150,22 @@ public class DataLakeMeasure {
     return timestampField.split(STREAM_PREFIX_DELIMITER)[1];
   }
 
+  @Override
   public String getRev() {
     return rev;
   }
 
+  @Override
   public void setRev(String rev) {
     this.rev = rev;
   }
 
+  @Override
   public String getElementId() {
     return elementId;
   }
 
+  @Override
   public void setElementId(String elementId) {
     this.elementId = elementId;
   }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java b/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java
index bc6810ae3e..f7ce37808c 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java
@@ -17,22 +17,25 @@
  */
 package org.apache.streampipes.model.template;
 
+import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonAlias;
 import com.google.gson.annotations.SerializedName;
 
 import java.util.Map;
 import java.util.UUID;
 
 @TsModel
-public class PipelineElementTemplate {
+public class PipelineElementTemplate implements Storable {
 
   Map<String, PipelineElementTemplateConfig> templateConfigs;
-  @JsonProperty("_id")
-  private @SerializedName("_id") String couchDbId;
-  @JsonProperty("_rev")
-  private @SerializedName("_rev") String couchDbRev;
+
+  @JsonAlias("_id")
+  private @SerializedName("_id") String elementId;
+
+  @JsonAlias("_rev")
+  private @SerializedName("_rev") String rev;
   private String templateName;
   private String templateDescription;
   private String basePipelineElementAppId;
@@ -46,7 +49,7 @@ public class PipelineElementTemplate {
   }
 
   public PipelineElementTemplate() {
-    this.couchDbId = UUID.randomUUID().toString();
+    this.elementId = UUID.randomUUID().toString();
   }
 
   public String getTemplateName() {
@@ -82,19 +85,32 @@ public class PipelineElementTemplate {
   }
 
   public String getCouchDbId() {
-    return couchDbId;
+    return elementId;
   }
 
-  public void setCouchDbId(String couchDbId) {
-    this.couchDbId = couchDbId;
+  public String getCouchDbRev() {
+    return rev;
   }
 
-  public String getCouchDbRev() {
-    return couchDbRev;
+
+  @Override
+  public String getRev() {
+    return rev;
+  }
+
+  @Override
+  public void setRev(String rev) {
+    this.rev = rev;
+  }
+
+  @Override
+  public String getElementId() {
+    return elementId;
   }
 
-  public void setCouchDbRev(String couchDbRev) {
-    this.couchDbRev = couchDbRev;
+  @Override
+  public void setElementId(String elementId) {
+    this.elementId = elementId;
   }
 }
 
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/extensions/AvailableExtensionsProvider.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/extensions/AvailableExtensionsProvider.java
index 951c52fe2c..6d03aace13 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/extensions/AvailableExtensionsProvider.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/extensions/AvailableExtensionsProvider.java
@@ -66,7 +66,7 @@ public class AvailableExtensionsProvider {
    * @return Map of extension item descriptions keyed by their elementId
    */
   private Map<String, ExtensionItemDescription> getUniqueAvailableExtensions() {
-    return storage.getExtensionsServiceStorage().getAll()
+    return storage.getExtensionsServiceStorage().findAll()
         .stream()
         .filter(service -> service.getStatus() == SpServiceStatus.HEALTHY)
         .flatMap(service -> service.getProvidedExtensions().stream())
@@ -111,18 +111,18 @@ public class AvailableExtensionsProvider {
   }
 
   private List<SpDataStream> getAllDataStreams() {
-    return storage.getDataStreamStorage().getAll()
+    return storage.getDataStreamStorage().findAll()
         .stream()
         .filter(stream -> !stream.isInternallyManaged())
         .toList();
   }
 
   private List<DataProcessorDescription> getAllDataProcessors() {
-    return storage.getDataProcessorStorage().getAll();
+    return storage.getDataProcessorStorage().findAll();
   }
 
   private List<DataSinkDescription> getAllDataSinks() {
-    return storage.getDataSinkStorage().getAll();
+    return storage.getDataSinkStorage().findAll();
   }
 
 }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java
index f29b39d11e..e4654c3710 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java
@@ -61,12 +61,12 @@ public class ServiceRegistrationManager {
   public void addService(SpServiceRegistration serviceRegistration,
                          SpServiceStatus status) {
     serviceRegistration.setStatus(status);
-    storage.createElement(serviceRegistration);
+    storage.persist(serviceRegistration);
     logService(serviceRegistration);
   }
 
   public List<SpServiceRegistration> getAllServices() {
-    return storage.getAll();
+    return storage.findAll();
   }
 
   public SpServiceRegistration getService(String serviceId) {
@@ -74,7 +74,7 @@ public class ServiceRegistrationManager {
   }
 
   public boolean isAnyServiceMigrating() {
-    return storage.getAll()
+    return storage.findAll()
         .stream()
         .anyMatch(service -> service.getStatus() == SpServiceStatus.MIGRATING);
   }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
index e980d9f900..98d94c3ca9 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
@@ -57,23 +57,13 @@ public class CouchDbInstallationStep extends InstallationStep {
 
   private void createDatabases() {
     try {
-      // Set up couchdb internal databases
-      Utils.getCouchDbInternalUsersClient();
-      Utils.getCouchDbReplicatorClient();
-      Utils.getCouchDbGlobalChangesClient();
-
       // Set up streampipes internal databases
       Utils.getCouchDbUserClient();
-      Utils.getCouchDbMonitoringClient();
       Utils.getCouchDbPipelineClient();
       Utils.getCouchDbConnectionClient();
       Utils.getCouchDbNotificationClient();
       Utils.getCouchDbPipelineCategoriesClient();
-      Utils.getCouchDbVisualizationClient();
-      Utils.getCouchDbDashboardClient();
-      Utils.getCouchDbDashboardWidgetClient();
       Utils.getCouchDbLabelClient();
-      Utils.getCouchDbCategoryClient();
 
       logSuccess(getTitle());
     } catch (Exception e) {
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
index 8f8c2cf2de..b34df894e6 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
@@ -220,7 +220,7 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor {
   }
 
   private boolean hasKey(StaticProperty sp) {
-    return configs.containsKey(sp.getInternalName());
+    return configs.getOrDefault(sp.getInternalName(), null) != null;
   }
 
   private String getAsString(StaticProperty sp) {
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java
index 09451a95f0..ff3c168b5c 100644
--- a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java
+++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java
@@ -65,7 +65,7 @@ public class PipelineElementTemplateResource extends AbstractRestResource {
       @RequestParam("appId") String appId
   ) {
     if (appId == null) {
-      return ok(getPipelineElementTemplateStorage().getAll());
+      return ok(getPipelineElementTemplateStorage().findAll());
     } else {
       return ok(getPipelineElementTemplateStorage().getPipelineElementTemplatesforAppId(appId));
     }
@@ -104,7 +104,7 @@ public class PipelineElementTemplateResource extends AbstractRestResource {
                    content = @Content(schema = @Schema(implementation = PipelineElementTemplate.class)))
       @org.springframework.web.bind.annotation.RequestBody PipelineElementTemplate entity
   ) {
-    getPipelineElementTemplateStorage().createElement(entity);
+    getPipelineElementTemplateStorage().persist(entity);
     return ok();
   }
 
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java
index 6e72d00e9d..67a0b479ee 100644
--- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java
+++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java
@@ -20,40 +20,41 @@ package org.apache.streampipes.resource.management;
 import org.apache.streampipes.model.client.user.Permission;
 import org.apache.streampipes.model.dashboard.DashboardModel;
 import org.apache.streampipes.model.util.ElementIdGenerator;
-import org.apache.streampipes.storage.api.IDashboardStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 
 import java.util.List;
 
-public abstract class AbstractDashboardResourceManager extends AbstractResourceManager<IDashboardStorage> {
+public abstract class AbstractDashboardResourceManager
+    extends AbstractResourceManager<CRUDStorage<String, DashboardModel>> {
 
-  public AbstractDashboardResourceManager(IDashboardStorage db) {
+  public AbstractDashboardResourceManager(CRUDStorage<String, DashboardModel> db) {
     super(db);
   }
 
   public List<DashboardModel> findAll() {
-    return db.getAllDashboards();
+    return db.findAll();
   }
 
   public DashboardModel find(String dashboardId) {
-    return db.getDashboard(dashboardId);
+    return db.getElementById(dashboardId);
   }
 
   public void delete(String dashboardId) {
-    db.deleteDashboard(dashboardId);
+    db.deleteElementById(dashboardId);
     deletePermissions(dashboardId);
   }
 
   public void create(DashboardModel dashboardModel, String principalSid) {
-    if (dashboardModel.getCouchDbId() == null) {
-      dashboardModel.setCouchDbId(ElementIdGenerator.makeElementId(DashboardModel.class));
+    if (dashboardModel.getElementId() == null) {
+      dashboardModel.setElementId(ElementIdGenerator.makeElementId(DashboardModel.class));
     }
-    db.storeDashboard(dashboardModel);
-    new PermissionResourceManager().createDefault(dashboardModel.getCouchDbId(), DashboardModel.class, principalSid,
+    db.persist(dashboardModel);
+    new PermissionResourceManager().createDefault(dashboardModel.getElementId(), DashboardModel.class, principalSid,
         false);
   }
 
   public void update(DashboardModel dashboardModel) {
-    db.updateDashboard(dashboardModel);
+    db.updateElement(dashboardModel);
   }
 
   private void deletePermissions(String dashboardId) {
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
index 255e3f127d..a36c00e4ce 100644
--- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
+++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
@@ -34,11 +34,11 @@ public abstract class AbstractPipelineElementResourceManager<T extends CRUDStora
   }
 
   public List<W> findAll() {
-    return db.getAll();
+    return db.findAll();
   }
 
   public List<String> findAllIdsOnly() {
-    return db.getAll().stream().map(NamedStreamPipesEntity::getAppId).collect(Collectors.toList());
+    return db.findAll().stream().map(NamedStreamPipesEntity::getAppId).collect(Collectors.toList());
   }
 
   public List<X> findAllAsInvocation() {
@@ -73,7 +73,7 @@ public abstract class AbstractPipelineElementResourceManager<T extends CRUDStora
   public void add(W pipelineElement, String principalSid) throws IllegalArgumentException {
     W existing = find(pipelineElement.getElementId());
     if (existing == null) {
-      this.db.createElement(pipelineElement);
+      this.db.persist(pipelineElement);
       new PermissionResourceManager()
           .createDefault(pipelineElement.getElementId(), SpDataStream.class, principalSid, false);
     } else {
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java
index 6cb50f6e50..9c9661247b 100644
--- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java
+++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java
@@ -143,7 +143,7 @@ public class UserResourceManager extends AbstractResourceManager<IUserStorage> {
   private void storeActivationCode(String username,
                                    String activationCode) throws IOException {
     UserActivationToken token = UserActivationToken.create(activationCode, username);
-    getUserActivationTokenStorage().createElement(token);
+    getUserActivationTokenStorage().persist(token);
     new MailSender().sendAccountActivationMail(username, activationCode);
   }
 
@@ -179,7 +179,7 @@ public class UserResourceManager extends AbstractResourceManager<IUserStorage> {
 
   private void storeRecoveryCode(String username,
                                  String recoveryCode) {
-    getPasswordRecoveryTokenStorage().createElement(PasswordRecoveryToken.create(recoveryCode, username));
+    getPasswordRecoveryTokenStorage().persist(PasswordRecoveryToken.create(recoveryCode, username));
   }
 
   private IPasswordRecoveryTokenStorage getPasswordRecoveryTokenStorage() {
diff --git a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java b/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java
index 3900781613..6be6c07713 100644
--- a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java
+++ b/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java
@@ -24,8 +24,6 @@ import org.apache.streampipes.model.message.Notification;
 import org.apache.streampipes.model.message.SuccessMessage;
 import org.apache.streampipes.resource.management.SpResourceManager;
 import org.apache.streampipes.rest.shared.impl.AbstractSharedRestInterface;
-import org.apache.streampipes.storage.api.IDataLakeStorage;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
 import org.apache.streampipes.storage.api.INoSqlStorage;
 import org.apache.streampipes.storage.api.INotificationStorage;
 import org.apache.streampipes.storage.api.IPipelineElementDescriptionStorage;
@@ -37,8 +35,6 @@ import org.apache.streampipes.storage.management.StorageDispatcher;
 
 import org.springframework.http.ResponseEntity;
 
-import java.net.URLDecoder;
-
 public class AbstractRestResource extends AbstractSharedRestInterface {
 
   protected ISpCoreConfigurationStorage getSpCoreConfigurationStorage() {
@@ -65,10 +61,6 @@ public class AbstractRestResource extends AbstractSharedRestInterface {
     return getNoSqlStorage().getNotificationStorageApi();
   }
 
-  protected IDataLakeStorage getDataLakeStorage() {
-    return getNoSqlStorage().getDataLakeStorage();
-  }
-
   protected IPipelineElementTemplateStorage getPipelineElementTemplateStorage() {
     return getNoSqlStorage().getPipelineElementTemplateStorage();
   }
@@ -77,10 +69,6 @@ public class AbstractRestResource extends AbstractSharedRestInterface {
     return StorageDispatcher.INSTANCE.getNoSqlStore();
   }
 
-  protected IFileMetadataStorage getFileMetadataStorage() {
-    return getNoSqlStorage().getFileMetadataStorage();
-  }
-
   protected ResponseEntity<Message> constructSuccessMessage(Notification... notifications) {
     return statusMessage(new SuccessMessage(notifications));
   }
@@ -89,11 +77,6 @@ public class AbstractRestResource extends AbstractSharedRestInterface {
     return statusMessage(new ErrorMessage(notifications));
   }
 
-  @SuppressWarnings("deprecation")
-  protected String decode(String encodedString) {
-    return URLDecoder.decode(encodedString);
-  }
-
   protected ResponseEntity<Message> statusMessage(Message message) {
     return ResponseEntity
         .ok()
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
index 3d57aa8ce7..5bce889136 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
@@ -33,9 +33,6 @@ import org.apache.streampipes.model.file.FileMetadata;
 import org.apache.streampipes.model.pipeline.Pipeline;
 import org.apache.streampipes.resource.management.SpResourceManager;
 import org.apache.streampipes.resource.management.UserResourceManager;
-import org.apache.streampipes.storage.api.IDashboardStorage;
-import org.apache.streampipes.storage.api.IDashboardWidgetStorage;
-import org.apache.streampipes.storage.api.IDataExplorerWidgetStorage;
 import org.apache.streampipes.storage.api.IGenericStorage;
 import org.apache.streampipes.storage.management.StorageDispatcher;
 
@@ -153,34 +150,34 @@ public class ResetManagement {
   }
 
   private static void removeAllDataViewWidgets() {
-    IDataExplorerWidgetStorage widgetStorage =
+    var widgetStorage =
         StorageDispatcher.INSTANCE.getNoSqlStore()
                                   .getDataExplorerWidgetStorage();
-    widgetStorage.getAllDataExplorerWidgets()
-                 .forEach(widget -> widgetStorage.deleteDataExplorerWidget(widget.getId()));
+    widgetStorage.findAll()
+                 .forEach(widget -> widgetStorage.deleteElementById(widget.getElementId()));
   }
 
   private static void removeAllDataViews() {
-    IDashboardStorage dataLakeDashboardStorage =
+    var dataLakeDashboardStorage =
         StorageDispatcher.INSTANCE.getNoSqlStore()
                                   .getDataExplorerDashboardStorage();
-    dataLakeDashboardStorage.getAllDashboards()
-                            .forEach(dashboard -> dataLakeDashboardStorage.deleteDashboard(dashboard.getCouchDbId()));
+    dataLakeDashboardStorage.findAll()
+                            .forEach(dashboard -> dataLakeDashboardStorage.deleteElementById(dashboard.getElementId()));
   }
 
   private static void removeAllDashboardWidgets() {
-    IDashboardWidgetStorage dashobardWidgetStorage =
+    var dashboardWidgetStorage =
         StorageDispatcher.INSTANCE.getNoSqlStore()
                                   .getDashboardWidgetStorage();
-    dashobardWidgetStorage.getAllDashboardWidgets()
-                          .forEach(widget -> dashobardWidgetStorage.deleteDashboardWidget(widget.getId()));
+    dashboardWidgetStorage.findAll()
+                          .forEach(widget -> dashboardWidgetStorage.deleteElementById(widget.getElementId()));
   }
 
   private static void removeAllDashboards() {
-    IDashboardStorage dashboardStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
+    var dashboardStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
                                                                    .getDashboardStorage();
-    dashboardStorage.getAllDashboards()
-                    .forEach(dashboard -> dashboardStorage.deleteDashboard(dashboard.getCouchDbId()));
+    dashboardStorage.findAll()
+                    .forEach(dashboard -> dashboardStorage.deleteElementById(dashboard.getElementId()));
   }
 
   private static void removeAllAssets(String username) {
@@ -202,7 +199,7 @@ public class ResetManagement {
         .getPipelineElementTemplateStorage();
 
     pipelineElementTemplateStorage
-        .getAll()
+        .findAll()
         .forEach(pipelineElementTemplateStorage::deleteElement);
 
   }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCanvasMetadataResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCanvasMetadataResource.java
index 169e2f80a1..20a6e35a0a 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCanvasMetadataResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCanvasMetadataResource.java
@@ -65,7 +65,7 @@ public class PipelineCanvasMetadataResource extends AbstractRestResource {
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Void> storePipelineCanvasMetadata(@RequestBody PipelineCanvasMetadata pipelineCanvasMetadata) {
-    getPipelineCanvasMetadataStorage().createElement(pipelineCanvasMetadata);
+    getPipelineCanvasMetadataStorage().persist(pipelineCanvasMetadata);
     return ok();
   }
 
@@ -97,7 +97,7 @@ public class PipelineCanvasMetadataResource extends AbstractRestResource {
     try {
       getPipelineCanvasMetadataStorage().updateElement(pipelineCanvasMetadata);
     } catch (IllegalArgumentException e) {
-      getPipelineCanvasMetadataStorage().createElement(pipelineCanvasMetadata);
+      getPipelineCanvasMetadataStorage().persist(pipelineCanvasMetadata);
     }
     return ok();
   }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java
index f2d768f5f1..6a15de5476 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java
@@ -50,7 +50,7 @@ public class ServiceConfigurationResource extends AbstractAuthGuardedRestResourc
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<List<SpServiceConfiguration>> getAllServiceConfigurations() {
-    return ok(extensionsServicesConfigStorage.getAll());
+    return ok(extensionsServicesConfigStorage.findAll());
   }
 
   @GetMapping(path = "{serviceGroup}", produces = MediaType.APPLICATION_JSON_VALUE)
@@ -67,7 +67,7 @@ public class ServiceConfigurationResource extends AbstractAuthGuardedRestResourc
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Void> registerServiceConfiguration(@RequestBody SpServiceConfiguration serviceConfiguration) {
     if (extensionsServicesConfigStorage.getElementById(serviceConfiguration.getServiceGroup()) == null) {
-      extensionsServicesConfigStorage.createElement(serviceConfiguration);
+      extensionsServicesConfigStorage.persist(serviceConfiguration);
       return created();
     } else {
       return ok();
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java
index 57f97b9741..c8cd157aa2 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java
@@ -27,8 +27,6 @@ import org.apache.streampipes.rest.security.AuthConstants;
 import org.apache.streampipes.rest.shared.exception.SpMessageException;
 import org.apache.streampipes.storage.api.CRUDStorage;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -47,14 +45,12 @@ import java.util.List;
 @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
 public class ServiceRegistrationResource extends AbstractAuthGuardedRestResource {
 
-  private static final Logger LOG = LoggerFactory.getLogger(ServiceRegistrationResource.class);
-
   private final CRUDStorage<String, SpServiceRegistration> extensionsServiceStorage =
       getNoSqlStorage().getExtensionsServiceStorage();
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<List<SpServiceRegistration>> getRegisteredServices() {
-    return ok(extensionsServiceStorage.getAll());
+    return ok(extensionsServiceStorage.findAll());
   }
 
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java
index e78fe1f183..b5f1ad0bc5 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java
@@ -46,13 +46,13 @@ public class UserGroupResource extends AbstractAuthGuardedRestResource {
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
   public ResponseEntity<List<Group>> getAllUserGroups() {
-    return ok(getUserGroupStorage().getAll());
+    return ok(getUserGroupStorage().findAll());
   }
 
   @PostMapping
   @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
   public ResponseEntity<Void> addUserGroup(@RequestBody Group group) {
-    getUserGroupStorage().createElement(group);
+    getUserGroupStorage().persist(group);
     return ok();
   }
 
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/AbstractDashboardResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/AbstractDashboardResource.java
index 6b83a949b8..644b1f6f9d 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/AbstractDashboardResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/AbstractDashboardResource.java
@@ -54,7 +54,7 @@ public abstract class AbstractDashboardResource extends AbstractAuthGuardedRestR
   @PreAuthorize("this.hasWriteAuthority() and hasPermission(#dashboardModel.couchDbId, 'WRITE')")
   public ResponseEntity<DashboardModel> modifyDashboard(@RequestBody DashboardModel dashboardModel) {
     getResourceManager().update(dashboardModel);
-    return ok(getResourceManager().find(dashboardModel.getCouchDbId()));
+    return ok(getResourceManager().find(dashboardModel.getElementId()));
   }
 
   @DeleteMapping(path = "/{dashboardId}")
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
index 2750f1412a..78eed04375 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
@@ -20,7 +20,7 @@ package org.apache.streampipes.rest.impl.dashboard;
 
 import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
 import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
-import org.apache.streampipes.storage.api.IDashboardWidgetStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
+import java.util.UUID;
 
 @RestController
 @RequestMapping("/api/v2/dashboard/widgets")
@@ -41,12 +42,12 @@ public class DashboardWidget extends AbstractRestResource {
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<List<DashboardWidgetModel>> getAllDashboardWidgets() {
-    return ok(getDashboardWidgetStorage().getAllDashboardWidgets());
+    return ok(getDashboardWidgetStorage().findAll());
   }
 
   @GetMapping(path = "/{widgetId}", produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<DashboardWidgetModel> getDashboardWidget(@PathVariable("widgetId") String widgetId) {
-    return ok(getDashboardWidgetStorage().getDashboardWidget(widgetId));
+    return ok(getDashboardWidgetStorage().getElementById(widgetId));
   }
 
   @PutMapping(
@@ -54,13 +55,13 @@ public class DashboardWidget extends AbstractRestResource {
       produces = MediaType.APPLICATION_JSON_VALUE,
       consumes = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Void> modifyDashboardWidget(@RequestBody DashboardWidgetModel dashboardWidgetModel) {
-    getDashboardWidgetStorage().updateDashboardWidget(dashboardWidgetModel);
+    getDashboardWidgetStorage().updateElement(dashboardWidgetModel);
     return ok();
   }
 
   @DeleteMapping(path = "/{widgetId}")
   public ResponseEntity<Void> deleteDashboardWidget(@PathVariable("widgetId") String widgetId) {
-    getDashboardWidgetStorage().deleteDashboardWidget(widgetId);
+    getDashboardWidgetStorage().deleteElementById(widgetId);
     return ok();
   }
 
@@ -70,11 +71,13 @@ public class DashboardWidget extends AbstractRestResource {
   )
   public ResponseEntity<DashboardWidgetModel> createDashboardWidget(
       @RequestBody DashboardWidgetModel dashboardWidgetModel) {
-    String widgetId = getDashboardWidgetStorage().storeDashboardWidget(dashboardWidgetModel);
-    return ok(getDashboardWidgetStorage().getDashboardWidget(widgetId));
+    String elementId = UUID.randomUUID().toString();
+    dashboardWidgetModel.setElementId(elementId);
+    getDashboardWidgetStorage().persist(dashboardWidgetModel);
+    return ok(getDashboardWidgetStorage().getElementById(elementId));
   }
 
-  private IDashboardWidgetStorage getDashboardWidgetStorage() {
+  private CRUDStorage<String, DashboardWidgetModel> getDashboardWidgetStorage() {
     return getNoSqlStorage().getDashboardWidgetStorage();
   }
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
index 2c108866a3..9324ff117c 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
@@ -18,9 +18,11 @@
 
 package org.apache.streampipes.rest.impl.datalake;
 
+import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.model.util.ElementIdGenerator;
 import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
-import org.apache.streampipes.storage.api.IDataExplorerWidgetStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -41,12 +43,12 @@ public class DataLakeWidgetResource extends AbstractRestResource {
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<List<DataExplorerWidgetModel>> getAllDataExplorerWidgets() {
-    return ok(getDataExplorerWidgetStorage().getAllDataExplorerWidgets());
+    return ok(getDataExplorerWidgetStorage().findAll());
   }
 
   @GetMapping(path = "/{widgetId}", produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<DataExplorerWidgetModel> getDataExplorerWidget(@PathVariable("widgetId") String widgetId) {
-    return ok(getDataExplorerWidgetStorage().getDataExplorerWidget(widgetId));
+    return ok(getDataExplorerWidgetStorage().getElementById(widgetId));
   }
 
   @PutMapping(
@@ -55,13 +57,13 @@ public class DataLakeWidgetResource extends AbstractRestResource {
       produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<DataExplorerWidgetModel> modifyDataExplorerWidget(
       @RequestBody DataExplorerWidgetModel dataExplorerWidgetModel) {
-    getDataExplorerWidgetStorage().updateDataExplorerWidget(dataExplorerWidgetModel);
-    return ok(getDataExplorerWidgetStorage().getDataExplorerWidget(dataExplorerWidgetModel.getId()));
+    getDataExplorerWidgetStorage().updateElement(dataExplorerWidgetModel);
+    return ok(getDataExplorerWidgetStorage().getElementById(dataExplorerWidgetModel.getElementId()));
   }
 
   @DeleteMapping(path = "/{widgetId}")
   public ResponseEntity<Void> deleteDataExplorerWidget(@PathVariable("widgetId") String widgetId) {
-    getDataExplorerWidgetStorage().deleteDataExplorerWidget(widgetId);
+    getDataExplorerWidgetStorage().deleteElementById(widgetId);
     return ok();
   }
 
@@ -71,11 +73,13 @@ public class DataLakeWidgetResource extends AbstractRestResource {
   )
   public ResponseEntity<DataExplorerWidgetModel> createDataExplorerWidget(
       @RequestBody DataExplorerWidgetModel dataExplorerWidgetModel) {
-    String widgetId = getDataExplorerWidgetStorage().storeDataExplorerWidget(dataExplorerWidgetModel);
-    return ok(getDataExplorerWidgetStorage().getDataExplorerWidget(widgetId));
+    String elementId = ElementIdGenerator.makeElementId(DashboardWidgetModel.class);
+    dataExplorerWidgetModel.setElementId(elementId);
+    getDataExplorerWidgetStorage().persist(dataExplorerWidgetModel);
+    return ok(getDataExplorerWidgetStorage().getElementById(elementId));
   }
 
-  private IDataExplorerWidgetStorage getDataExplorerWidgetStorage() {
+  private CRUDStorage<String, DataExplorerWidgetModel> getDataExplorerWidgetStorage() {
     return getNoSqlStorage().getDataExplorerWidgetStorage();
   }
 
diff --git a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/PostStartupTask.java b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/PostStartupTask.java
index 8e042c72f6..aa378ffae5 100644
--- a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/PostStartupTask.java
+++ b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/PostStartupTask.java
@@ -74,7 +74,7 @@ public class PostStartupTask implements Runnable {
 
   private void performAdapterAssetUpdate() {
     var installedAppIds = CouchDbStorageManager.INSTANCE.getExtensionsServiceStorage()
-                                                        .getAll()
+                                                        .findAll()
                                                         .stream()
                                                         .flatMap(config -> config.getTags()
                                                                                  .stream())
diff --git a/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java b/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java
index 19f1479483..c096267c5f 100644
--- a/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java
+++ b/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java
@@ -92,7 +92,7 @@ public class SpServiceDiscoveryCore implements ISpServiceDiscovery {
   }
 
   private List<SpServiceRegistration> findServices(int retryCount) {
-    var services = serviceStorage.getAll();
+    var services = serviceStorage.findAll();
     if (services.isEmpty()) {
       if (retryCount < MAX_RETRIES) {
         try {
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
index f21f7bd904..a5539aa1e4 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
@@ -17,17 +17,24 @@
  */
 package org.apache.streampipes.storage.api;
 
+import org.apache.streampipes.model.Tuple2;
+
 import java.util.List;
 
 public interface CRUDStorage<K, V> {
 
-  List<V> getAll();
+  List<V> findAll();
 
-  void createElement(V element);
+  Tuple2<Boolean, String> persist(V element);
 
   V getElementById(K id);
 
   V updateElement(V element);
 
   void deleteElement(V element);
+
+  default void deleteElementById(K id) {
+    var element = getElementById(id);
+    deleteElement(element);
+  }
 }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardStorage.java
deleted file mode 100644
index 099d8ce0e3..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardStorage.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.dashboard.DashboardModel;
-
-import java.util.List;
-
-public interface IDashboardStorage {
-
-  List<DashboardModel> getAllDashboards();
-
-  void storeDashboard(DashboardModel dashboardModel);
-
-  void updateDashboard(DashboardModel dashboardModel);
-
-  DashboardModel getDashboard(String dashboardId);
-
-  void deleteDashboard(String dashboardId);
-}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java
deleted file mode 100644
index 0d9bf2cfeb..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
-
-import java.util.List;
-
-public interface IDashboardWidgetStorage {
-
-  List<DashboardWidgetModel> getAllDashboardWidgets();
-
-  String storeDashboardWidget(DashboardWidgetModel dashboardWidgetModel);
-
-  void updateDashboardWidget(DashboardWidgetModel dashboardWidgetModel);
-
-  DashboardWidgetModel getDashboardWidget(String dashboardWidgetId);
-
-  void deleteDashboardWidget(String dashboardWidgetId);
-}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataExplorerWidgetStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataExplorerWidgetStorage.java
deleted file mode 100644
index 4b493099f6..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataExplorerWidgetStorage.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
-
-import java.util.List;
-
-public interface IDataExplorerWidgetStorage {
-
-  List<DataExplorerWidgetModel> getAllDataExplorerWidgets();
-
-  String storeDataExplorerWidget(DataExplorerWidgetModel dataExplorerWidgetModel);
-
-  void updateDataExplorerWidget(DataExplorerWidgetModel dataExplorerWidgetModel);
-
-  DataExplorerWidgetModel getDataExplorerWidget(String dataExplorerWidgetId);
-
-  void deleteDataExplorerWidget(String dataExplorerWidgetId);
-}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
index 2f68841105..3b704f5eb1 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
@@ -17,6 +17,10 @@
  */
 package org.apache.streampipes.storage.api;
 
+import org.apache.streampipes.model.dashboard.DashboardModel;
+import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
+import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.extensions.configuration.SpServiceConfiguration;
 import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceRegistration;
 
@@ -44,17 +48,17 @@ public interface INoSqlStorage {
 
   IAssetDashboardStorage getAssetDashboardStorage();
 
-  IDataLakeStorage getDataLakeStorage();
+  CRUDStorage<String, DataLakeMeasure> getDataLakeStorage();
 
   IFileMetadataStorage getFileMetadataStorage();
 
-  IDashboardStorage getDashboardStorage();
+  CRUDStorage<String, DashboardModel> getDashboardStorage();
 
-  IDashboardStorage getDataExplorerDashboardStorage();
+  CRUDStorage<String, DashboardModel> getDataExplorerDashboardStorage();
 
-  IDashboardWidgetStorage getDashboardWidgetStorage();
+  CRUDStorage<String, DashboardWidgetModel> getDashboardWidgetStorage();
 
-  IDataExplorerWidgetStorage getDataExplorerWidgetStorage();
+  CRUDStorage<String, DataExplorerWidgetModel> getDataExplorerWidgetStorage();
 
   IPipelineElementTemplateStorage getPipelineElementTemplateStorage();
 
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java
index 3465f966b8..155652997c 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java
@@ -18,7 +18,6 @@
 
 package org.apache.streampipes.storage.api;
 
-import org.apache.streampipes.model.VirtualSensor;
 import org.apache.streampipes.model.pipeline.Pipeline;
 
 import java.util.List;
@@ -29,8 +28,6 @@ public interface IPipelineStorage {
 
   List<Pipeline> getAllPipelines();
 
-  List<Pipeline> getSystemPipelines();
-
   void storePipeline(Pipeline pipeline);
 
   void updatePipeline(Pipeline pipeline);
@@ -40,8 +37,4 @@ public interface IPipelineStorage {
   void deletePipeline(String pipelineId);
 
   void store(Pipeline object);
-
-  void storeVirtualSensor(String username, VirtualSensor virtualSensor);
-
-  List<VirtualSensor> getVirtualSensors(String username);
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
index 715fb4cfcc..abdb176262 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
@@ -17,15 +17,15 @@
  */
 package org.apache.streampipes.storage.couchdb;
 
+import org.apache.streampipes.model.dashboard.DashboardModel;
+import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
+import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.extensions.configuration.SpServiceConfiguration;
 import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceRegistration;
 import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.api.IAdapterStorage;
 import org.apache.streampipes.storage.api.IAssetDashboardStorage;
-import org.apache.streampipes.storage.api.IDashboardStorage;
-import org.apache.streampipes.storage.api.IDashboardWidgetStorage;
-import org.apache.streampipes.storage.api.IDataExplorerWidgetStorage;
-import org.apache.streampipes.storage.api.IDataLakeStorage;
 import org.apache.streampipes.storage.api.IDataProcessorStorage;
 import org.apache.streampipes.storage.api.IDataSinkStorage;
 import org.apache.streampipes.storage.api.IDataStreamStorage;
@@ -51,14 +51,10 @@ import org.apache.streampipes.storage.couchdb.impl.AdapterInstanceStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.AssetDashboardStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.ConnectionStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.CoreConfigurationStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.DashboardStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.DashboardWidgetStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.DataExplorerDashboardStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.DataExplorerWidgetStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.DataLakeStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DataProcessorStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DataSinkStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DataStreamStorageImpl;
+import org.apache.streampipes.storage.couchdb.impl.DefaultCrudStorage;
 import org.apache.streampipes.storage.couchdb.impl.ExtensionsServiceConfigStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.ExtensionsServiceStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.FileMetadataStorageImpl;
@@ -75,6 +71,7 @@ import org.apache.streampipes.storage.couchdb.impl.PipelineStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.UserActivationTokenImpl;
 import org.apache.streampipes.storage.couchdb.impl.UserGroupStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.UserStorage;
+import org.apache.streampipes.storage.couchdb.utils.Utils;
 
 public enum CouchDbStorageManager implements INoSqlStorage {
 
@@ -136,8 +133,11 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public IDataLakeStorage getDataLakeStorage() {
-    return new DataLakeStorageImpl();
+  public CRUDStorage<String, DataLakeMeasure> getDataLakeStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("data-lake"),
+        DataLakeMeasure.class
+    );
   }
 
   @Override
@@ -146,23 +146,35 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public IDashboardStorage getDashboardStorage() {
-    return new DashboardStorageImpl();
+  public CRUDStorage<String, DashboardModel> getDashboardStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("dashboard"),
+        DashboardModel.class
+    );
   }
 
   @Override
-  public IDashboardStorage getDataExplorerDashboardStorage() {
-    return new DataExplorerDashboardStorageImpl();
+  public CRUDStorage<String, DashboardModel> getDataExplorerDashboardStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("dataexplorerdashboard"),
+        DashboardModel.class
+    );
   }
 
   @Override
-  public IDashboardWidgetStorage getDashboardWidgetStorage() {
-    return new DashboardWidgetStorageImpl();
+  public CRUDStorage<String, DashboardWidgetModel> getDashboardWidgetStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("dashboardwidget"),
+        DashboardWidgetModel.class
+    );
   }
 
   @Override
-  public IDataExplorerWidgetStorage getDataExplorerWidgetStorage() {
-    return new DataExplorerWidgetStorageImpl();
+  public CRUDStorage<String, DataExplorerWidgetModel> getDataExplorerWidgetStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("dataexplorerwidget"),
+        DataExplorerWidgetModel.class
+    );
   }
 
   @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterDescriptionStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterDescriptionStorageImpl.java
index 9a771a408b..2095bc618e 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterDescriptionStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterDescriptionStorageImpl.java
@@ -67,7 +67,7 @@ public class AdapterDescriptionStorageImpl extends AbstractDao<AdapterDescriptio
 
   @Override
   public AdapterDescription getFirstAdapterByAppId(String appId) {
-    return getAll()
+    return this.findAll()
             .stream()
             .filter(p -> p.getAppId().equals(appId))
             .findFirst()
@@ -76,22 +76,12 @@ public class AdapterDescriptionStorageImpl extends AbstractDao<AdapterDescriptio
 
   @Override
   public List<AdapterDescription> getAdaptersByAppId(String appId) {
-    return getAll()
+    return this.findAll()
             .stream()
             .filter(p -> p.getAppId().equals(appId))
             .toList();
   }
 
-  @Override
-  public List<AdapterDescription> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(AdapterDescription adapter) {
-    persist(adapter);
-  }
-
   @Override
   public AdapterDescription getElementById(String id) {
     return findWithNullIfEmpty(id);
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java
index e8cc511374..a744bf7866 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java
@@ -65,16 +65,6 @@ public class AdapterInstanceStorageImpl extends AbstractDao<AdapterDescription>
 
   }
 
-  @Override
-  public List<AdapterDescription> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(AdapterDescription adapter) {
-    persist(adapter);
-  }
-
   @Override
   public AdapterDescription getElementById(String id) {
     return findWithNullIfEmpty(id);
@@ -82,7 +72,7 @@ public class AdapterInstanceStorageImpl extends AbstractDao<AdapterDescription>
 
   @Override
   public AdapterDescription getFirstAdapterByAppId(String appId) {
-    return getAll()
+    return this.findAll()
             .stream()
             .filter(p -> p.getAppId().equals(appId))
             .findFirst()
@@ -91,7 +81,7 @@ public class AdapterInstanceStorageImpl extends AbstractDao<AdapterDescription>
 
   @Override
   public List<AdapterDescription> getAdaptersByAppId(String appId) {
-    return getAll()
+    return this.findAll()
             .stream()
             .filter(p -> p.getAppId().equals(appId))
             .toList();
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java
deleted file mode 100644
index 74e5e29273..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.dashboard.DashboardModel;
-import org.apache.streampipes.storage.api.IDashboardStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class DashboardStorageImpl extends AbstractDao<DashboardModel> implements IDashboardStorage {
-
-  public DashboardStorageImpl() {
-    super(Utils::getCouchDbDashboardClient, DashboardModel.class);
-  }
-
-  @Override
-  public List<DashboardModel> getAllDashboards() {
-    return findAll();
-  }
-
-  @Override
-  public void storeDashboard(DashboardModel dashboardModel) {
-    persist(dashboardModel);
-  }
-
-  @Override
-  public void updateDashboard(DashboardModel dashboardModel) {
-    update(dashboardModel);
-  }
-
-  @Override
-  public DashboardModel getDashboard(String dashboardId) {
-    return find(dashboardId).orElse(new DashboardModel());
-  }
-
-  @Override
-  public void deleteDashboard(String dashboardId) {
-    delete(dashboardId);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java
deleted file mode 100644
index ca85583c0b..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
-import org.apache.streampipes.storage.api.IDashboardWidgetStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class DashboardWidgetStorageImpl extends AbstractDao<DashboardWidgetModel> implements IDashboardWidgetStorage {
-
-  public DashboardWidgetStorageImpl() {
-    super(Utils::getCouchDbDashboardWidgetClient, DashboardWidgetModel.class);
-  }
-
-  @Override
-  public List<DashboardWidgetModel> getAllDashboardWidgets() {
-    return findAll();
-  }
-
-  @Override
-  public String storeDashboardWidget(DashboardWidgetModel dashboardWidgetModel) {
-    return persist(dashboardWidgetModel).v;
-  }
-
-  @Override
-  public void updateDashboardWidget(DashboardWidgetModel dashboardWidgetModel) {
-    update(dashboardWidgetModel);
-  }
-
-  @Override
-  public DashboardWidgetModel getDashboardWidget(String dashboardWidgetId) {
-    return find(dashboardWidgetId).orElse(new DashboardWidgetModel());
-  }
-
-  @Override
-  public void deleteDashboardWidget(String dashboardWidgetId) {
-    delete(dashboardWidgetId);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataExplorerDashboardStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataExplorerDashboardStorageImpl.java
deleted file mode 100644
index d637ae00ad..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataExplorerDashboardStorageImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.dashboard.DashboardModel;
-import org.apache.streampipes.storage.api.IDashboardStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class DataExplorerDashboardStorageImpl extends AbstractDao<DashboardModel> implements IDashboardStorage {
-
-  public DataExplorerDashboardStorageImpl() {
-    super(Utils::getCouchDbDataExplorerDashboardClient, DashboardModel.class);
-  }
-
-  @Override
-  public List<DashboardModel> getAllDashboards() {
-    return findAll();
-  }
-
-  @Override
-  public void storeDashboard(DashboardModel dashboardModel) {
-    persist(dashboardModel);
-  }
-
-  @Override
-  public void updateDashboard(DashboardModel dashboardModel) {
-    update(dashboardModel);
-  }
-
-  @Override
-  public DashboardModel getDashboard(String dashboardId) {
-    return find(dashboardId).orElse(new DashboardModel());
-  }
-
-  @Override
-  public void deleteDashboard(String dashboardId) {
-    delete(dashboardId);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataExplorerWidgetStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataExplorerWidgetStorageImpl.java
deleted file mode 100644
index 77308394db..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataExplorerWidgetStorageImpl.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
-import org.apache.streampipes.storage.api.IDataExplorerWidgetStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class DataExplorerWidgetStorageImpl extends AbstractDao<DataExplorerWidgetModel>
-    implements IDataExplorerWidgetStorage {
-
-  public DataExplorerWidgetStorageImpl() {
-    super(Utils::getCouchDbDataExplorerWidgetClient, DataExplorerWidgetModel.class);
-  }
-
-  @Override
-  public List<DataExplorerWidgetModel> getAllDataExplorerWidgets() {
-    return findAll();
-  }
-
-  @Override
-  public String storeDataExplorerWidget(DataExplorerWidgetModel dataExplorerWidgetModel) {
-    return persist(dataExplorerWidgetModel).v;
-  }
-
-  @Override
-  public void updateDataExplorerWidget(DataExplorerWidgetModel dataExplorerWidgetModel) {
-    update(dataExplorerWidgetModel);
-  }
-
-  @Override
-  public DataExplorerWidgetModel getDataExplorerWidget(String dataExplorerWidgetId) {
-    return find(dataExplorerWidgetId).orElse(new DataExplorerWidgetModel());
-  }
-
-  @Override
-  public void deleteDataExplorerWidget(String dataExplorerWidgetId) {
-    delete(dataExplorerWidgetId);
-
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataProcessorStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataProcessorStorageImpl.java
index cf013b56ea..c6102fbf6b 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataProcessorStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataProcessorStorageImpl.java
@@ -32,16 +32,6 @@ public class DataProcessorStorageImpl extends AbstractDao<DataProcessorDescripti
     super(Utils::getCouchDbDataProcessorDescriptionClient, DataProcessorDescription.class);
   }
 
-  @Override
-  public List<DataProcessorDescription> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(DataProcessorDescription element) {
-    persist(element);
-  }
-
   @Override
   public DataProcessorDescription getElementById(String s) {
     return findWithNullIfEmpty(s);
@@ -61,7 +51,7 @@ public class DataProcessorStorageImpl extends AbstractDao<DataProcessorDescripti
 
   @Override
   public DataProcessorDescription getFirstDataProcessorByAppId(String appId) {
-    return getAll()
+    return this.findAll()
         .stream()
         .filter(p -> p.getAppId().equals(appId))
         .findFirst()
@@ -70,7 +60,7 @@ public class DataProcessorStorageImpl extends AbstractDao<DataProcessorDescripti
 
   @Override
   public List<DataProcessorDescription> getDataProcessorsByAppId(String appId) {
-    return getAll()
+    return this.findAll()
             .stream()
             .filter(p -> p.getAppId().equals(appId))
             .toList();
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataSinkStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataSinkStorageImpl.java
index f15149c1b1..bfaa065dea 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataSinkStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataSinkStorageImpl.java
@@ -31,16 +31,6 @@ public class DataSinkStorageImpl extends AbstractDao<DataSinkDescription> implem
     super(Utils::getCouchDbDataSinkDescriptionClient, DataSinkDescription.class);
   }
 
-  @Override
-  public List<DataSinkDescription> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(DataSinkDescription element) {
-    persist(element);
-  }
-
   @Override
   public DataSinkDescription getElementById(String s) {
     return findWithNullIfEmpty(s);
@@ -60,7 +50,7 @@ public class DataSinkStorageImpl extends AbstractDao<DataSinkDescription> implem
 
   @Override
   public DataSinkDescription getFirstDataSinkByAppId(String appId) {
-    return getAll()
+    return this.findAll()
         .stream()
         .filter(s -> s.getAppId().equals(appId))
         .findFirst()
@@ -69,7 +59,7 @@ public class DataSinkStorageImpl extends AbstractDao<DataSinkDescription> implem
 
   @Override
   public List<DataSinkDescription> getDataSinksByAppId(String appId) {
-    return getAll()
+    return this.findAll()
             .stream()
             .filter(s -> s.getAppId().equals(appId))
             .toList();
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataStreamStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataStreamStorageImpl.java
index 542796b508..d035f1f6b1 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataStreamStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataStreamStorageImpl.java
@@ -22,24 +22,12 @@ import org.apache.streampipes.storage.api.IDataStreamStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
-import java.util.List;
-
 public class DataStreamStorageImpl extends AbstractDao<SpDataStream> implements IDataStreamStorage {
 
   public DataStreamStorageImpl() {
     super(Utils::getCouchDbDataStreamDescriptionClient, SpDataStream.class);
   }
 
-  @Override
-  public List<SpDataStream> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(SpDataStream element) {
-    persist(element);
-  }
-
   @Override
   public SpDataStream getElementById(String s) {
     return findWithNullIfEmpty(s);
@@ -59,7 +47,7 @@ public class DataStreamStorageImpl extends AbstractDao<SpDataStream> implements
 
   @Override
   public SpDataStream getDataStreamByAppId(String appId) {
-    return getAll()
+    return this.findAll()
         .stream()
         .filter(s -> s.getAppId().equals(appId))
         .findFirst()
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java
similarity index 53%
rename from streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java
rename to streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java
index 7cd2cbdf25..88e9f275a6 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java
@@ -18,41 +18,34 @@
 
 package org.apache.streampipes.storage.couchdb.impl;
 
-import org.apache.streampipes.model.datalake.DataLakeMeasure;
-import org.apache.streampipes.storage.api.IDataLakeStorage;
+import org.apache.streampipes.model.api.Storable;
+import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
 
-import java.util.List;
+import org.lightcouch.CouchDbClient;
 
-public class DataLakeStorageImpl extends AbstractDao<DataLakeMeasure> implements IDataLakeStorage {
+import java.util.function.Supplier;
 
-  public DataLakeStorageImpl() {
-    super(Utils::getCouchDbDataLakeClient, DataLakeMeasure.class);
-  }
+public class DefaultCrudStorage<T extends Storable> extends AbstractDao<T> implements CRUDStorage<String, T> {
 
-  @Override
-  public boolean storeDataLakeMeasure(DataLakeMeasure measure) {
-    return persist(measure).k;
-  }
-
-  @Override
-  public List<DataLakeMeasure> getAllDataLakeMeasures() {
-    return findAll();
+  public DefaultCrudStorage(Supplier<CouchDbClient> couchDbClientSupplier,
+                            Class<T> clazz) {
+    super(couchDbClientSupplier, clazz);
   }
 
   @Override
-  public DataLakeMeasure findOne(String id) {
-    return find(id).orElse(null);
+  public T getElementById(String id) {
+    return find(id).orElseThrow(IllegalArgumentException::new);
   }
 
   @Override
-  public void updateDataLakeMeasure(DataLakeMeasure measure) {
-    update(measure);
+  public T updateElement(T element) {
+    update(element);
+    return findWithNullIfEmpty(element.getElementId());
   }
 
   @Override
-  public void deleteDataLakeMeasure(String id) {
-    delete(id);
+  public void deleteElement(T element) {
+    delete(element.getElementId());
   }
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java
index 72bee5d5b5..554632ca80 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java
@@ -23,8 +23,6 @@ import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
-import java.util.List;
-
 public class ExtensionsServiceConfigStorageImpl extends AbstractDao<SpServiceConfiguration>
     implements CRUDStorage<String, SpServiceConfiguration> {
 
@@ -32,16 +30,6 @@ public class ExtensionsServiceConfigStorageImpl extends AbstractDao<SpServiceCon
     super(Utils::getCouchDbServiceConfigStorage, SpServiceConfiguration.class);
   }
 
-  @Override
-  public List<SpServiceConfiguration> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(SpServiceConfiguration element) {
-    persist(element);
-  }
-
   @Override
   public SpServiceConfiguration getElementById(String id) {
     return findWithNullIfEmpty(id);
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java
index 85a36e85d7..230c7a3393 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java
@@ -23,8 +23,6 @@ import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
-import java.util.List;
-
 public class ExtensionsServiceStorageImpl extends AbstractDao<SpServiceRegistration>
     implements CRUDStorage<String, SpServiceRegistration> {
 
@@ -32,20 +30,9 @@ public class ExtensionsServiceStorageImpl extends AbstractDao<SpServiceRegistrat
     super(Utils::getCouchDbExtensionsStorage, SpServiceRegistration.class);
   }
 
-
-  @Override
-  public List<SpServiceRegistration> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(SpServiceRegistration element) {
-    persist(element);
-  }
-
   @Override
   public SpServiceRegistration getElementById(String id) {
-    return find(id).orElseThrow(IllegalArgumentException::new);
+    return findWithNullIfEmpty(id);
   }
 
   @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java
index 618b10885b..2f65f09912 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java
@@ -22,17 +22,12 @@ import org.apache.streampipes.storage.api.IFileMetadataStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.util.List;
 import java.util.stream.Collectors;
 
 public class FileMetadataStorageImpl extends AbstractDao<FileMetadata> implements
     IFileMetadataStorage {
 
-  Logger logger = LoggerFactory.getLogger(NotificationStorageImpl.class);
-
   public FileMetadataStorageImpl() {
     super(Utils::getCouchDbFileMetadataClient, FileMetadata.class);
   }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/NotificationStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/NotificationStorageImpl.java
index 8cd2d8b625..8c1b6c13a0 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/NotificationStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/NotificationStorageImpl.java
@@ -27,8 +27,6 @@ import org.apache.streampipes.storage.couchdb.utils.Utils;
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import org.lightcouch.View;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
 import java.util.List;
@@ -37,8 +35,6 @@ import java.util.stream.Collectors;
 public class NotificationStorageImpl extends AbstractDao<Notification> implements
     INotificationStorage {
 
-  Logger logger = LoggerFactory.getLogger(NotificationStorageImpl.class);
-
   public NotificationStorageImpl() {
     super(Utils::getCouchDbNotificationClient, Notification.class);
   }
@@ -137,7 +133,7 @@ public class NotificationStorageImpl extends AbstractDao<Notification> implement
             .group(true)
             .query(JsonObject.class);
 
-    if (count.size() > 0) {
+    if (!count.isEmpty()) {
       Integer countValue = count.get(0).get("value").getAsInt();
       return new NotificationCount(countValue);
     } else {
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java
index 30bcf74fb0..4a8b687658 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java
@@ -19,30 +19,26 @@ package org.apache.streampipes.storage.couchdb.impl;
 
 import org.apache.streampipes.model.client.user.PasswordRecoveryToken;
 import org.apache.streampipes.storage.api.IPasswordRecoveryTokenStorage;
-import org.apache.streampipes.storage.couchdb.dao.CrudDao;
+import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
 import java.util.List;
 
-public class PasswordRecoveryTokenImpl extends CrudDao implements IPasswordRecoveryTokenStorage {
+public class PasswordRecoveryTokenImpl extends AbstractDao<PasswordRecoveryToken>
+    implements IPasswordRecoveryTokenStorage {
 
   private static final String viewName = "users/password-recovery";
 
   public PasswordRecoveryTokenImpl() {
-    super(Utils::getCouchDbUserClient);
+    super(Utils::getCouchDbUserClient, PasswordRecoveryToken.class);
   }
 
 
   @Override
-  public List<PasswordRecoveryToken> getAll() {
+  public List<PasswordRecoveryToken> findAll() {
     return findAll(viewName, PasswordRecoveryToken.class);
   }
 
-  @Override
-  public void createElement(PasswordRecoveryToken element) {
-    persist(element, PasswordRecoveryToken.class);
-  }
-
   @Override
   public PasswordRecoveryToken getElementById(String s) {
     return findWithNullIfEmpty(s, PasswordRecoveryToken.class);
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCanvasMetadataStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCanvasMetadataStorageImpl.java
index 8b1712c7bd..65b097059c 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCanvasMetadataStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCanvasMetadataStorageImpl.java
@@ -22,8 +22,6 @@ import org.apache.streampipes.storage.api.IPipelineCanvasMetadataStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
-import java.util.List;
-
 public class PipelineCanvasMetadataStorageImpl extends AbstractDao<PipelineCanvasMetadata>
     implements IPipelineCanvasMetadataStorage {
 
@@ -31,16 +29,6 @@ public class PipelineCanvasMetadataStorageImpl extends AbstractDao<PipelineCanva
     super(Utils::getCouchDbPipelineCanvasMetadataClient, PipelineCanvasMetadata.class);
   }
 
-  @Override
-  public List<PipelineCanvasMetadata> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(PipelineCanvasMetadata element) {
-    persist(element);
-  }
-
   @Override
   public PipelineCanvasMetadata getElementById(String id) {
     return find(id).orElseThrow(IllegalArgumentException::new);
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementDescriptionStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementDescriptionStorageImpl.java
index 0b8e26ca6a..7a2a291b52 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementDescriptionStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementDescriptionStorageImpl.java
@@ -53,13 +53,13 @@ public class PipelineElementDescriptionStorageImpl implements IPipelineElementDe
 
   @Override
   public boolean storeDataStream(SpDataStream stream) {
-    this.dataStreamStorage.createElement(stream);
+    this.dataStreamStorage.persist(stream);
     return true;
   }
 
   @Override
   public boolean storeDataProcessor(DataProcessorDescription processorDescription) {
-    this.dataProcessorStorage.createElement(processorDescription);
+    this.dataProcessorStorage.persist(processorDescription);
     return true;
   }
 
@@ -105,12 +105,12 @@ public class PipelineElementDescriptionStorageImpl implements IPipelineElementDe
 
   @Override
   public List<SpDataStream> getAllDataStreams() {
-    return this.dataStreamStorage.getAll();
+    return this.dataStreamStorage.findAll();
   }
 
   @Override
   public List<DataProcessorDescription> getAllDataProcessors() {
-    return this.dataProcessorStorage.getAll();
+    return this.dataProcessorStorage.findAll();
   }
 
   @Override
@@ -249,7 +249,7 @@ public class PipelineElementDescriptionStorageImpl implements IPipelineElementDe
 
   @Override
   public boolean storeDataSink(DataSinkDescription sec) {
-    this.dataSinkStorage.createElement(sec);
+    this.dataSinkStorage.persist(sec);
     return true;
   }
 
@@ -261,7 +261,7 @@ public class PipelineElementDescriptionStorageImpl implements IPipelineElementDe
 
   @Override
   public List<DataSinkDescription> getAllDataSinks() {
-    return this.dataSinkStorage.getAll();
+    return this.dataSinkStorage.findAll();
   }
 
   @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java
index fde5d02bb7..03cae5751b 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java
@@ -18,14 +18,12 @@
 
 package org.apache.streampipes.storage.couchdb.impl;
 
-import org.apache.streampipes.model.VirtualSensor;
 import org.apache.streampipes.model.pipeline.Pipeline;
 import org.apache.streampipes.storage.api.IPipelineStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
 import com.google.gson.JsonObject;
-import org.lightcouch.CouchDbClient;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -33,7 +31,6 @@ import java.util.stream.Collectors;
 
 public class PipelineStorageImpl extends AbstractDao<Pipeline> implements IPipelineStorage {
 
-  private static final String SYSTEM_USER = "system";
   private static final String ADAPTER_VIEW = "adapters/used-adapters";
   private static final String ALL_PIPELINES_VIEW = "pipelines/all";
 
@@ -65,15 +62,6 @@ public class PipelineStorageImpl extends AbstractDao<Pipeline> implements IPipel
     return result;
   }
 
-  @Override
-  public List<Pipeline> getSystemPipelines() {
-    List<Pipeline> pipelines = getAllPipelines();
-    return pipelines
-        .stream()
-        .filter(p -> p.getCreatedByUser().equals(SYSTEM_USER))
-        .collect(Collectors.toList());
-  }
-
   @Override
   public void storePipeline(Pipeline pipeline) {
     persist(pipeline);
@@ -98,22 +86,4 @@ public class PipelineStorageImpl extends AbstractDao<Pipeline> implements IPipel
   public void store(Pipeline object) {
     persist(object);
   }
-
-  @Override
-  public void storeVirtualSensor(String username, VirtualSensor virtualSensor) {
-    CouchDbClient couchDbClient = couchDbClientSupplier.get();
-    couchDbClient.save(virtualSensor);
-    couchDbClient.shutdown();
-  }
-
-  @Override
-  public List<VirtualSensor> getVirtualSensors(String username) {
-    CouchDbClient couchDbClient = couchDbClientSupplier.get();
-    List<VirtualSensor> virtualSensors = couchDbClient.view("_all_docs")
-        .includeDocs(true)
-        .query(VirtualSensor.class);
-    couchDbClient.shutdown();
-    return virtualSensors;
-  }
-
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java
index 3fbf356dc6..79d5f93509 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java
@@ -19,29 +19,24 @@ package org.apache.streampipes.storage.couchdb.impl;
 
 import org.apache.streampipes.model.client.user.UserActivationToken;
 import org.apache.streampipes.storage.api.IUserActivationTokenStorage;
-import org.apache.streampipes.storage.couchdb.dao.CrudDao;
+import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
 import java.util.List;
 
-public class UserActivationTokenImpl extends CrudDao implements IUserActivationTokenStorage {
+public class UserActivationTokenImpl extends AbstractDao<UserActivationToken> implements IUserActivationTokenStorage {
 
   private static final String viewName = "users/user-activation";
 
   public UserActivationTokenImpl() {
-    super(Utils::getCouchDbUserClient);
+    super(Utils::getCouchDbUserClient, UserActivationToken.class);
   }
 
   @Override
-  public List<UserActivationToken> getAll() {
+  public List<UserActivationToken> findAll() {
     return findAll(viewName, UserActivationToken.class);
   }
 
-  @Override
-  public void createElement(UserActivationToken element) {
-    persist(element, UserActivationToken.class);
-  }
-
   @Override
   public UserActivationToken getElementById(String s) {
     return findWithNullIfEmpty(s, UserActivationToken.class);
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java
index 9039413152..e657e960a2 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java
@@ -19,29 +19,24 @@ package org.apache.streampipes.storage.couchdb.impl;
 
 import org.apache.streampipes.model.client.user.Group;
 import org.apache.streampipes.storage.api.IUserGroupStorage;
-import org.apache.streampipes.storage.couchdb.dao.CrudDao;
+import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
 import java.util.List;
 
-public class UserGroupStorageImpl extends CrudDao implements IUserGroupStorage {
+public class UserGroupStorageImpl extends AbstractDao<Group> implements IUserGroupStorage {
 
   private static final String viewName = "users/groups";
 
   public UserGroupStorageImpl() {
-    super(Utils::getCouchDbUserClient);
+    super(Utils::getCouchDbUserClient, Group.class);
   }
 
   @Override
-  public List<Group> getAll() {
+  public List<Group> findAll() {
     return findAll(viewName, Group.class);
   }
 
-  @Override
-  public void createElement(Group element) {
-    persist(element, Group.class);
-  }
-
   @Override
   public Group getElementById(String s) {
     return findWithNullIfEmpty(s, Group.class);
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
index 1d4819cf1a..7f9cfd15ff 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
@@ -66,10 +66,6 @@ public class Utils {
     return getCouchDbGsonClient("general-configuration");
   }
 
-  public static CouchDbClient getCouchDbCategoryClient() {
-    return getCouchDbGsonClient("category");
-  }
-
   public static CouchDbClient getCouchDbServiceConfigStorage() {
     return getCouchDbGsonClient("extensions-services-configurations");
   }
@@ -110,46 +106,10 @@ public class Utils {
     return getCouchDbStandardSerializerClient("connection");
   }
 
-  public static CouchDbClient getCouchDbVisualizationClient() {
-    return getCouchDbStandardSerializerClient("visualizations");
-  }
-
-  public static CouchDbClient getCouchDbDataExplorerDashboardClient() {
-    return getCouchDbGsonClient("dataexplorerdashboard");
-  }
-
-  public static CouchDbClient getCouchDbDataExplorerWidgetClient() {
-    return getCouchDbGsonClient("dataexplorerwidget");
-  }
-
-  public static CouchDbClient getCouchDbDashboardClient() {
-    return getCouchDbGsonClient("dashboard");
-  }
-
-  public static CouchDbClient getCouchDbDashboardWidgetClient() {
-    return getCouchDbGsonClient("dashboardwidget");
-  }
-
   public static CouchDbClient getCouchDbUserClient() {
     return getCouchDbPrincipalClient(USER_DB_NAME);
   }
 
-  public static CouchDbClient getCouchDbInternalUsersClient() {
-    return getCouchDbStandardSerializerClient("_users");
-  }
-
-  public static CouchDbClient getCouchDbReplicatorClient() {
-    return getCouchDbStandardSerializerClient("_replicator");
-  }
-
-  public static CouchDbClient getCouchDbGlobalChangesClient() {
-    return getCouchDbStandardSerializerClient("_global_changes");
-  }
-
-  public static CouchDbClient getCouchDbMonitoringClient() {
-    return getCouchDbStandardSerializerClient("monitoring");
-  }
-
   public static CouchDbClient getCouchDbNotificationClient() {
     return getCouchDbStandardSerializerClient("notification");
   }
@@ -158,11 +118,7 @@ public class Utils {
     return getCouchDbStandardSerializerClient("pipelinecategories");
   }
 
-  public static CouchDbClient getCouchDbDataLakeClient() {
-    return getCouchDbGsonClient("data-lake");
-  }
-
-  private static CouchDbClient getCouchDbGsonClient(String dbname) {
+  public static CouchDbClient getCouchDbGsonClient(String dbname) {
     CouchDbClient dbClient = new CouchDbClient(props(dbname));
     dbClient.setGsonBuilder(GsonSerializer.getGsonBuilder());
     return dbClient;
@@ -188,10 +144,6 @@ public class Utils {
     return new CouchDbClient(props(database, createIfNotExists));
   }
 
-  public static CouchDbClient getCouchDbClient(String database) {
-    return new CouchDbClient(props(database));
-  }
-
   private static CouchDbProperties props(String dbname,
                                          boolean createDbIfNotExists) {
     var env = getEnvironment();
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
index f46ed1d04b..b26c60be9b 100644
--- a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
@@ -22,11 +22,7 @@ import { map } from 'rxjs/operators';
 import { Observable } from 'rxjs';
 import { MeasurementUnit } from '../model/measurement-unit/MeasurementUnit';
 import { PlatformServicesCommons } from './commons.service';
-import {
-    DashboardWidgetModel,
-    Pipeline,
-    VisualizablePipeline,
-} from '../model/gen/streampipes-model';
+import { DashboardWidgetModel, Pipeline } from '../model/gen/streampipes-model';
 import { Dashboard } from '../model/dashboard/dashboard.model';
 
 @Injectable({
@@ -46,37 +42,6 @@ export class DashboardService {
         );
     }
 
-    getVisualizablePipelines(): Observable<VisualizablePipeline[]> {
-        return this.http.get(this.visualizablePipelineUrl).pipe(
-            map(data => {
-                return (data as []).map(p =>
-                    VisualizablePipeline.fromData(p as VisualizablePipeline),
-                );
-            }),
-        );
-    }
-
-    getVisualizablePipelineByPipelineIdAndVisualizationName(
-        pipelineId: string,
-        visualizationName: string,
-    ): Observable<VisualizablePipeline> {
-        return this.http
-            .get(
-                this.visualizablePipelineUrl +
-                    '/' +
-                    pipelineId +
-                    '/' +
-                    visualizationName,
-            )
-            .pipe(
-                map(data => {
-                    return VisualizablePipeline.fromData(
-                        data as VisualizablePipeline,
-                    );
-                }),
-            );
-    }
-
     getDashboards(): Observable<Dashboard[]> {
         return this.http.get(this.dashboardUrl).pipe(
             map(data => {
@@ -111,7 +76,7 @@ export class DashboardService {
 
     updateDashboard(dashboard: Dashboard): Observable<Dashboard> {
         return this.http
-            .put(this.dashboardUrl + '/' + dashboard._id, dashboard)
+            .put(this.dashboardUrl + '/' + dashboard.elementId, dashboard)
             .pipe(
                 map(data => {
                     return data as Dashboard;
@@ -120,7 +85,7 @@ export class DashboardService {
     }
 
     deleteDashboard(dashboard: Dashboard): Observable<any> {
-        return this.http.delete(this.dashboardUrl + '/' + dashboard._id);
+        return this.http.delete(this.dashboardUrl + '/' + dashboard.elementId);
     }
 
     saveDashboard(dashboard: Dashboard): Observable<any> {
@@ -147,10 +112,6 @@ export class DashboardService {
         return this.baseUrl + '/dashboard/widgets';
     }
 
-    private get visualizablePipelineUrl() {
-        return this.baseUrl + '/dashboard/pipelines';
-    }
-
     getWidget(widgetId: string): Observable<DashboardWidgetModel> {
         return this.http.get(this.dashboardWidgetUrl + '/' + widgetId).pipe(
             map(d => {
@@ -175,7 +136,7 @@ export class DashboardService {
 
     updateWidget(widget: DashboardWidgetModel): Observable<any> {
         return this.http.put(
-            this.dashboardWidgetUrl + '/' + widget._id,
+            this.dashboardWidgetUrl + '/' + widget.elementId,
             widget,
         );
     }
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
index 11a22dae9b..a9315adca6 100644
--- a/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
@@ -125,7 +125,7 @@ export class DataViewDataExplorerService {
 
     updateWidget(widget: DataExplorerWidgetModel): Observable<any> {
         return this.http.put(
-            this.dashboardWidgetUrl + '/' + widget._id,
+            this.dashboardWidgetUrl + '/' + widget.elementId,
             widget,
         );
     }
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/shared-dashboard.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/shared-dashboard.service.ts
index 53238f996d..90f6e28554 100644
--- a/ui/projects/streampipes/platform-services/src/lib/apis/shared-dashboard.service.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/apis/shared-dashboard.service.ts
@@ -41,7 +41,7 @@ export class SharedDatalakeRestService {
         dashboard: Dashboard,
     ): Observable<Dashboard> {
         return this.http
-            .put(dashboardUrl + '/' + dashboard._id, dashboard)
+            .put(dashboardUrl + '/' + dashboard.elementId, dashboard)
             .pipe(
                 map(data => {
                     return data as Dashboard;
@@ -53,7 +53,7 @@ export class SharedDatalakeRestService {
         dashboardUrl: string,
         dashboard: Dashboard,
     ): Observable<any> {
-        return this.http.delete(dashboardUrl + '/' + dashboard._id);
+        return this.http.delete(dashboardUrl + '/' + dashboard.elementId);
     }
 
     saveDashboard(dashboardUrl: string, dashboard: Dashboard): Observable<any> {
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
index 017225bf26..c73bedb49d 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
@@ -36,6 +36,6 @@ export interface Dashboard {
     widgets?: ClientDashboardItem[];
     dashboardTimeSettings?: TimeSettings;
     dashboardGeneralSettings?: any;
-    _id?: string;
-    _rev?: string;
+    elementId?: string;
+    rev?: string;
 }
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index cae644ba47..b859b31db2 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -20,9 +20,9 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2024-06-17 23:25:59.
+// Generated using typescript-generator version 3.2.1263 on 2024-06-26 16:51:04.
 
-export class NamedStreamPipesEntity {
+export class NamedStreamPipesEntity implements Storable {
     '@class':
         | 'org.apache.streampipes.model.connect.grounding.ProtocolDescription'
         | 'org.apache.streampipes.model.template.PipelineTemplateDescription'
@@ -32,7 +32,6 @@ export class NamedStreamPipesEntity {
         | 'org.apache.streampipes.model.base.InvocableStreamPipesEntity'
         | 'org.apache.streampipes.model.graph.DataProcessorInvocation'
         | 'org.apache.streampipes.model.graph.DataSinkInvocation';
-    '_rev': string;
     'appId': string;
     'connectedTo': string[];
     'description': string;
@@ -44,6 +43,7 @@ export class NamedStreamPipesEntity {
     'includesLocales': boolean;
     'internallyManaged': boolean;
     'name': string;
+    'rev': string;
 
     static 'fromData'(
         data: NamedStreamPipesEntity,
@@ -54,7 +54,6 @@ export class NamedStreamPipesEntity {
         }
         const instance = target || new NamedStreamPipesEntity();
         instance['@class'] = data['@class'];
-        instance._rev = data._rev;
         instance.appId = data.appId;
         instance.connectedTo = __getCopyArrayFn(__identity<string>())(
             data.connectedTo,
@@ -72,6 +71,7 @@ export class NamedStreamPipesEntity {
         instance.includesLocales = data.includesLocales;
         instance.internallyManaged = data.internallyManaged;
         instance.name = data.name;
+        instance.rev = data.rev;
         return instance;
     }
 }
@@ -950,9 +950,9 @@ export class CustomTransformOutputStrategy extends OutputStrategy {
     }
 }
 
-export class DashboardEntity {
-    _id: string;
-    _rev: string;
+export class DashboardEntity implements Storable {
+    elementId: string;
+    rev: string;
 
     static fromData(
         data: DashboardEntity,
@@ -962,8 +962,8 @@ export class DashboardEntity {
             return data;
         }
         const instance = target || new DashboardEntity();
-        instance._id = data._id;
-        instance._rev = data._rev;
+        instance.elementId = data.elementId;
+        instance.rev = data.rev;
         return instance;
     }
 }
@@ -1000,15 +1000,16 @@ export class DashboardItem {
     }
 }
 
-export class DashboardModel {
-    _id: string;
-    _rev: string;
+export class DashboardModel implements Storable {
+    couchDbId: string;
     dashboardGeneralSettings: { [index: string]: any };
     dashboardTimeSettings: { [index: string]: any };
     description: string;
     displayHeader: boolean;
+    elementId: string;
     id: string;
     name: string;
+    rev: string;
     widgets: DashboardItem[];
 
     static fromData(
@@ -1019,8 +1020,7 @@ export class DashboardModel {
             return data;
         }
         const instance = target || new DashboardModel();
-        instance._id = data._id;
-        instance._rev = data._rev;
+        instance.couchDbId = data.couchDbId;
         instance.dashboardGeneralSettings = __getCopyObjectFn(
             __identity<any>(),
         )(data.dashboardGeneralSettings);
@@ -1029,8 +1029,10 @@ export class DashboardModel {
         );
         instance.description = data.description;
         instance.displayHeader = data.displayHeader;
+        instance.elementId = data.elementId;
         instance.id = data.id;
         instance.name = data.name;
+        instance.rev = data.rev;
         instance.widgets = __getCopyArrayFn(DashboardItem.fromData)(
             data.widgets,
         );
@@ -1128,15 +1130,15 @@ export class DataExplorerWidgetModel extends DashboardEntity {
     }
 }
 
-export class DataLakeMeasure {
+export class DataLakeMeasure implements Storable {
     '@class': 'org.apache.streampipes.model.datalake.DataLakeMeasure';
-    '_rev': string;
     'elementId': string;
     'eventSchema': EventSchema;
     'measureName': string;
     'pipelineId': string;
     'pipelineIsRunning': boolean;
     'pipelineName': string;
+    'rev': string;
     'schemaUpdateStrategy': DataLakeMeasureSchemaUpdateStrategy;
     'schemaVersion': string;
     'timestampField': string;
@@ -1150,13 +1152,13 @@ export class DataLakeMeasure {
         }
         const instance = target || new DataLakeMeasure();
         instance['@class'] = data['@class'];
-        instance._rev = data._rev;
         instance.elementId = data.elementId;
         instance.eventSchema = EventSchema.fromData(data.eventSchema);
         instance.measureName = data.measureName;
         instance.pipelineId = data.pipelineId;
         instance.pipelineIsRunning = data.pipelineIsRunning;
         instance.pipelineName = data.pipelineName;
+        instance.rev = data.rev;
         instance.schemaUpdateStrategy = data.schemaUpdateStrategy;
         instance.schemaVersion = data.schemaVersion;
         instance.timestampField = data.timestampField;
@@ -2720,10 +2722,12 @@ export class PipelineElementStatus {
     }
 }
 
-export class PipelineElementTemplate {
-    _id: string;
-    _rev: string;
+export class PipelineElementTemplate implements Storable {
     basePipelineElementAppId: string;
+    couchDbId: string;
+    couchDbRev: string;
+    elementId: string;
+    rev: string;
     templateConfigs: { [index: string]: PipelineElementTemplateConfig };
     templateDescription: string;
     templateName: string;
@@ -2736,9 +2740,11 @@ export class PipelineElementTemplate {
             return data;
         }
         const instance = target || new PipelineElementTemplate();
-        instance._id = data._id;
-        instance._rev = data._rev;
         instance.basePipelineElementAppId = data.basePipelineElementAppId;
+        instance.couchDbId = data.couchDbId;
+        instance.couchDbRev = data.couchDbRev;
+        instance.elementId = data.elementId;
+        instance.rev = data.rev;
         instance.templateConfigs = __getCopyObjectFn(
             PipelineElementTemplateConfig.fromData,
         )(data.templateConfigs);
@@ -3730,6 +3736,11 @@ export class StaticPropertyAlternatives extends StaticProperty {
     }
 }
 
+export interface Storable {
+    elementId: string;
+    rev: string;
+}
+
 export class StreamPipesApplicationPackage {
     adapters: string[];
     assets: string[];
diff --git a/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts b/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts
index 54faea3742..7f7748e946 100644
--- a/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts
+++ b/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts
@@ -45,7 +45,6 @@ export class AssetDashboardOverviewComponent implements OnInit {
 
     getDashboards() {
         this.restService.getDashboards().subscribe(response => {
-            console.log(response);
             this.dashboardConfigs = response;
         });
     }
diff --git a/ui/src/app/connect/components/adapter-configuration/directives/adapter-template-configuration.directive.ts b/ui/src/app/connect/components/adapter-configuration/directives/adapter-template-configuration.directive.ts
index 4bd1ec2a47..78565e557b 100644
--- a/ui/src/app/connect/components/adapter-configuration/directives/adapter-template-configuration.directive.ts
+++ b/ui/src/app/connect/components/adapter-configuration/directives/adapter-template-configuration.directive.ts
@@ -89,7 +89,7 @@ export abstract class AdapterTemplateConfigurationDirective {
             this.selectedTemplate = event.value;
             this.pipelineElementTemplateService
                 .getConfiguredAdapterForTemplate(
-                    event.value._id,
+                    event.value.elementId,
                     this.adapterDescription,
                 )
                 .subscribe(adapterDescription => {
diff --git a/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html
index 65c18d5129..fe9991be09 100644
--- a/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html
+++ b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html
@@ -86,7 +86,7 @@
                     <button
                         mat-icon-button
                         color="accent"
-                        (click)="deleteTemplate(template._id)"
+                        (click)="deleteTemplate(template.elementId)"
                         data-cy="delete-pipeline-element-template"
                     >
                         <mat-icon>delete</mat-icon>
diff --git a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
index 79e2d77b79..919e2621f1 100644
--- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
+++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
@@ -129,17 +129,20 @@ export class DashboardOverviewComponent implements OnInit {
     }
 
     showDashboard(dashboard: Dashboard): void {
-        this.router.navigate(['dashboard', dashboard._id]);
+        this.router.navigate(['dashboard', dashboard.elementId]);
     }
 
     editDashboard(dashboard: Dashboard): void {
-        this.router.navigate(['dashboard', dashboard._id], {
+        this.router.navigate(['dashboard', dashboard.elementId], {
             queryParams: { action: 'edit' },
         });
     }
 
     openExternalDashboard(dashboard: Dashboard) {
-        const href = this.router.createUrlTree(['standalone', dashboard._id]);
+        const href = this.router.createUrlTree([
+            'standalone',
+            dashboard.elementId,
+        ]);
         // TODO fixes bug that hashing strategy is ignored by createUrlTree
         window.open('#' + href.toString(), '_blank');
     }
@@ -152,7 +155,7 @@ export class DashboardOverviewComponent implements OnInit {
                 title: 'Manage permissions',
                 width: '50vw',
                 data: {
-                    objectInstanceId: dashboard._id,
+                    objectInstanceId: dashboard.elementId,
                     headerTitle:
                         'Manage permissions for dashboard ' + dashboard.name,
                 },
diff --git a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
index 3618a809ca..c20cd66d12 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -137,8 +137,8 @@ export class DashboardPanelComponent implements OnInit {
 
     addWidgetToDashboard(widget: DashboardWidgetModel) {
         const dashboardItem = {} as ClientDashboardItem;
-        dashboardItem.widgetId = widget._id;
-        dashboardItem.id = widget._id;
+        dashboardItem.widgetId = widget.elementId;
+        dashboardItem.id = widget.elementId;
         // TODO there should be a widget type DashboardWidget
         dashboardItem.widgetType = widget.dashboardWidgetSettings.widgetName;
         dashboardItem.cols = 4;
@@ -165,7 +165,7 @@ export class DashboardPanelComponent implements OnInit {
 
     closeEditModeAndReloadDashboard() {
         this.editMode = !this.editMode;
-        this.getDashboard(this.dashboard._id);
+        this.getDashboard(this.dashboard.elementId);
     }
 
     prepareWidgetUpdates(): Observable<any>[] {
@@ -179,7 +179,7 @@ export class DashboardPanelComponent implements OnInit {
 
     discardChanges() {
         this.editModeChange.emit(!this.editMode);
-        this.refreshDashboardService.notify(this.dashboard._id);
+        this.refreshDashboardService.notify(this.dashboard.elementId);
     }
 
     removeAndQueueItemForDeletion(widget: ClientDashboardItem) {
@@ -191,7 +191,7 @@ export class DashboardPanelComponent implements OnInit {
     }
 
     updateAndQueueItemForDeletion(dashboardWidget: DashboardWidgetModel) {
-        this.widgetsToUpdate.set(dashboardWidget._id, dashboardWidget);
+        this.widgetsToUpdate.set(dashboardWidget.elementId, dashboardWidget);
     }
 
     deleteWidgets() {
diff --git a/ui/src/app/dashboard/components/widgets/base/base-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-widget.ts
index f8d7c0c3b4..ccee55aa1e 100644
--- a/ui/src/app/dashboard/components/widgets/base/base-widget.ts
+++ b/ui/src/app/dashboard/components/widgets/base/base-widget.ts
@@ -88,7 +88,7 @@ export abstract class BaseStreamPipesWidget
         const widthOffset = 0;
         const heightOffset = 0;
         this.resizeSub = this.resizeService.resizeSubject.subscribe(info => {
-            if (info.gridsterItem.id === this.widgetConfig._id) {
+            if (info.gridsterItem.id === this.widgetConfig.elementId) {
                 this.onSizeChanged(
                     this.computeCurrentWidth(
                         this.gridsterItemComponent.width - widthOffset,
@@ -266,7 +266,7 @@ export abstract class BaseStreamPipesWidget
 
         if (includeMeasure) {
             queryParams.measureName = this.widgetDataConfig.measureName;
-            queryParams.forId = this.widgetConfig._id;
+            queryParams.forId = this.widgetConfig.elementId;
         }
 
         return queryParams;
diff --git a/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts b/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts
index dfdb732548..241189b4cd 100644
--- a/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts
+++ b/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts
@@ -270,8 +270,8 @@ export class AddVisualizationDialogComponent implements OnInit, AfterViewInit {
                         this.dialogRef.close(response);
                     });
             } else {
-                configuredWidget._id = this.widget._id;
-                configuredWidget._rev = this.widget._rev;
+                configuredWidget.elementId = this.widget.elementId;
+                configuredWidget.rev = this.widget.rev;
                 configuredWidget.widgetId = this.widget.widgetId;
                 this.dialogRef.close(configuredWidget);
             }
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
index 68a578b3e7..6aa928dba7 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
@@ -57,7 +57,7 @@
                             [(dataLakeMeasure)]="dataLakeMeasure"
                             [dataConfig]="currentlyConfiguredWidget.dataConfig"
                             [newWidgetMode]="newWidgetMode"
-                            [widgetId]="currentlyConfiguredWidget._id"
+                            [widgetId]="currentlyConfiguredWidget.elementId"
                             (createWidgetEmitter)="createNewWidget()"
                         >
                         </sp-data-explorer-widget-data-settings>
@@ -91,7 +91,7 @@
                         <sp-data-explorer-widget-appearance-settings
                             fxFlex="100"
                             fxLayout="column"
-                            [widgetId]="currentlyConfiguredWidget._id"
+                            [widgetId]="currentlyConfiguredWidget.elementId"
                             [currentlyConfiguredWidget]="
                                 currentlyConfiguredWidget
                             "
diff --git a/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.ts b/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.ts
index 3252e380d2..8b8b3b8899 100644
--- a/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.ts
+++ b/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.ts
@@ -67,7 +67,7 @@ export class DataExplorerVisualisationSettingsComponent
 
     triggerWidgetTypeChange(ev: MatSelectChange) {
         this.widgetTypeService.notify({
-            widgetId: this.currentlyConfiguredWidget._id,
+            widgetId: this.currentlyConfiguredWidget.elementId,
             newWidgetTypeId: ev.value,
         });
         this.selectWidget();
diff --git a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts
index cd143b836f..6a5e38a4b5 100644
--- a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts
+++ b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts
@@ -135,7 +135,7 @@ export class DataExplorerDashboardOverviewComponent
                 title: 'Manage permissions',
                 width: '50vw',
                 data: {
-                    objectInstanceId: dashboard._id,
+                    objectInstanceId: dashboard.elementId,
                     headerTitle:
                         'Manage permissions for dashboard ' + dashboard.name,
                 },
@@ -160,11 +160,11 @@ export class DataExplorerDashboardOverviewComponent
     }
 
     showDashboard(dashboard: Dashboard) {
-        this.router.navigate(['dataexplorer/', dashboard._id]);
+        this.router.navigate(['dataexplorer/', dashboard.elementId]);
     }
 
     editDashboard(dashboard: Dashboard) {
-        this.router.navigate(['dataexplorer/', dashboard._id], {
+        this.router.navigate(['dataexplorer/', dashboard.elementId], {
             queryParams: { action: 'edit' },
         });
     }
diff --git a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts
index 788b2f3771..5b33a4bfc1 100644
--- a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts
+++ b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts
@@ -162,16 +162,16 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
     addWidgetToDashboard(widget: DataExplorerWidgetModel) {
         // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
         const dashboardItem = {} as ClientDashboardItem;
-        dashboardItem.id = widget._id;
+        dashboardItem.id = widget.elementId;
         dashboardItem.cols = 3;
         dashboardItem.rows = 4;
         dashboardItem.x = 0;
         dashboardItem.y = 0;
         this.dashboard.widgets.push(dashboardItem);
         if (this.viewMode === 'grid') {
-            this.dashboardGrid.loadWidgetConfig(widget._id, true);
+            this.dashboardGrid.loadWidgetConfig(widget.elementId, true);
         } else {
-            this.dashboardSlide.loadWidgetConfig(widget._id, true);
+            this.dashboardSlide.loadWidgetConfig(widget.elementId, true);
         }
     }
 
@@ -179,7 +179,7 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
         this.dataViewDataExplorerService
             .updateDashboard(this.dashboard)
             .subscribe(result => {
-                this.dashboard._rev = result._rev;
+                this.dashboard.rev = result.rev;
                 if (this.widgetIdsToRemove.length > 0) {
                     const observables = this.deleteWidgets();
                     zip(...observables).subscribe(() => {
@@ -220,17 +220,17 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
 
     removeAndQueueItemForDeletion(widget: DataExplorerWidgetModel) {
         const index = this.dashboard.widgets.findIndex(
-            item => item.id === widget._id,
+            item => item.id === widget.elementId,
         );
         this.dashboard.widgets.splice(index, 1);
-        this.widgetIdsToRemove.push(widget._id);
-        if (this.currentlyConfiguredWidget._id === widget._id) {
+        this.widgetIdsToRemove.push(widget.elementId);
+        if (this.currentlyConfiguredWidget.elementId === widget.elementId) {
             this.currentlyConfiguredWidget = undefined;
         }
     }
 
     updateAndQueueItemForDeletion(widget: DataExplorerWidgetModel) {
-        this.widgetsToUpdate.set(widget._id, widget);
+        this.widgetsToUpdate.set(widget.elementId, widget);
     }
 
     deleteWidgets(): Observable<any>[] {
@@ -247,9 +247,9 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
 
     updateCurrentlyConfiguredWidget(currentWidget: DataExplorerWidgetModel) {
         if (currentWidget) {
-            this.widgetsToUpdate.set(currentWidget._id, currentWidget);
+            this.widgetsToUpdate.set(currentWidget.elementId, currentWidget);
             this.currentlyConfiguredWidget = currentWidget;
-            this.currentlyConfiguredWidgetId = currentWidget._id;
+            this.currentlyConfiguredWidgetId = currentWidget.elementId;
             this.designerPanel.modifyWidgetMode(currentWidget, false);
             this.showDesignerPanel = true;
         } else {
@@ -316,7 +316,7 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
     getDashboard(dashboardId: string, startTime: number, endTime: number) {
         this.dataViewService.getDataViews().subscribe(data => {
             this.dashboard = data.filter(
-                dashboard => dashboard._id === dashboardId,
+                dashboard => dashboard.elementId === dashboardId,
             )[0];
             this.breadcrumbService.updateBreadcrumb(
                 this.breadcrumbService.makeRoute(
diff --git a/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts b/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
index 18ab22d48b..be0a6b300e 100644
--- a/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
+++ b/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
@@ -76,7 +76,7 @@ export abstract class AbstractWidgetViewDirective {
             this.dataViewDataExplorerService
                 .updateWidget(value)
                 .subscribe(response => {
-                    value._rev = response._rev;
+                    value.rev = response._rev;
                     this.currentlyConfiguredWidgetId = undefined;
                 });
         });
@@ -84,7 +84,7 @@ export abstract class AbstractWidgetViewDirective {
 
     startEditMode(value: DataExplorerWidgetModel) {
         this.startEditModeEmitter.emit(value);
-        this.currentlyConfiguredWidgetId = value._id;
+        this.currentlyConfiguredWidgetId = value.elementId;
     }
 
     @Input() set dashboard(dashboard: Dashboard) {
@@ -143,9 +143,9 @@ export abstract class AbstractWidgetViewDirective {
         widget.widgetType = this.widgetRegistryService.getWidgetType(
             widget.widgetType,
         );
-        this.configuredWidgets.set(widget._id, widget);
+        this.configuredWidgets.set(widget.elementId, widget);
         this.dataLakeMeasures.set(
-            widget._id,
+            widget.elementId,
             widget.dataConfig.sourceConfigs[0].measure,
         );
     }
@@ -161,7 +161,7 @@ export abstract class AbstractWidgetViewDirective {
     propagateWidgetSelection(configuredWidget: DataExplorerWidgetModel) {
         this.configureWidgetCallback.emit(configuredWidget);
         if (configuredWidget) {
-            this.currentlyConfiguredWidgetId = configuredWidget._id;
+            this.currentlyConfiguredWidgetId = configuredWidget.elementId;
         } else {
             this.currentlyConfiguredWidgetId = undefined;
         }
diff --git a/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html
index aad8de77a6..9331289194 100644
--- a/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html
+++ b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html
@@ -27,7 +27,7 @@
             <div
                 *ngFor="let item of dashboard.widgets; let i = index"
                 [ngClass]="
-                    item.id === currentWidget._id
+                    item.id === currentWidget.elementId
                         ? 'viz-preview viz-preview-selected'
                         : 'viz-preview'
                 "
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
index 69a4463a7f..f2a051edab 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
@@ -24,7 +24,8 @@
             color: configuredWidget.baseAppearanceConfig.textColor,
             height: gridsterItemComponent.height - 13 + 'px',
             border:
-                editMode && currentlyConfiguredWidgetId === configuredWidget._id
+                editMode &&
+                currentlyConfiguredWidgetId === configuredWidget.elementId
                     ? '4px solid var(--color-accent)'
                     : '2px solid ' +
                       configuredWidget.baseAppearanceConfig.backgroundColor
@@ -116,12 +117,14 @@
                 <button
                     mat-icon-button
                     [class.mat-raised-button]="
-                        currentlyConfiguredWidgetId === configuredWidget._id
+                        currentlyConfiguredWidgetId ===
+                        configuredWidget.elementId
                     "
                     (click)="triggerWidgetEditMode()"
                     *ngIf="editMode"
                     [color]="
-                        currentlyConfiguredWidgetId === configuredWidget._id
+                        currentlyConfiguredWidgetId ===
+                        configuredWidget.elementId
                             ? 'accent'
                             : ''
                     "
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
index f617a06ec7..f1a937ffa6 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
@@ -138,7 +138,9 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
         this.widgetTypeChangedSubscription =
             this.widgetTypeService.widgetTypeChangeSubject.subscribe(
                 typeChange => {
-                    if (typeChange.widgetId === this.configuredWidget._id) {
+                    if (
+                        typeChange.widgetId === this.configuredWidget.elementId
+                    ) {
                         this.chooseWidget(typeChange.newWidgetTypeId);
                     }
                 },
@@ -230,7 +232,9 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
     }
 
     triggerWidgetEditMode() {
-        if (this.currentlyConfiguredWidgetId === this.configuredWidget._id) {
+        if (
+            this.currentlyConfiguredWidgetId === this.configuredWidget.elementId
+        ) {
             this.configureWidgetCallback.emit();
         } else {
             this.configureWidgetCallback.emit(this.configuredWidget);
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
index f3ed95c931..0bdd480447 100644
--- a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
@@ -155,7 +155,8 @@ export abstract class BaseDataExplorerWidgetDirective<
             this.widgetConfigurationService.configurationChangedSubject.subscribe(
                 refreshMessage => {
                     if (
-                        refreshMessage.widgetId === this.dataExplorerWidget._id
+                        refreshMessage.widgetId ===
+                        this.dataExplorerWidget.elementId
                     ) {
                         if (refreshMessage.refreshData) {
                             const newFieldsProvider =
@@ -191,7 +192,10 @@ export abstract class BaseDataExplorerWidgetDirective<
         if (!this.previewMode) {
             this.resizeSub = this.resizeService.resizeSubject.subscribe(
                 info => {
-                    if (info.gridsterItem.id === this.dataExplorerWidget._id) {
+                    if (
+                        info.gridsterItem.id ===
+                        this.dataExplorerWidget.elementId
+                    ) {
                         this.onResize(
                             this.gridsterItemComponent.width - this.widthOffset,
                             this.gridsterItemComponent.height -
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-widget-config.ts b/ui/src/app/data-explorer/components/widgets/base/base-widget-config.ts
index 402716de3f..e755b8861b 100644
--- a/ui/src/app/data-explorer/components/widgets/base/base-widget-config.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/base-widget-config.ts
@@ -16,14 +16,7 @@
  *
  */
 
-import {
-    Directive,
-    Input,
-    OnChanges,
-    OnDestroy,
-    OnInit,
-    SimpleChanges,
-} from '@angular/core';
+import { Directive, Input, OnDestroy, OnInit } from '@angular/core';
 import {
     DataExplorerWidgetModel,
     SourceConfig,
@@ -60,7 +53,10 @@ export abstract class BaseWidgetConfig<
         this.configChangedSubject =
             this.widgetConfigurationService.configurationChangedSubject.subscribe(
                 res => {
-                    if (res.widgetId === this.currentlyConfiguredWidget._id) {
+                    if (
+                        res.widgetId ===
+                        this.currentlyConfiguredWidget.elementId
+                    ) {
                         if (res.refreshData) {
                             this.makeFields();
                             this.checkAndInitialize();
@@ -97,7 +93,7 @@ export abstract class BaseWidgetConfig<
 
     triggerDataRefresh() {
         this.widgetConfigurationService.notify({
-            widgetId: this.currentlyConfiguredWidget._id,
+            widgetId: this.currentlyConfiguredWidget.elementId,
             refreshData: true,
             refreshView: true,
         });
@@ -105,7 +101,7 @@ export abstract class BaseWidgetConfig<
 
     triggerViewRefresh() {
         this.widgetConfigurationService.notify({
-            widgetId: this.currentlyConfiguredWidget._id,
+            widgetId: this.currentlyConfiguredWidget.elementId,
             refreshData: false,
             refreshView: true,
         });
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
index c2c3fc7fcb..e684e72f18 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
@@ -63,7 +63,7 @@ export class SelectColorPropertiesComponent implements OnInit {
 
     triggerViewRefresh() {
         this.widgetConfigurationService.notify({
-            widgetId: this.currentlyConfiguredWidget._id,
+            widgetId: this.currentlyConfiguredWidget.elementId,
             refreshData: false,
             refreshView: true,
         });
diff --git a/ui/src/app/editor/dialog/customize/customize.component.ts b/ui/src/app/editor/dialog/customize/customize.component.ts
index 5ba51d280c..88ade59a1a 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.ts
+++ b/ui/src/app/editor/dialog/customize/customize.component.ts
@@ -216,7 +216,7 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
             if (this.cachedPipelineElement instanceof DataProcessorInvocation) {
                 this.pipelineElementTemplateService
                     .getConfiguredDataProcessorForTemplate(
-                        event.value._id,
+                        event.value.elementId,
                         this.cachedPipelineElement,
                     )
                     .subscribe(pe => {
@@ -226,7 +226,7 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
             } else {
                 this.pipelineElementTemplateService
                     .getConfiguredDataSinkForTemplate(
-                        event.value._id,
+                        event.value.elementId,
                         this.cachedPipelineElement as DataSinkInvocation,
                     )
                     .subscribe(pe => {


Test patch:
diff --git a/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java b/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java
index 8484e3f326..6c76d31c40 100644
--- a/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java
+++ b/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java
@@ -21,7 +21,7 @@ package org.apache.streampipes.dataexplorer;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.datalake.DataLakeMeasureSchemaUpdateStrategy;
 import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.storage.api.IDataLakeStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.test.generator.EventPropertyPrimitiveTestBuilder;
 import org.apache.streampipes.test.generator.EventSchemaTestBuilder;
 import org.apache.streampipes.vocabulary.XSD;
@@ -46,17 +46,16 @@ public class DataExplorerSchemaManagementTest {
   public static final String NEW_PROPERTY = "newProperty";
   public static final String OLD_PROPERTY = "oldProperty";
 
-  private IDataLakeStorage dataLakeStorageMock;
+  private CRUDStorage<String, DataLakeMeasure> dataLakeStorageMock;
 
   @BeforeEach
   public void setUp() {
-    dataLakeStorageMock = mock(IDataLakeStorage.class);
+    dataLakeStorageMock = mock(CRUDStorage.class);
   }
 
   @Test
   public void createMeasurementThatNotExisted() {
-    when(dataLakeStorageMock.getAllDataLakeMeasures()).thenReturn(List.of());
-    when(dataLakeStorageMock.storeDataLakeMeasure(any())).thenReturn(true);
+    when(dataLakeStorageMock.findAll()).thenReturn(List.of());
     var schemaManagement = new DataExplorerSchemaManagement(dataLakeStorageMock);
 
     var oldMeasure = getSampleMeasure(
@@ -67,7 +66,7 @@ public class DataExplorerSchemaManagementTest {
 
     assertEquals(oldMeasure.getMeasureName(), resultingMeasure.getMeasureName());
     verify(dataLakeStorageMock, Mockito.times(1))
-        .storeDataLakeMeasure(any());
+        .persist(any());
   }
 
 
@@ -81,8 +80,8 @@ public class DataExplorerSchemaManagementTest {
         )
     );
 
-    when(dataLakeStorageMock.getAllDataLakeMeasures()).thenReturn(List.of(oldMeasure));
-    when(dataLakeStorageMock.findOne(any())).thenReturn(oldMeasure);
+    when(dataLakeStorageMock.findAll()).thenReturn(List.of(oldMeasure));
+    when(dataLakeStorageMock.getElementById(any())).thenReturn(oldMeasure);
     var schemaManagement = new DataExplorerSchemaManagement(dataLakeStorageMock);
 
     var newMeasure = getNewMeasure(DataLakeMeasureSchemaUpdateStrategy.UPDATE_SCHEMA);
@@ -91,7 +90,7 @@ public class DataExplorerSchemaManagementTest {
 
     assertEquals(newMeasure.getMeasureName(), resultMeasure.getMeasureName());
     verify(dataLakeStorageMock, Mockito.times(1))
-        .updateDataLakeMeasure(any());
+        .updateElement(any());
     assertFalse(containsPropertyWithName(resultMeasure, OLD_PROPERTY));
     assertTrue(containsPropertyWithName(resultMeasure, NEW_PROPERTY));
 
@@ -107,15 +106,15 @@ public class DataExplorerSchemaManagementTest {
             getEventProperty(OLD_PROPERTY, XSD.STRING)
         )
     );
-    when(dataLakeStorageMock.getAllDataLakeMeasures()).thenReturn(List.of(oldMeasure));
-    when(dataLakeStorageMock.findOne(any())).thenReturn(oldMeasure);
+    when(dataLakeStorageMock.findAll()).thenReturn(List.of(oldMeasure));
+    when(dataLakeStorageMock.getElementById(any())).thenReturn(oldMeasure);
     var schemaManagement = new DataExplorerSchemaManagement(dataLakeStorageMock);
     var newMeasure = getNewMeasure(DataLakeMeasureSchemaUpdateStrategy.EXTEND_EXISTING_SCHEMA);
 
     var resultMeasure = schemaManagement.createOrUpdateMeasurement(newMeasure);
 
     assertEquals(newMeasure.getMeasureName(), resultMeasure.getMeasureName());
-    verify(dataLakeStorageMock, Mockito.times(1)).updateDataLakeMeasure(any());
+    verify(dataLakeStorageMock, Mockito.times(1)).updateElement(any());
     assertTrue(containsPropertyWithName(resultMeasure, OLD_PROPERTY));
     assertTrue(containsPropertyWithName(resultMeasure, NEW_PROPERTY));
   }
@@ -131,8 +130,8 @@ public class DataExplorerSchemaManagementTest {
         )
     );
 
-    when(dataLakeStorageMock.getAllDataLakeMeasures()).thenReturn(List.of(oldMeasure));
-    when(dataLakeStorageMock.findOne(any())).thenReturn(oldMeasure);
+    when(dataLakeStorageMock.findAll()).thenReturn(List.of(oldMeasure));
+    when(dataLakeStorageMock.getElementById(any())).thenReturn(oldMeasure);
 
     var schemaManagement = new DataExplorerSchemaManagement(dataLakeStorageMock);
 
@@ -140,7 +139,7 @@ public class DataExplorerSchemaManagementTest {
 
     var resultMeasure = schemaManagement.createOrUpdateMeasurement(newMeasure);
     assertEquals(newMeasure.getMeasureName(), resultMeasure.getMeasureName());
-    verify(dataLakeStorageMock, Mockito.times(1)).updateDataLakeMeasure(any());
+    verify(dataLakeStorageMock, Mockito.times(1)).updateElement(any());
     assertEquals(
         2,
         resultMeasure.getEventSchema()
@@ -202,4 +201,4 @@ public class DataExplorerSchemaManagementTest {
                                           .equals(runtimeName)
         );
   }
-}
\ No newline at end of file
+}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementTemplateStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementTemplateStorageImpl.java
index 8e9acf975a..0444ac98f8 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementTemplateStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineElementTemplateStorageImpl.java
@@ -32,16 +32,6 @@ public class PipelineElementTemplateStorageImpl extends AbstractDao<PipelineElem
     super(Utils::getCouchDbPipelineElementTemplateClient, PipelineElementTemplate.class);
   }
 
-  @Override
-  public List<PipelineElementTemplate> getAll() {
-    return findAll();
-  }
-
-  @Override
-  public void createElement(PipelineElementTemplate element) {
-    persist(element);
-  }
-
   @Override
   public PipelineElementTemplate getElementById(String s) {
     return find(s).orElseThrow(RuntimeException::new);
@@ -60,7 +50,7 @@ public class PipelineElementTemplateStorageImpl extends AbstractDao<PipelineElem
 
   @Override
   public List<PipelineElementTemplate> getPipelineElementTemplatesforAppId(String appId) {
-    return getAll()
+    return this.findAll()
         .stream()
         .filter(template -> template.getBasePipelineElementAppId().equals(appId))
         .collect(Collectors.toList());