Repository: digitalservicebund/ris-norms
Pull request #1068: RISDEV-6988-Cleanup-documents-for-prototype
Author: login: SebastianRossa
Created: 2025-03-07T14:32:17Z | Merged: 2025-03-13T13:54:32Z



Diff:
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
index 94aea3501..30a433944 100644
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
@@ -32,6 +32,7 @@ public class PortalPrototypePublishService implements PublishNormsToPortalProtot
   private final LoadNormPort loadNormPort;
   private final LoadPortalPublishingAllowListPort loadPortalPublishingAllowListPort;
   private final ConfidentialDataCleanupService confidentialDataCleanupService;
+  private final PrototypeCleanupService prototypeCleanupService;
 
   public PortalPrototypePublishService(
     LoadNormManifestationElisByPublishStatePort loadNormManifestationElisByPublishStatePort,
@@ -40,7 +41,8 @@ public PortalPrototypePublishService(
     @Qualifier("portalPrototype") PublishChangelogPort publishChangelogsPort,
     LoadNormPort loadNormPort,
     LoadPortalPublishingAllowListPort loadPortalPublishingAllowListPort,
-    ConfidentialDataCleanupService confidentialDataCleanupService
+    ConfidentialDataCleanupService confidentialDataCleanupService,
+    PrototypeCleanupService prototypeCleanupService
   ) {
     this.loadNormManifestationElisByPublishStatePort = loadNormManifestationElisByPublishStatePort;
     this.publishNormPort = publishNormPort;
@@ -49,6 +51,7 @@ public PortalPrototypePublishService(
     this.loadNormPort = loadNormPort;
     this.loadPortalPublishingAllowListPort = loadPortalPublishingAllowListPort;
     this.confidentialDataCleanupService = confidentialDataCleanupService;
+    this.prototypeCleanupService = prototypeCleanupService;
   }
 
   @Override
@@ -77,7 +80,7 @@ public void publishNormsToPortalPrototype() {
         return;
       }
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm);
 
       confidentialDataCleanupService.clean(norm);
 
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
new file mode 100644
index 000000000..478be1fba
--- /dev/null
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
@@ -0,0 +1,124 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import de.bund.digitalservice.ris.norms.utils.exceptions.MandatoryNodeNotFoundException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in
+ * the prototype not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> ALLOWED_METADATA = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link
+   * Norm}.
+   *
+   * <p>This method iterates through each {@link Dokument} in the provided {@link Norm} and applies
+   * a series of metadata-cleaning operations. Specifically, it:
+   *
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.
+   *   <li>Deletes regular metadata.
+   *   <li>Deletes metadata associated with the German federal government.
+   *   <li>Removes specific notes related to amendments.
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   */
+  public void clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isEmpty()) return;
+
+    var nodesToDelete = NodeParser.getNodesFromExpression(
+      createXpathAllDsProprietaryExceptAllowedOnes(),
+      dsProprietary.get()
+    );
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String entryIntoForce = dokument
+      .getMeta()
+      .getProprietary()
+      .orElseThrow(() -> new MandatoryNodeNotFoundException("./ris:legalDocML.de_metadaten"))
+      .getMetadataValue(Metadata.ENTRY_INTO_FORCE)
+      .orElseThrow(() -> new MandatoryNodeNotFoundException("./ris:entryIntoForce"));
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten' and @date='" +
+      entryIntoForce +
+      "')]";
+
+    var nodesToChange = NodeParser.getElementsFromExpression(query, metadataElement);
+    for (Element element : nodesToChange) {
+      element.setAttribute("date", "1001-01-01");
+    }
+  }
+
+  private void deleteMetaData(Dokument dokument, String namespaceUri) {
+    NodeParser
+      .getElementFromExpression(
+        "//Q{" + namespaceUri + "}legalDocML.de_metadaten",
+        dokument.getDocument()
+      )
+      .ifPresent(element -> element.getParentNode().removeChild(element));
+  }
+
+  private static String createXpathAllDsProprietaryExceptAllowedOnes() {
+    String shouldStayConcat = ALLOWED_METADATA
+      .stream()
+      .map(s -> "self::" + s) // Prefix each element with "self::"
+      .collect(Collectors.joining(" or "));
+    return "./*[not(" + shouldStayConcat + ")]";
+  }
+}
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java
index 6d171caa3..7657b55f0 100644
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java
@@ -9,7 +9,7 @@
  * <ul>
  *   <li>A {@link Namespace} that defines its XML namespace.</li>
  *   <li>An XPath expression used to locate the metadata within its parent, bound to the namespace.</li>
- *   <li>A tag name that represents the metadata field.</li>
+ *   <li>A tag name that points to the metadata value. This can be the actual tag name or an attribute depending on where the value is stored</li>
  *   <li>An optional attribute flag indicating whether the metadata is an XML attribute.</li>
  * </ul>
  */
@@ -45,7 +45,8 @@ public enum Metadata {
   ),
   ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit"),
   EXPIRY(Namespace.METADATEN_RIS, "./expiry/@date", "date", true),
-  ENTRY_INTO_FORCE(Namespace.METADATEN_RIS, "./entryIntoForce/@date", "date", true);
+  ENTRY_INTO_FORCE(Namespace.METADATEN_RIS, "./entryIntoForce/@date", "date", true),
+  STANDANGABE(Namespace.METADATEN_RIS, "./standangabe", "standangabe");
 
   private final Namespace namespace;
   private final String xpath;
