From e620ef301fff289700541fa6097407987818fc36 Mon Sep 17 00:00:00 2001
From: Kevin Adametz
Date: Mon, 21 Sep 2026 10:40:10 +0000
Subject: [PATCH] =?UTF-8?q?web:=20Datenschutzerkl=C3=A4rung=20=E2=80=94=20?=
=?UTF-8?q?Abschnitt=205a=20=E2=80=9EEigene=20Nutzungsstatistiken=20ohne?=
=?UTF-8?q?=20Personenbezug",=20Frist=20395=20Tage=20(Roadmap=200.7)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Aufrufe/Teilen je Meldung, Abrufe durch Such-, KI- und Feed-Dienste,
Konversionsschritte: Umfang ohne IP, Zweck, Art. 6 Abs. 1 lit. f, Löschung
nach 395 Tagen in Abschnitt 13. Text vom Betreiber abgenommen (21.09.2026);
gilt für Hub und beide Portale. 0.7 in Roadmap und Protokoll abgehakt.
Co-Authored-By: Claude Fable 5.1
---
dev/2026-09-01/roadmap-2026.md | 2 +-
dev/2026-09-01/umsetzung-protokoll.md | 13 +++----
resources/views/web/datenschutz.blade.php | 41 +++++++++++++++++++++++
tests/Feature/Web/StaticPagesTest.php | 5 +++
4 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/dev/2026-09-01/roadmap-2026.md b/dev/2026-09-01/roadmap-2026.md
index 405ab74a..d1c2270e 100644
--- a/dev/2026-09-01/roadmap-2026.md
+++ b/dev/2026-09-01/roadmap-2026.md
@@ -42,7 +42,7 @@ Ohne definierte Konversionspunkte ist keiner der folgenden Blöcke bewertbar. Di
| 0.4 | Herkunftsparameter in allen Mail-Links, gespeichert **auf dem Magic-Link-Token**, nicht in der Session | S | 0.3 |
| 0.5 | Ereignisse an den bestehenden Zustandsänderungen mitschreiben | M | 0.3, 0.4 |
| 0.6 | Auswertung als Artisan-Befehl: Trichter je Quelle und Zeitraum | S | 0.5 |
-| 0.7 | Aufbewahrungsfrist für Ereignisdaten festlegen und in der Datenschutzerklärung führen | S | 0.3 |
+| ~~0.7~~ | Aufbewahrungsfrist für Ereignisdaten festlegen und in der Datenschutzerklärung führen — **395 Tage seit 01.09.2026; Datenschutz-Abschnitt 5a am 21.09.2026 eingebaut** (gilt für Aufrufe, Crawler- und Feed-Abrufe, Konversionsschritte) | S | 0.3 |
### Konversionsleiter
diff --git a/dev/2026-09-01/umsetzung-protokoll.md b/dev/2026-09-01/umsetzung-protokoll.md
index e741782e..acdd7bf5 100644
--- a/dev/2026-09-01/umsetzung-protokoll.md
+++ b/dev/2026-09-01/umsetzung-protokoll.md
@@ -2143,10 +2143,11 @@ Befunde und was daraus wurde:
**Bleibt offen, bewusst nicht aus dem Code heraus erledigt:**
-- 0.7: Absatz zur Ereignistabelle (Zweck, Umfang, 395 Tage, Rechtsgrundlage)
- in der Datenschutzerklärung — Rechtstext, Betreiber. Gilt seit dem
- 21.09.2026 ebenso für das Crawler- und das Feed-Abruf-Protokoll (beide
- ohne IP, gleiche Aufbewahrung).
+- ~~0.7: Absatz zur Ereignistabelle in der Datenschutzerklärung~~ —
+ **erledigt 21.09.2026:** Abschnitt „5a. Eigene Nutzungsstatistiken ohne
+ Personenbezug" (Aufrufe/Teilen, Abrufe durch Such-, KI- und Feed-Dienste,
+ Konversionsschritte; keine IP, lit. f) plus Frist 395 Tage in Abschnitt 13,
+ auf Hub und beiden Portalen (eine Datei). Text vom Betreiber abgenommen.
- 0.1: Kohortenwerte „28–55 Tage" vom Live-System (Fenster 01.06.–01.09.)
einmal erheben und ablegen: `php artisan press-releases:view-distribution --from=2026-06-01 --to=2026-09-01 --json > dev/2026-09-01/basiswert-0.1.json`.
- Abbruchbedingungen der Blöcke 1–3 tragen weiter Platzhalter für Zeitraum
@@ -2280,6 +2281,6 @@ Cache-Treffer, Report je Reader/Feed, Panel, Bereinigung),
**Deploy:** `migrate` (neue Tabelle, keine Änderung an `press_releases`),
`FEED_FETCHES_RECORDED_SINCE` setzen, `view:cache`/`route:cache`,
-`config:cache`. **Offen (0.7, Betreiber):** Datenschutzerklärung — derselbe
-Absatz wie für Ereignis- und Crawler-Log (Zweck, Umfang ohne IP, 395 Tage).
+`config:cache`. 0.7 (Datenschutzerklärung) ist seit dem 21.09.2026 erledigt,
+siehe oben.
diff --git a/resources/views/web/datenschutz.blade.php b/resources/views/web/datenschutz.blade.php
index 4628c19b..73b882b9 100644
--- a/resources/views/web/datenschutz.blade.php
+++ b/resources/views/web/datenschutz.blade.php
@@ -143,6 +143,46 @@
Analysedaten an externe Tracking- oder Werbedienstleister findet nicht statt.
+ {{-- Roadmap 0.7 (abgestimmt 21.09.2026): Ereignisprotokolle ohne
+ Personenbezug — press_release_events, press_release_crawler_hits,
+ feed_fetches, conversion_events. Aufbewahrung 395 Tage (Abschnitt 13). --}}
+ 5a. Eigene Nutzungsstatistiken ohne Personenbezug
+
+ Neben Umami führen wir auf unseren eigenen Servern drei einfache Ereignisprotokolle, mit
+ denen wir die Reichweite veröffentlichter Pressemitteilungen belegen und den Weg von einer
+ Benachrichtigung zum Kundenkonto nachvollziehen. Diese Protokolle enthalten keine
+ IP-Adressen, keine Cookies und keine Kennungen, die eine Person oder ein Gerät
+ wiedererkennbar machen.
+
+
+ -
+ Aufrufe und Teilen-Klicks je Pressemitteilung. Gespeichert werden die
+ Meldung, der Zeitpunkt und bei einem Teilen-Klick der gewählte Kanal. Daraus entstehen
+ die Aufrufzahlen und Tagesverläufe, die wir dem einreichenden Unternehmen zeigen.
+
+ -
+ Abrufe durch Such-, KI- und Feed-Dienste. Ruft ein bekannter Dienst eine
+ Meldung oder einen RSS-Feed ab, speichern wir den Dienst, die gekürzte Programmkennung
+ (User-Agent), den Zeitpunkt und die betroffene Meldung beziehungsweise den Feed. Nennt ein
+ Feed-Dienst in seiner Kennung eine Abonnentenzahl, übernehmen wir diese Zahl. Wer einen
+ Feed abonniert hat, erfahren wir nicht.
+
+ -
+ Schritte vom Hinweis zum Konto. Klickt ein Empfänger einen Link in einer
+ unserer Benachrichtigungen, nutzt einen Anmeldelink, bearbeitet einen Newsroom, legt ein
+ Konto an oder bucht erstmals, halten wir den Schritt, den Anlass (zum Beispiel
+ „Veröffentlichungsmail") und das betroffene Unternehmen fest. Die Person und ihre
+ E-Mail-Adresse werden dabei nicht gespeichert; die Auswertung zählt Unternehmen, nicht
+ Menschen.
+
+
+
+ Die Verarbeitung erfolgt zur Reichweitenmessung gegenüber unseren Kunden, zur Bewertung
+ unserer Benachrichtigungen und zur Verbesserung unseres Angebots. Rechtsgrundlage ist
+ Art. 6 Abs. 1 lit. f DSGVO. Die Protokolle werden nicht an Dritte weitergegeben und nicht
+ mit anderen Daten zu Nutzerprofilen verbunden.
+
+
6. Kontaktaufnahme
Wenn Sie uns per E-Mail oder über ein Formular kontaktieren, verarbeiten wir die von Ihnen
@@ -495,6 +535,7 @@
- Server-Logs werden grundsätzlich nach 14 Tagen gelöscht, sofern kein sicherheitsrelevanter Vorfall eine längere Aufbewahrung erforderlich macht.
- Magic-Link-Token verfallen nach einmaliger Nutzung oder nach Ablauf von {{ $magicLinkTtl }}.
+ - Die Ereignisprotokolle zu Aufrufen, Abrufen durch Dienste und Konversionsschritten (Abschnitt 5a) werden nach 395 Tagen gelöscht.
- Meldedaten werden grundsätzlich für drei Jahre nach Abschluss des Vorgangs gespeichert.
- Vertrags-, Buchungs- und Rechnungsdaten unterliegen handels- und steuerrechtlichen Aufbewahrungspflichten und werden nach Ablauf dieser Fristen gelöscht.
- Veröffentlichte Pressemitteilungen werden im Rahmen der Archivfunktion grundsätzlich dauerhaft gespeichert, soweit keine gesetzlichen Ansprüche auf Entfernung, Sperrung oder Änderung bestehen.
diff --git a/tests/Feature/Web/StaticPagesTest.php b/tests/Feature/Web/StaticPagesTest.php
index 40e3b34a..dbcc91ee 100644
--- a/tests/Feature/Web/StaticPagesTest.php
+++ b/tests/Feature/Web/StaticPagesTest.php
@@ -150,6 +150,10 @@ test('the privacy policy renders the real v03 content with host-specific blocks'
->assertSeeText('Hetzner Online GmbH')
->assertSeeText('Medienprivileg')
->assertSeeText('Änderungslinks für Pressekontakte')
+ // Roadmap 0.7: Ereignisprotokolle ohne Personenbezug, 395 Tage.
+ ->assertSeeText('Eigene Nutzungsstatistiken ohne Personenbezug')
+ ->assertSeeText('Feed abonniert hat, erfahren wir nicht.')
+ ->assertSeeText('werden nach 395 Tagen gelöscht')
->assertDontSeeText('Zahlungsabwicklung mit Stripe')
// Alter Platzhalter (Google Analytics gibt es nicht) ist weg.
->assertDontSeeText('Google Analytics');
@@ -158,6 +162,7 @@ test('the privacy policy renders the real v03 content with host-specific blocks'
$this->get('https://pressekonto.test/de/datenschutz')
->assertSuccessful()
->assertSeeText('Kundenkonto und Registrierung auf dem Hub')
+ ->assertSeeText('Eigene Nutzungsstatistiken ohne Personenbezug')
->assertSeeText('Zahlungsabwicklung mit Stripe')
->assertSeeText('gewerblichen oder selbständigen beruflichen Tätigkeit')
->assertDontSeeText('Medienprivileg');