diff --git a/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishServiceTest.java b/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishServiceTest.java
index 2212a037e..e476af3ca 100644
--- a/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishServiceTest.java
+++ b/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishServiceTest.java
@@ -33,6 +33,7 @@ class PortalPrototypePublishServiceTest {
   final ConfidentialDataCleanupService confidentialDataCleanupService = mock(
     ConfidentialDataCleanupService.class
   );
+  final PrototypeCleanupService prototypeCleanupService = mock(PrototypeCleanupService.class);
   final PortalPrototypePublishService portalPrototypePublishService =
     new PortalPrototypePublishService(
       loadNormManifestationElisByPublishStatePort,
@@ -41,7 +42,8 @@ class PortalPrototypePublishServiceTest {
       publishChangelogPort,
       loadNormPort,
       loadPortalPublishingAllowListPort,
-      confidentialDataCleanupService
+      confidentialDataCleanupService,
+      prototypeCleanupService
     );
 
   @Test
diff --git a/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupServiceTest.java b/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupServiceTest.java
new file mode 100644
index 000000000..83b8c51b8
--- /dev/null
+++ b/backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupServiceTest.java
@@ -0,0 +1,174 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import de.bund.digitalservice.ris.norms.domain.entity.Fixtures;
+import de.bund.digitalservice.ris.norms.domain.entity.Metadata;
+import de.bund.digitalservice.ris.norms.domain.entity.Namespace;
+import de.bund.digitalservice.ris.norms.domain.entity.Norm;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+class PrototypeCleanupServiceTest {
+
+  private final PrototypeCleanupService prototypeCleanupService = new PrototypeCleanupService();
+
+  @Test
+  void cleanRisMetadata() {
+    final Norm norm = Fixtures.loadNormFromDisk("NormWithProprietaryToBeCleaned.xml");
+
+    prototypeCleanupService.clean(norm);
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.SUBTYP)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.BEZEICHNUNG_IN_VORLAGE)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.ART_DER_NORM)
+    )
+      .isEmpty();
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.NORMGEBER)
+    )
+      .isEmpty();
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.SUBTYP)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.BEZEICHNUNG_IN_VORLAGE)
+    )
+      .isEmpty();
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.NORMGEBER)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.BESCHLIESSENDES_ORGAN)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.ORGANISATIONS_EINHEIT)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.ENTRY_INTO_FORCE)
+    )
+      .contains("2025-09-01");
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.EXPIRY)
+    )
+      .contains("2011-12-31");
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.STANDANGABE)
+    )
+      .contains(
+        "V aufgeh. durch Art. 22 G v. 22.12.2011 I 1111 mWv\n                       1.1.2012"
+      );
+  }
+
+  @Test
+  void cleanRegularAndBundesregierungMetadata() {
+    final Norm norm = Fixtures.loadNormFromDisk("NormWithProprietaryToBeCleaned.xml");
+
+    prototypeCleanupService.clean(norm);
+    List<Node> proprietyChildNodes = NodeParser
+      .nodeListToList(
+        norm.getRegelungstext1().getMeta().getProprietary().get().getElement().getChildNodes()
+      )
+      .stream()
+      .filter(node -> node.getNodeType() == Node.ELEMENT_NODE)
+      .toList();
+
+    assertThat(proprietyChildNodes).hasSize(1);
+    assertThat(proprietyChildNodes.get(0).getNamespaceURI())
+      .isEqualTo(Namespace.METADATEN_RIS.getNamespaceUri());
+  }
+
+  @Test
+  void cleanNotesMetadata() {
+    final Norm norm = Fixtures.loadNormFromDisk("NormWithProprietaryToBeCleaned.xml");
+
+    prototypeCleanupService.clean(norm);
+    List<Node> notes = NodeParser
+      .nodeListToList(
+        norm.getRegelungstext1().getMeta().getElement().getElementsByTagName("akn:note")
+      )
+      .stream()
+      .filter(node -> node.getNodeType() == Node.ELEMENT_NODE)
+      .toList();
+
+    assertThat(notes).hasSize(1);
+    assertThat(notes.getFirst().getAttributes().getNamedItem("refersTo").getNodeValue())
+      .isEqualTo("kommentierende-fussnote");
+  }
+
+  @Test
+  void cleanZeitgrenzenMetadata() {
+    final Norm norm = Fixtures.loadNormFromDisk("NormWithProprietaryToBeCleaned.xml");
+
+    prototypeCleanupService.clean(norm);
+
+    List<Node> eventRefs = NodeParser.nodeListToList(
+      norm.getRegelungstext1().getDocument().getElementsByTagName("akn:eventRef")
+    );
+    assertThat(eventRefs).hasSize(28);
+
+    for (Node eventRef : eventRefs) {
+      Element event = (Element) eventRef;
+      String type = event.getAttribute("type");
+      String refersTo = event.getAttribute("refersTo");
+      String date = event.getAttribute("date");
+
+      if (
+        ("generation".equals(type) && "ausfertigung".equals(refersTo)) ||
+        ("generation".equals(type) && "inkrafttreten".equals(refersTo) && "2025-09-01".equals(date))
+      ) {
+        assertThat(date).isNotEqualTo("1001-01-01");
+      } else {
+        assertThat(date).isEqualTo("1001-01-01");
+      }
+    }
+  }
+}
diff --git a/backend/src/test/resources/de/bund/digitalservice/ris/norms/domain/entity/NormWithProprietaryToBeCleaned.xml b/backend/src/test/resources/de/bund/digitalservice/ris/norms/domain/entity/NormWithProprietaryToBeCleaned.xml
new file mode 100644
index 000000000..651500ae5
--- /dev/null
+++ b/backend/src/test/resources/de/bund/digitalservice/ris/norms/domain/entity/NormWithProprietaryToBeCleaned.xml
@@ -0,0 +1,407 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+	##################################################################################
+	Projekt E-Gesetzgebung
+	Nicht-normative Exemplifikation für den Standard LegalDocML.de 1.6 (Dezember 2023)
+
+	2023 Copyright (C) 2021-2023 Bundesministerium des Innern und für Heimat,
+	Referat DG II 6, Maßnahmen Enterprise Resource Management und Elektronische
+	Verwaltungsarbeit
+
+	Veröffentlicht unter der Lizenz CC-BY-3.0 (Creative Commons Namensnennung 3.0)
+	##################################################################################
+-->
+<?xml-model href="../../../Grammatiken/legalDocML.de.sch" schematypens="http://purl.oclc.org/dsdl/schematron"?>
+<akn:akomaNtoso xmlns:akn="http://Inhaltsdaten.LegalDocML.de/1.7.2/"
+                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                xsi:schemaLocation="http://Metadaten.LegalDocML.de/1.7.2/ ../../../Grammatiken/legalDocML.de-metadaten.xsd http://Inhaltsdaten.LegalDocML.de/1.7.2/ ../../../Grammatiken/legalDocML.de-rechtsetzungsdokument.xsd">
+   <akn:act name="regelungstext">
+        <!-- Metadaten-->
+       <akn:meta eId="meta-1" GUID="eae1e025-1648-4053-9d33-b64bff221b3d">
+           <akn:identification eId="meta-1_ident-1"
+                               GUID="6e3766a8-174d-4ead-b913-1fcace3cd1d2"
+                               source="attributsemantik-noch-undefiniert">
+               <akn:FRBRWork eId="meta-1_ident-1_frbrwork-1"
+                             GUID="b2b5e44e-05ab-43f1-a998-8a3eb1936200">
+                   <akn:FRBRthis eId="meta-1_ident-1_frbrwork-1_frbrthis-1"
+                                 GUID="111a26d8-d7b5-4ebc-a8b1-e999e1926f80"
+                                 value="eli/bund/bgbl-1/2002/s1181/rechtsetzungsdokument-1"/>
+                   <akn:FRBRuri eId="meta-1_ident-1_frbrwork-1_frbruri-1"
+                                GUID="14e9a46b-d8e7-4d0e-9615-f786e7501c54"
+                                value="eli/bund/bgbl-1/2002/s1181"/>
+                   <akn:FRBRalias eId="meta-1_ident-1_frbrwork-1_frbralias-1"
+                                  GUID="92fe1317-4a0f-43cf-ad0d-524af051c11c"
+                                  name="übergreifende-id"
+                                  value="5e0e63f4-1cca-44aa-8f5b-875e3df464fe"/>
+                   <akn:FRBRdate eId="meta-1_ident-1_frbrwork-1_frbrdate-1"
+                                 GUID="83fdd9ee-ab40-4eab-a918-86c5d7b72d70"
+                                 date="2002-03-21"
+                                 name="neufassung"/>
+                   <akn:FRBRauthor eId="meta-1_ident-1_frbrwork-1_frbrauthor-1"
+                                   GUID="cefcbaf9-4c8c-4fe1-ba01-678212964fe9"
+                                   href="recht.bund.de/institution/bundesregierung"/>
+                   <akn:FRBRcountry eId="meta-1_ident-1_frbrwork-1_frbrcountry-1"
+                                    GUID="067acc3c-ecdc-4d2b-a0f5-7c2a05c53cc0"
+                                    value="de"/>
+                   <akn:FRBRnumber eId="meta-1_ident-1_frbrwork-1_frbrnumber-1"
+                                   GUID="fa208d03-eaef-4226-9bad-c6f4493e17ff"
+                                   value="s1181"/>
+                   <akn:FRBRname eId="meta-1_ident-1_frbrwork-1_frbrname-1"
+                                 GUID="6dfbaba6-b5d1-47c8-a855-9cd4d11535a2"
+                                 value="bgbl-1"/>
+                   <akn:FRBRsubtype eId="meta-1_ident-1_frbrwork-1_frbrsubtype-1"
+                                    GUID="08e77d78-853b-4ca6-a927-78b41ba44e5b"
+                                    value="rechtsetzungsdokument-1"/>
+               </akn:FRBRWork>
+               <akn:FRBRExpression eId="meta-1_ident-1_frbrexpression-1"
+                                   GUID="2926499a-2c77-4465-a433-4391c52a95d9">
+                   <akn:FRBRthis eId="meta-1_ident-1_frbrexpression-1_frbrthis-1"
+                                 GUID="a54dde16-3222-4d82-9c8f-d181cf6b4ae2"
+                                 value="eli/bund/bgbl-1/2002/s1181/2019-11-22/1/deu/rechtsetzungsdokument-1"/>
+                   <akn:FRBRuri eId="meta-1_ident-1_frbrexpression-1_frbruri-1"
+                                GUID="eccd2b2a-57e3-45f3-8ee2-6cb1dfdf900f"
+                                value="eli/bund/bgbl-1/2002/s1181/2019-11-22/1/deu"/>
+                   <akn:FRBRalias eId="meta-1_ident-1_frbrexpression-1_frbralias-1"
+                                  GUID="2dcf4101-0315-4cff-b943-180f4bc2ac7e"
+                                  name="vorherige-version-id"
+                                  value="faa7106e-db90-4205-9985-28d93cf2aa04"/>
+                   <akn:FRBRalias eId="meta-1_ident-1_frbrexpression-1_frbralias-2"
+                                  GUID="94b5c038-f66c-4399-89e4-a53d700aed19"
+                                  name="aktuelle-version-id"
+                                  value="9a8998e1-2a7f-4f81-99d3-a5f224d317d1"/>
+                   <akn:FRBRalias eId="meta-1_ident-1_frbrexpression-1_frbralias-3"
+                                  GUID="ac66dab7-fcbf-4d3d-8988-a9427f33e4cd"
+                                  name="nachfolgende-version-id"
+                                  value="3a783981-3db0-4708-84cd-622a314a205b"/>
+                   <akn:FRBRauthor eId="meta-1_ident-1_frbrexpression-1_frbrauthor-1"
+                                   GUID="59f381c6-0a36-4b32-a282-7b56192b0fa9"
+                                   href="recht.bund.de/institution/bundesregierung"/>
+                   <akn:FRBRdate eId="meta-1_ident-1_frbrexpression-1_frbrdate-1"
+                                 GUID="08f62601-4fae-4037-a73c-1f0af3c66d66"
+                                 date="2019-11-22"
+                                 name="aenderung"/>
+                   <akn:FRBRlanguage eId="meta-1_ident-1_frbrexpression-1_frbrlanguage-1"
+                                     GUID="20d1ebf2-1ece-4ba7-a2f1-923d75b51217"
+                                     language="deu"/>
+                   <akn:FRBRversionNumber eId="meta-1_ident-1_frbrexpression-1_frbrversionnumber-1"
+                                          GUID="9f13561c-8980-4421-add2-b62651ed2ce5"
+                                          value="1"/>
+               </akn:FRBRExpression>
+               <akn:FRBRManifestation eId="meta-1_ident-1_frbrmanifestation-1"
+                                      GUID="cd18d3f1-5afb-42fb-a158-db4b7f5f4646">
+                   <akn:FRBRthis eId="meta-1_ident-1_frbrmanifestation-1_frbrthis-1"
+                                 GUID="e182b6cd-0dff-4100-bf8a-ba16b4ac1312"
+                                 value="eli/bund/bgbl-1/2002/s1181/2019-11-22/1/deu/2022-08-23/rechtsetzungsdokument-1.xml"/>
+                   <akn:FRBRuri eId="meta-1_ident-1_frbrmanifestation-1_frbruri-1"
+                                GUID="3b330a10-573c-4466-a469-25b85f5ad400"
+                                value="eli/bund/bgbl-1/2002/s1181/2019-11-22/1/deu/2022-08-23/rechtsetzungsdokument-1.xml"/>
+                   <akn:FRBRdate eId="meta-1_ident-1_frbrmanifestation-1_frbrdate-1"
+                                 GUID="b7e717dc-786d-472b-8c1f-7e9e560c0088"
+                                 date="2022-08-23"
+                                 name="generierung"/>
+                   <akn:FRBRauthor eId="meta-1_ident-1_frbrmanifestation-1_frbrauthor-1"
+                                   GUID="58b44e60-8bd9-49f7-93e2-75d6c7ffd5b0"
+                                   href="recht.bund.de"/>
+                   <akn:FRBRformat eId="meta-1_ident-1_frbrmanifestation-1_frbrformat-1"
+                                   GUID="d3fac04b-806c-4cd5-a909-cccac11eff5e"
+                                   value="xml"/>
+               </akn:FRBRManifestation>
+           </akn:identification>
+           <!-- Diese Metadaten sind die Konstituenten für die Schematron-Validierung. -->
+           <akn:lifecycle GUID="47b53983-69fe-402c-9044-3cd95402a748" eId="meta-1_lebzykl-1"
+                          source="attributsemantik-noch-undefiniert">
+               <akn:eventRef GUID="a18a1897-dac0-4c7a-882f-d34c3b3b7b59" date="2011-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-1" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="repeal" />
+               <akn:eventRef GUID="e9b93d1c-fe15-400e-87e8-575bf26cacb3" date="2000-03-17"
+                             eId="meta-1_lebzykl-1_ereignis-2" refersTo="ausfertigung"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+               <akn:eventRef GUID="91331eb2-e02b-4047-9011-c27036e26ab0" date="1999-01-01"
+                             eId="meta-1_lebzykl-1_ereignis-3" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+               <akn:eventRef GUID="2f71454a-710b-40da-836c-1df7a3dbb230" date="2001-08-02"
+                             eId="meta-1_lebzykl-1_ereignis-4" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+               <akn:eventRef GUID="ea1c959e-4510-439a-bbaf-f8118767fbb7" date="2004-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-5" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+               <akn:eventRef GUID="ac9c2fa3-757d-4a74-a0e6-4fd415a5967a" date="2005-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-6" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+               <akn:eventRef GUID="3509044b-b0ae-4b37-aa8e-99f0f3e76c0a" date="2011-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-7" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+               <akn:eventRef GUID="3d9d5798-6de2-43b6-9853-ad24630b730d" date="2001-07-27"
+                             eId="meta-1_lebzykl-1_ereignis-8" refersTo="ausfertigung"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="cbc8498f-1290-40ef-a2d8-3b9889f6b952" date="2001-08-03"
+                             eId="meta-1_lebzykl-1_ereignis-9" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="e8d2929f-b9eb-4211-aecc-757f09cc30b2" date="2003-11-27"
+                             eId="meta-1_lebzykl-1_ereignis-10" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="74686348-f0e3-40b1-9b9f-2f2a4578ffa8" date="2004-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-11" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="db816a34-c300-4158-8447-0cfd0b50ba10" date="2003-11-25"
+                             eId="meta-1_lebzykl-1_ereignis-12" refersTo="ausfertigung"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="48e4341e-8bd7-4d7f-aa7e-3d1d1b9ae0ea" date="2003-11-28"
+                             eId="meta-1_lebzykl-1_ereignis-13" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="b8af58b2-2ab1-45ec-bfb6-b859c2335f14" date="2003-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-14" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="67e17c6f-4655-4753-92dd-8bb46ab1ba61" date="2004-12-09"
+                             eId="meta-1_lebzykl-1_ereignis-15" refersTo="ausfertigung"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="96b2b883-0665-46d2-b07f-5bb1719c6607" date="2004-01-01"
+                             eId="meta-1_lebzykl-1_ereignis-16" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="144d5849-27f0-42da-a3d0-53da55d5a8e1" date="2005-09-30"
+                             eId="meta-1_lebzykl-1_ereignis-17" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="dc1ad87c-710f-4e00-97f0-3deb3a4b8369" date="2005-01-01"
+                             eId="meta-1_lebzykl-1_ereignis-18" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="73ac4986-dede-493e-b609-2b04c744f8de" date="2011-12-31"
+                             eId="meta-1_lebzykl-1_ereignis-19" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="4d88e5f2-ea3d-4917-8476-bdd864d38ec3" date="2005-10-01"
+                             eId="meta-1_lebzykl-1_ereignis-20" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="401fa9de-1c69-4656-a2a6-63049c770a8c" date="2006-11-07"
+                             eId="meta-1_lebzykl-1_ereignis-21" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="a2c5787f-4c99-452c-951d-50c2271576ef" date="2006-01-01"
+                             eId="meta-1_lebzykl-1_ereignis-22" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="cdee732e-0fa5-4af4-b3d4-ce5ce55542fd" date="2006-10-31"
+                             eId="meta-1_lebzykl-1_ereignis-23" refersTo="ausfertigung"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="669563bd-2bfc-4f74-aa7f-61e31e22bffc" date="2006-11-08"
+                             eId="meta-1_lebzykl-1_ereignis-24" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="f595e9a2-a21c-4a83-a256-81fc101d5917" date="2008-06-30"
+                             eId="meta-1_lebzykl-1_ereignis-25" refersTo="ausserkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="87e0b073-362f-4cee-8571-dde9e52adeff" date="2007-03-26"
+                             eId="meta-1_lebzykl-1_ereignis-26" refersTo="ausfertigung"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="b6e98b9f-d7e7-4784-8e52-20aa662ecd78" date="2008-07-01"
+                             eId="meta-1_lebzykl-1_ereignis-27" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="amendment" />
+               <akn:eventRef GUID="91331eb2-e02b-4047-9011-c27036e26ab0" date="2025-09-01"
+                             eId="meta-1_lebzykl-1_ereignis-28" refersTo="inkrafttreten"
+                             source="attributsemantik-noch-undefiniert" type="generation" />
+           </akn:lifecycle>
+           <akn:temporalData GUID="ad7645df-00a2-42b1-b54f-d2beb5ecae22" eId="meta-1_geltzeiten-1"
+                             source="attributsemantik-noch-undefiniert">
+               <akn:temporalGroup GUID="9563ee11-1503-4f72-8198-553916bfabbd"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-1">
+                   <akn:timeInterval GUID="d10a8364-b5ff-4fa4-8d73-906b19aa3d17"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-1_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-4" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-3" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="1c825ca3-75bf-4902-87e7-ad36fc0cb310"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-2">
+                   <akn:timeInterval GUID="1e77d4b7-e67d-4dad-bc3a-9adfc054903a"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-2_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-5" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-3" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="f504be38-7109-4030-b45e-ca019a8dc84b"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-3">
+                   <akn:timeInterval GUID="054f269e-4986-47bc-ba8f-71ce45c8e099"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-3_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-6" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-3" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="8b5a8f4d-ea75-41eb-9895-da7e1eee82f7"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-4">
+                   <akn:timeInterval GUID="6b1b853c-d34b-480d-a817-e5306b581fdc"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-4_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-7" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-3" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="926fe507-4c7f-490b-865b-296951efdef3"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-5">
+                   <akn:timeInterval GUID="4622a206-a076-4f62-8b67-2c70589abda9"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-5_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-10" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-9" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="7312b984-c067-4c3d-9076-8c02f6ddf1e9"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-6">
+                   <akn:timeInterval GUID="4993e5f1-5500-4950-9fcc-4c0127a654e9"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-6_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-11" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-9" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="54773580-d6da-43f5-be59-3476757987de"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-7">
+                   <akn:timeInterval GUID="29a579fb-5fbc-48e2-a4fc-5a02aea281bd"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-7_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-14" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-13" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="0b90ead6-4cc9-43cd-b599-ed559bf145cd"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-8">
+                   <akn:timeInterval GUID="afb396cf-a073-4a1c-97be-88f335f87fdc"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-8_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-17" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-16" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="a10c53b3-125b-4ffd-9f31-52912f94a71a"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-9">
+                   <akn:timeInterval GUID="42c6864f-a5c6-42a6-8357-9c11b50ec69f"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-9_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-19" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-18" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="601569fd-2ffa-45de-8196-4fdf4f9bffcb"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-10">
+                   <akn:timeInterval GUID="a7946209-d4e5-4a45-a10c-594d7b38e96a"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-10_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-21" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-20" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="ddbdf3ad-dbad-4738-95c7-fb225833e2a1"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-11">
+                   <akn:timeInterval GUID="394042f5-9794-4a55-b40a-e8486a0bf2b9"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-11_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-19" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-22" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="3500580e-7acf-43a5-992a-c2815a399d85"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-12">
+                   <akn:timeInterval GUID="b13fd4a3-f248-469c-99d6-dc65791c6e36"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-12_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-25" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-24" />
+               </akn:temporalGroup>
+               <akn:temporalGroup GUID="d57f1e9f-eff2-40dc-8ec0-ae02c2df686e"
+                                  eId="meta-1_geltzeiten-1_geltungszeitgr-13">
+                   <akn:timeInterval GUID="6f18a577-2d1c-44a6-a132-24f688d00da3"
+                                     eId="meta-1_geltzeiten-1_geltungszeitgr-13_gelzeitintervall-1"
+                                     end="#meta-1_lebzykl-1_ereignis-19" refersTo="geltungszeit"
+                                     start="#meta-1_lebzykl-1_ereignis-27" />
+               </akn:temporalGroup>
+           </akn:temporalData>
+           <akn:notes source="attributsemantik-noch-undefiniert">
+               <akn:note GUID="62ef7b71-c670-4639-ba9e-7216f237e9c1" eId="meta-1_editfnote-1"
+                         marker="#" placement="bottom" refersTo="kommentierende-fussnote">
+                   <akn:p GUID="ad2edab0-725d-4459-9731-6c28173ea10b"
+                          eId="meta-1_editfnote-1_text-1">*T (+++ Textnachweis ab: 1.1.1999 +++)</akn:p>
+               </akn:note>
+               <akn:note GUID="3120cc1f-019b-4757-b024-43be6cfcdd42" eId="meta-1_editfnote-2"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="a3de9c13-9e89-49d2-b9f6-c621f9486395"
+                          eId="meta-1_editfnote-2_text-1">*/ Überschrift: IdF d. Art. 75 Nr. 1 G v.
+                       9.12.2004 I 3242 mWv 1.1.2005</akn:p>
+               </akn:note>
+               <akn:note GUID="ae6026db-7e60-4296-a771-1c37df3f0456" eId="meta-1_editfnote-3"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="10ce3f1d-3460-4ce2-a516-b57d0f9d8dab"
+                          eId="meta-1_editfnote-3_text-1">§ 1 Abs. 1 Nr. 6: IdF d. Art. 9 Nr. 1 G v.
+                       27.7.2001 I 1939 mWv 3.8.2001</akn:p>
+               </akn:note>
+               <akn:note GUID="f6cd8c28-13c0-4233-bb4e-29c6f7ee6b48" eId="meta-1_editfnote-4"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="28253cf0-ab16-4ddf-afad-56ec56f7cd0b"
+                          eId="meta-1_editfnote-4_text-1">§ 1 Abs. 1 Nr. 7: Eingef. durch Art. 9 Nr. 1
+                       G v. 27.7.2001 I 1939 mWv 3.8.2001</akn:p>
+               </akn:note>
+               <akn:note GUID="02d4d9b7-c589-4f5a-b41c-0787033c0066" eId="meta-1_editfnote-5"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="bf29b42b-2bc2-41b1-9745-3960f2d705d0"
+                          eId="meta-1_editfnote-5_text-1">§ 1 Abs. 2: IdF d. Art. 75 Nr. 2 G v.
+                       9.12.2004 I 3242 mWv 1.1.2005</akn:p>
+               </akn:note>
+               <akn:note GUID="b4a1a401-0f17-4dde-92ec-d8454333682d" eId="meta-1_editfnote-6"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="70dd68bc-d96b-431c-bfc8-7d2349bcdd9f"
+                          eId="meta-1_editfnote-6_text-1">§ 2 Abs. 1 Satz 2: IdF d. Art. 9 Nr. 2 G v.
+                       27.7.2001 I 1939 mWv 3.8.2001</akn:p>
+               </akn:note>
+               <akn:note GUID="9625eef4-6bd3-44b3-9cb9-1f0a985c9016" eId="meta-1_editfnote-7"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="e65c2505-e81f-42df-b7cf-6d6818c1e049"
+                          eId="meta-1_editfnote-7_text-1">§ 2 Abs. 2: IdF d. Art. 75 Nr. 3 Buchst. a G
+                       v. 9.12.2004 I 3242 mWv 1.10.2005</akn:p>
+               </akn:note>
+               <akn:note GUID="80c2dc7c-0b84-4476-99c0-b9cfcd07d976" eId="meta-1_editfnote-8"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="6e2b13d5-beec-4c9a-a206-494e33f28b78"
+                          eId="meta-1_editfnote-8_text-1">§ 2 Abs. 3: IdF d. Art. 75 Nr. 3 Buchst. b G
+                       v. 9.12.2004 I 3242 mWv 1.1.2004</akn:p>
+               </akn:note>
+               <akn:note GUID="1225e0fe-030b-4e67-9a53-2e6da06cc131" eId="meta-1_editfnote-9"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="4cd63d01-16c6-4f3f-969b-9367f7cf60bd"
+                          eId="meta-1_editfnote-9_text-1">§ 2 Abs. 3 Satz 1: IdF d. Art. 458 V v.
+                       31.10.2006 I 2407 mWv 8.11.2006 u. d. Art. 28 G v. 26.3.2007 I 378 mWv
+                       1.7.2008</akn:p>
+               </akn:note>
+               <akn:note GUID="272c03cc-04a3-4cb4-b0e3-2a7545193891" eId="meta-1_editfnote-10"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="3cf776cd-685b-49a4-b10e-768cb46fe0b5"
+                          eId="meta-1_editfnote-10_text-1">§ 2 Abs. 4 Satz 2: IdF d. Art. 75 Nr. 3
+                       Buchst. c G v. 9.12.2004 I 3242 mWv 1.10.2005</akn:p>
+               </akn:note>
+               <akn:note GUID="7d698ff7-7cd5-4fb1-9133-1898a5f3f124" eId="meta-1_editfnote-11"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="2356a348-bd55-419c-a188-98d9633c80e0"
+                          eId="meta-1_editfnote-11_text-1">§ 3: IdF d. Art. 75 Nr. 4 G v. 9.12.2004 I
+                       3242 mWv 1.1.2005</akn:p>
+               </akn:note>
+               <akn:note GUID="1b5aee45-f740-498f-acf7-bce97f455296" eId="meta-1_editfnote-12"
+                         marker="#" placement="bottom" refersTo="aenderungsfussnote">
+                   <akn:p GUID="00c5f0ec-ad21-4cb0-a541-53e3d028c58b"
+                          eId="meta-1_editfnote-12_text-1">§ 4 Abs. 2 Satz 2 bis 4: Früher Satz 2 u. 3
+                       gem. u. idF d. Art. 75 Nr. 5 G v. 9.12.2004 I 3242 mWv 1.1.2006</akn:p>
+               </akn:note>
+           </akn:notes>
+           <akn:proprietary eId="meta-1_proprietary-1"
+                            GUID="952262d3-de92-4c1d-a06d-95aa94f5f21c"
+                            source="attributsemantik-noch-undefiniert">
+               <meta:legalDocML.de_metadaten xmlns:meta="http://Metadaten.LegalDocML.de/1.7.2/">
+                   <meta:typ>gesetz</meta:typ>
+                   <meta:form>stammform</meta:form>
+                   <meta:fassung>verkuendungsfassung</meta:fassung>
+                   <meta:art>rechtsetzungsdokument</meta:art>
+                   <meta:initiant>nicht-vorhanden</meta:initiant>
+                   <meta:bearbeitendeInstitution>nicht-vorhanden</meta:bearbeitendeInstitution>
+                   <!-- Die vorliegende Angabe von meta:fna stellt einen beliebigen, exemplarischen Fundstellennachweis dar und besitzt keine fachliche Korrektheit. -->
+                   <meta:fna>754-28-1</meta:fna>
+                   <!-- Die vorliegende Angabe von meta:gesta besitzt keine fachliche Korrektheit. -->
+                   <meta:gesta>nicht-vorhanden</meta:gesta>
+                   <!-- Die vorliegenden Angaben von meta:federfuehrung besitzen keine fachliche Korrektheit. -->
+               </meta:legalDocML.de_metadaten>
+               <meta:legalDocML.de_metadaten xmlns:meta="http://MetadatenBundesregierung.LegalDocML.de/1.7.2/">
+                   <meta:federfuehrung>
+                       <meta:federfuehrend ab="2002-12-01"
+                                           bis="unbestimmt">Bundesministerium des Innern und für Heimat</meta:federfuehrend>
+                       <meta:federfuehrend ab="2002-10-01" bis="2002-12-01">Bundesministerium der Justiz</meta:federfuehrend>
+                   </meta:federfuehrung>
+               </meta:legalDocML.de_metadaten>
+               <ris:legalDocML.de_metadaten xmlns:ris="http://MetadatenRIS.LegalDocML.de/1.7.2/">
+                   <ris:subtyp>rechtsverordnung</ris:subtyp>
+                   <ris:bezeichnungInVorlage>Bezeichnung gemäß Vorlage</ris:bezeichnungInVorlage>
+                   <ris:artDerNorm>SN,ÄN,ÜN</ris:artDerNorm>
+                   <ris:normgeber>DEU</ris:normgeber>
+                   <ris:subtyp>new-subtyp</ris:subtyp>
+                   <ris:bezeichnungInVorlage>new-bezeichnungInVorlage</ris:bezeichnungInVorlage>
+                   <ris:normgeber>DDR</ris:normgeber>
+                   <ris:beschliessendesOrgan qualifizierteMehrheit="false">LT</ris:beschliessendesOrgan>
+                   <ris:organisationsEinheit>Andere Organisationseinheit</ris:organisationsEinheit>
+                   <ris:entryIntoForce date="2025-09-01" />
+                   <ris:expiry date="2011-12-31" />
+                   <ris:standangabe type="aufh">V aufgeh. durch Art. 22 G v. 22.12.2011 I 1111 mWv
+                       1.1.2012</ris:standangabe>
+               </ris:legalDocML.de_metadaten>
+           </akn:proprietary>
+      </akn:meta>
+   </akn:act>
+</akn:akomaNtoso>


Reviews:
user: login: malte-laukoetter
body: Looks good to me, i left some (mostly nitpicky) comments :)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-11T16:30:52Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:26:21Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:27:32Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:28:49Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:32:57Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:35:42Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:36:25Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:37:59Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T06:39:49Z
user: login: VictorDelCampo
body: LGTM. Also like Malte just being a nitpicker. And maybe also a comment: you went to xpath querying instead of using our domain classes (eventRef for example). Was this a deliberated decision? I guess you wanted to avoid relying on the domain since this service will be "temporary", if so, GOOD
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-12T06:41:54Z
user: login: SebastianRossa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T06:46:42Z
user: login: SebastianRossa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T06:48:28Z
user: login: SebastianRossa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T07:03:19Z
user: login: SebastianRossa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T07:16:42Z
user: login: malte-laukoetter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T08:20:24Z
user: login: malte-laukoetter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T08:25:34Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T08:30:43Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T08:35:14Z
user: login: malte-laukoetter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T09:07:16Z
user: login: SebastianRossa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T09:29:50Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T09:57:00Z
user: login: malte-laukoetter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T09:57:15Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T09:59:08Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T10:00:02Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T10:05:05Z
user: login: malte-laukoetter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T10:06:26Z
user: login: malte-laukoetter
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T11:15:23Z
user: login: VictorDelCampo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T11:41:18Z

Review comments:
diff_hunk: @@ -0,0 +1,178 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import de.bund.digitalservice.ris.norms.domain.entity.Fixtures;
+import de.bund.digitalservice.ris.norms.domain.entity.Metadata;
+import de.bund.digitalservice.ris.norms.domain.entity.Norm;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+class PrototypeCleanupServiceTest {
+
+  private final PrototypeCleanupService underTest = new PrototypeCleanupService();
+
+  @Test
+  void cleanRisMetadata() {
+    final Norm norm = Fixtures.loadNormFromDisk("NormWithProprietaryToBeCleaned.xml");
+
+    underTest.clean(norm);
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.SUBTYP)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.BEZEICHNUNG_IN_VORLAGE)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.ART_DER_NORM)
+    )
+      .isEmpty();
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.NORMGEBER)
+    )
+      .isEmpty();
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.SUBTYP)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.BEZEICHNUNG_IN_VORLAGE)
+    )
+      .isEmpty();
+    assertThat(
+      norm.getRegelungstext1().getMeta().getProprietary().get().getMetadataValue(Metadata.NORMGEBER)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.BESCHLIESSENDES_ORGAN)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.ORGANISATIONS_EINHEIT)
+    )
+      .isEmpty();
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.ENTRY_INTO_FORCE_DATE)
+    )
+      .contains("2008-07-01");
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.EXPIRY_DATE)
+    )
+      .contains("2011-12-31");
+    assertThat(
+      norm
+        .getRegelungstext1()
+        .getMeta()
+        .getProprietary()
+        .get()
+        .getMetadataValue(Metadata.STANDANGABE)
+    )
+      .contains(
+        "V aufgeh. durch Art. 22 G v. 22.12.2011 I 1111 mWv\n                       1.1.2012"
+      );
+  }
+
+  @Test
+  void cleanRegularAndBundesregierungMetadata() {
+    final Norm norm = Fixtures.loadNormFromDisk("NormWithProprietaryToBeCleaned.xml");
+
+    underTest.clean(norm);
+    List<Node> proprietyChildNodes = NodeParser
+      .nodeListToList(
+        norm.getRegelungstext1().getMeta().getProprietary().get().getElement().getChildNodes()
+      )
+      .stream()
+      .filter(node -> node.getNodeType() == Node.ELEMENT_NODE)
+      .toList();
+
+    assertThat(proprietyChildNodes).hasSize(1);
+    assertThat(proprietyChildNodes.get(0).getNamespaceURI())
+      .isEqualTo("http://MetadatenRIS.LegalDocML.de/1.7.2/");
path: backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupServiceTest.java
user: login: malte-laukoetter
body: i would use `Namespace.METADATEN_RIS.getNamespaceUri()` here as well so we don't need to touch this when updating the ldml version
created_at: 2025-03-11T16:18:29Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,178 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import de.bund.digitalservice.ris.norms.domain.entity.Fixtures;
+import de.bund.digitalservice.ris.norms.domain.entity.Metadata;
+import de.bund.digitalservice.ris.norms.domain.entity.Norm;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+class PrototypeCleanupServiceTest {
+
+  private final PrototypeCleanupService underTest = new PrototypeCleanupService();
path: backend/src/test/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupServiceTest.java
user: login: malte-laukoetter
body: nitpick: in the other tests we have always named this by the name of the service (so eg. `prototypeCleanupService`)
created_at: 2025-03-11T16:19:21Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: malte-laukoetter
body: i was confused for a short moment what exactly `SHOULD_STAY` contains and what it will be used for. Maybe move this down to the one method that is using it? or give it another name?
created_at: 2025-03-11T16:21:13Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: malte-laukoetter
body: nitpick: there is also `Optional::ifPresent` that could have been used here, or maybe an early return?
created_at: 2025-03-11T16:22:35Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: malte-laukoetter
body: we don't have a ticket for this todo item yet, as i wasn't sure if you would just do it in here as well, should i create one?
created_at: 2025-03-11T16:23:54Z
author_association: MEMBER
diff_hunk: @@ -43,7 +43,10 @@ public enum Metadata {
     "qualifizierteMehrheit",
     true
   ),
-  ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit");
+  ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit"),
+  ENTRY_INTO_FORCE_DATE(Namespace.METADATEN_RIS, "./entryIntoForce/@date", "entryIntoForce", true),
+  EXPIRY_DATE(Namespace.METADATEN_RIS, "./expiry/@date", "expiry", true),
path: backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java
user: login: malte-laukoetter
body: we will probably have a merge conflict here as we both added these lines :) Also I think the 3 parameter should be date for both of these as that is the attribute that should be read and `isAttribute` is true
created_at: 2025-03-11T16:28:43Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: VictorDelCampo
body: Should we integrate the clean-up service into `PortalPrototypePublishService` to have just 1 service with this "temporary" code? or do we wanna keep the clean-up separated for testing purposes?
created_at: 2025-03-12T06:26:21Z
author_association: MEMBER
diff_hunk: @@ -43,7 +43,10 @@ public enum Metadata {
     "qualifizierteMehrheit",
     true
   ),
-  ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit");
+  ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit"),
+  ENTRY_INTO_FORCE_DATE(Namespace.METADATEN_RIS, "./entryIntoForce/@date", "entryIntoForce", true),
+  EXPIRY_DATE(Namespace.METADATEN_RIS, "./expiry/@date", "expiry", true),
path: backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java
user: login: VictorDelCampo
body: Jep it should be date, as these metadata are attributes. Good catch!
created_at: 2025-03-12T06:27:32Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: I prefer personally to have them at the top of the class (like in the table of content service) but you can decide. 
About the naming what about "ALLOWED_METADATA" ? 
created_at: 2025-03-12T06:28:49Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: Bit nitpicking.... what about using a forEach on the Set directly?

```
    norm.getDokumente().forEach(dokument -> {
        cleanRisMetadata(dokument);
        ...
    });
```
created_at: 2025-03-12T06:32:57Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: +1 for if present
created_at: 2025-03-12T06:35:42Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: Nitpicking again, i would make another foreach here and 1-liner:

```
 NodeParser.getNodesFromExpression(createXpathAllDsProprietaryExceptShouldStay(), dsProprietary)
            .forEach(node -> node.getParentNode().removeChild(node))
```
created_at: 2025-03-12T06:36:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
+      for (Node node : nodesToDelete) {
+        node.getParentNode().removeChild(node);
+      }
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten')]";
+    var nodesToChange = NodeParser.getElementsFromExpression(query, metadataElement);
+    for (Element element : nodesToChange) {
+      element.setAttribute("date", "1001-01-01");
+    }
+  }
+
+  private void deleteMetaData(Dokument dokument, String namespaceUri) {
+    Optional<Element> proprietaryElement = NodeParser.getElementFromExpression(
+      "//Q{" + namespaceUri + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    proprietaryElement.ifPresent(element -> element.getParentNode().removeChild(element));
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: would combine these two statements:
```
    NodeParser.getElementFromExpression(
        "//Q{" + namespaceUri + "}legalDocML.de_metadaten",
        dokument.getDocument()
    ).ifPresent(element -> element.getParentNode().removeChild(element));
```
created_at: 2025-03-12T06:37:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
+      for (Node node : nodesToDelete) {
+        node.getParentNode().removeChild(node);
+      }
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten')]";
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: Didn't you say something about only the first `ausfertigung` and the first `inkraftreten` can stay? Or is it exactly the combination of generation+ausfertigung and generation+inkraftreten ? These combinations can only happen once each?
created_at: 2025-03-12T06:39:49Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: SebastianRossa
body: @VictorDelCampo I prefer small concise classes. It's just easier for me to grasp what is happening there. Having all the cleanup methods in this class would distract me from the higher abstraction of this publishing service. And yes: testing was a breeze :-)
created_at: 2025-03-12T06:46:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: SebastianRossa
body: @malte-laukoetter i wasn't sure why we would have the cleanup step in the"normal" PublishService. Can you please clarify? 
created_at: 2025-03-12T06:48:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,7 +43,10 @@ public enum Metadata {
     "qualifizierteMehrheit",
     true
   ),
-  ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit");
+  ORGANISATIONS_EINHEIT(Namespace.METADATEN_RIS, "./organisationsEinheit", "organisationsEinheit"),
+  ENTRY_INTO_FORCE_DATE(Namespace.METADATEN_RIS, "./entryIntoForce/@date", "entryIntoForce", true),
+  EXPIRY_DATE(Namespace.METADATEN_RIS, "./expiry/@date", "expiry", true),
path: backend/src/main/java/de/bund/digitalservice/ris/norms/domain/entity/Metadata.java
user: login: SebastianRossa
body: Thanks a lot for clarifying this. I thought the actual tag would go in here and wasn't aware this changes when isAttribute is true. 
Looking into how getTag is used I get why we have it anyways. Should we add a small comment how this works?
E.g. in the Metadata docs:  *   <li>A tag name that points to the metadata value. This can be the actual tag name or an attribute depending on where the value is stored</li>

created_at: 2025-03-12T07:03:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: SebastianRossa
body: What advantage do you see in using forEach? 
From my point of view the readability is the same while a for loop is faster (performance)
created_at: 2025-03-12T07:16:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: malte-laukoetter
body: It is also filtering out data from the xmls that we are not allowed to publish (eg. metadata that should only be available to the private portal). I would want to make sure that that definitely happens and not rely on the data in the database being already cleaned up (which might be the case i'm not 100% sure). And as that cleanup might remove different things than this new cleanup service we should call both.
created_at: 2025-03-12T08:20:24Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: malte-laukoetter
body: i created a subtask for it :)
created_at: 2025-03-12T08:25:34Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: VictorDelCampo
body: Not sure if we need to also call the cleanup of the publish service... since that clean up is bound to that job. And we have a separated clean up for the prototyp job. I think they are not related
created_at: 2025-03-12T08:30:43Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: To be honest, just readability in this case. But it is just my taste. I agree with the for loop being faster and if we don't have any need of additional functionality provided by the `forEach` (like parallel execution) we should stick to the for loop, specially if we dont have big collections, like the case for our set of `Dokument`. Let's keep then your for loop :)
created_at: 2025-03-12T08:35:14Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: malte-laukoetter
body: Both add restrictions on what data can be available to the public, the stuff from the existing publish service may never be public and the cleanup here is just the data that can not be available for the prototype. So to ensure we do not publish data that is not supposed to be public we need to run both. My idea is to move the cleanup from the publish service into it's own service and then call it here as well.
created_at: 2025-03-12T09:07:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
+      for (Node node : nodesToDelete) {
+        node.getParentNode().removeChild(node);
+      }
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten')]";
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: SebastianRossa
body: As I understand generation/ausfertigung can only happen once. Then amendment/ausfertigung can occur. A Neufassung would be generation/neufassung. 
Not sure with the generation/inkrafttreten though. That might happen twice as i see it. Once at the former version and than on Neufassung. But i can't find any example. 
created_at: 2025-03-12T09:29:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: VictorDelCampo
body: I see your reasoning and you are logically right.. I don't think it is good though to intertwine both clean-ups, since the jobs (and services including the clean-ups steps) should be independent. Also the clean-up for the prototype should take into consideration what should not be public anyway (organisationsEinheit), meaning the definition of what does not belong in the XML should already contain that. We are doing now work a devs that is not expected/specified 
created_at: 2025-03-12T09:56:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: malte-laukoetter
body: one last thought: as this method is modifying the norm in place I think it would be a bit simpler to understand if we do not return it here
created_at: 2025-03-12T09:57:15Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
+      for (Node node : nodesToDelete) {
+        node.getParentNode().removeChild(node);
+      }
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten')]";
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: So what about laws with several inkraftrete when they are announced/generated? they would have several eventRef with the combination generation/inkraftreten right?
created_at: 2025-03-12T09:59:08Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
+      for (Node node : nodesToDelete) {
+        node.getParentNode().removeChild(node);
+      }
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten')]";
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: Page 56 of LDML.de 1.7.2:

_inkrafttreten – Inkrafttreten eines Dokuments bzw. eines Teils davon oder eines auf das
Dokument anzuwendenden Änderungsbefehls._
created_at: 2025-03-12T10:00:01Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,112 @@
+package de.bund.digitalservice.ris.norms.application.service;
+
+import de.bund.digitalservice.ris.norms.domain.entity.*;
+import de.bund.digitalservice.ris.norms.utils.NodeParser;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Service responsible for cleaning up all {@link Dokument}s contained in a {@link Norm} since in the prototype
+ * not all available data can be published due to legal obligations
+ */
+@Service
+public class PrototypeCleanupService {
+
+  private static final Set<String> SHOULD_STAY = Set.of(
+    "entryIntoForce",
+    "expiry",
+    "standangabe",
+    "ausserkraft",
+    "vollzitat"
+  );
+
+  /**
+   * Cleans the metadata and lifecycle events of all documents associated with the given {@link Norm}.
+   * <p>
+   * This method iterates through each {@link Dokument} in the provided {@link Norm} and applies a series of
+   * metadata-cleaning operations. Specifically, it:
+   * <ul>
+   *   <li>Removes metadata from RIS-specific elements.</li>
+   *   <li>Deletes regular metadata.</li>
+   *   <li>Deletes metadata associated with the German federal government.</li>
+   *   <li>Removes specific notes related to amendments.</li>
+   *   <li>Modifies lifecycle events so the real date of the event is hidden.</li>
+   * </ul>
+   *
+   * @param norm The {@link Norm} containing the documents to be cleaned.
+   * @return The cleaned {@link Norm} with updated metadata and lifecycle events.
+   */
+  public Norm clean(Norm norm) {
+    Set<Dokument> dokumente = norm.getDokumente();
+    for (Dokument dokument : dokumente) {
+      cleanRisMetadata(dokument);
+      cleanRegularMetaData(dokument);
+      cleanBundesRegierungMetaData(dokument);
+      cleanNotes(dokument);
+      cleanLifecycleEvents(dokument);
+    }
+
+    return norm;
+  }
+
+  private void cleanRisMetadata(Dokument dokument) {
+    Optional<Element> dsProprietary = NodeParser.getElementFromExpression(
+      "//Q{" + Namespace.METADATEN_RIS.getNamespaceUri() + "}legalDocML.de_metadaten",
+      dokument.getDocument()
+    );
+    if (dsProprietary.isPresent()) {
+      String query = createXpathAllDsProprietaryExceptShouldStay();
+      var nodesToDelete = NodeParser.getNodesFromExpression(query, dsProprietary.get());
+      for (Node node : nodesToDelete) {
+        node.getParentNode().removeChild(node);
+      }
+    }
+  }
+
+  private void cleanRegularMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN.getNamespaceUri());
+  }
+
+  private void cleanBundesRegierungMetaData(Dokument dokument) {
+    deleteMetaData(dokument, Namespace.METADATEN_BUNDESREGIERUNG.getNamespaceUri());
+  }
+
+  private void cleanNotes(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query = "./notes/note[@refersTo=\"aenderungsfussnote\"]";
+    var nodesToDelete = NodeParser.getNodesFromExpression(query, metadataElement);
+    for (Node node : nodesToDelete) {
+      node.getParentNode().removeChild(node);
+    }
+  }
+
+  private void cleanLifecycleEvents(Dokument dokument) {
+    Element metadataElement = dokument.getMeta().getElement();
+    String query =
+      "//eventRef[not(@type='generation' and @refersTo='ausfertigung') and not(@type='generation' and @refersTo='inkrafttreten')]";
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PrototypeCleanupService.java
user: login: VictorDelCampo
body: In page 114 you can see examples of several eventRef with generation/inkraftreten, this is the case when you have split time boundaries (gespaltene Geltungszeit), meaning one law that when announced already specified different inktraftreten

created_at: 2025-03-12T10:05:05Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: malte-laukoetter
body: I already see us adjusting the cleanup for publishing and then forgetting to also adjust the prototype-publishing. As yes in the moment all the non-public fields are in the metadata sections we clean up, but this might change and we would now always need to keep in mind both places.
My understanding of the prototype publishing is that all requirements of the "normal" publishing also apply here, as it is "just" normal publishing with some **additional** restrictions on which norms to publish and what data is allowed to be included.
created_at: 2025-03-12T10:06:26Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: malte-laukoetter
body: https://github.com/digitalservicebund/ris-norms/pull/1082
created_at: 2025-03-12T11:15:23Z
author_association: MEMBER
diff_hunk: @@ -65,7 +68,7 @@ public void publishNormsToPortalPrototype() {
 
       // TODO: (Malte Laukötter, 2025-03-07) check if norm is allowed to be published
 
-      // TODO: (Malte Laukötter, 2025-03-07) clean up norm
+      prototypeCleanupService.clean(norm.get());
       // TODO: (Malte Laukötter, 2025-03-07) also run the cleanup from the normal PublishService
path: backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PortalPrototypePublishService.java
user: login: VictorDelCampo
body: But Malte.. this is once again your understanding and not a explicit requirement. We are doing now again things only on the dev side, without syncing with PM. If it is needed, let make it visible and gather first input from PM...
created_at: 2025-03-12T11:41:18Z
author_association: MEMBER

PR comments:
user: login: malte-laukoetter
created_at: 2025-03-12T09:42:12Z
body: One more thing i just remembered, I add some integration tests for the whole prototype publishing service in https://github.com/digitalservicebund/ris-norms/pull/1076/ it would be cool if you could add in a check that the published norm is cleaned up after we have merged the two PRs :)
author_association: MEMBER
user: login: sonarqubecloud[bot]
created_at: 2025-03-13T13:50:29Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=digitalservicebund_ris-norms-frontend&pullRequest=1068) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=digitalservicebund_ris-norms-frontend&pullRequest=1068&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=digitalservicebund_ris-norms-frontend&pullRequest=1068&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=digitalservicebund_ris-norms-frontend&pullRequest=1068&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=digitalservicebund_ris-norms-frontend&pullRequest=1068&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=digitalservicebund_ris-norms-frontend&pullRequest=1068&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=digitalservicebund_ris-norms-frontend&pullRequest=1068)


author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-13T13:54:11Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=digitalservicebund_ris-norms-backend&pullRequest=1068) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=digitalservicebund_ris-norms-backend&pullRequest=1068&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=digitalservicebund_ris-norms-backend&pullRequest=1068&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=digitalservicebund_ris-norms-backend&pullRequest=1068&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [98.6% Coverage on New Code](https://sonarcloud.io/component_measures?id=digitalservicebund_ris-norms-backend&pullRequest=1068&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=digitalservicebund_ris-norms-backend&pullRequest=1068&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=digitalservicebund_ris-norms-backend&pullRequest=1068)


author_association: NONE