1. Wie dieses Verzeichnis zu lesen ist
Dies ist ein internes Rechenschaftsdokument nach Art. 30 DSGVO. Es ist keine Datenschutzerklärung, es ist nicht als Information für Betroffene geschrieben, auch wenn es veröffentlicht ist, und es ist nicht geschrieben, um gut auszusehen. Seine einzige Aufgabe ist es, einer Aufsichtsbehörde — oder der nächsten Person, die eine Frage beantworten muss — zu zeigen, was tatsächlich verarbeitet wird, wo es liegt und wie lange es bleibt.
Drei Regeln haben die Abfassung bestimmt. Erstens: Eine Aussage steht nur dort, wo Code, Schema oder eine Messung sie trägt. Wo ein Eintrag fehlt, markiert ein Platzhalter die Lücke statt eines plausibel klingenden Satzes. Eine ehrliche Lücke übersteht eine Prüfung; eine gut formulierte Vermutung nicht. Zweitens: Wo der Code seine eigene Begründung dokumentiert, wird diese Begründung mit Datei und Zeile zitiert, damit ein späterer Leser sie nachprüfen kann, statt diesem Dokument zu vertrauen. Drittens: Die Aufbewahrung wird zweimal angegeben — einmal für die Tabellen, die der tägliche Löschlauf erfasst, einmal für die Tabellen, die er nicht erfasst. Ein Verzeichnis, das eine Löschfrist behauptet, die nur für die Hälfte der Tabellen gilt, ist schlechter als eines, das die Lücke benennt, denn genau die Lücke wird geprüft.
MESSGRUNDLAGE. Alle Messungen beziehen sich auf das ENTWICKLUNGSSYSTEM (www.mouseplayer.com, APP_ENV=dev); sie beschreiben nicht den Produktivbetrieb. Zeilenzahlen, Tabellengrößen und Konfigurationswerte ohne eigenes Datum stammen aus der Messsitzung vom 10. August 2026 und beschreiben jenen Stand; neuere Zahlen tragen ihr Datum („Stand 16.10.2026“). Datei- und Zeilenangaben ohne Datum geben ebenfalls den Stand vom 10. August 2026 wieder: Zeilennummern verschieben sich mit jeder Änderung des Codes, maßgeblich sind die genannten Dateien und Funktionen. Zahlen aus dem Produktivbetrieb: auszufüllen: dieselben Zahlen, gemessen auf dem Produktivsystem, mit dem Datum der Messung
BEWUSST WEGGELASSEN. Die zugrunde liegende Erhebung hat vier vollständige öffentliche IP-Adressen als Beleg dafür festgehalten, dass der Altbestand ungekürzt ist. Sie werden hier nicht wiedergegeben. Ein Verzeichnis von Verarbeitungstätigkeiten wird intern und an Prüfer weitergereicht; es darf nicht selbst zur zweiten Kopie der Daten werden, die es beschreibt. Der Befund steht; die Werte nicht.
2. Der Rechtsträger, und warum dieses Verzeichnis zwei Hälften hat
| Feld | Eintrag |
| Rechtsträger | LW IT Solutions Company Lukas Wójcik |
| Anschrift | al. Tadeusza Kościuszki 80/82 lok. 301, 90-437 Lodz, Polen |
| Steuerliche Kennung | NIP: PL7252266190 |
| Kontakt | office@mouseplayer.com (keine Telefonnummer veröffentlicht) |
| Produkt | MousePlayer — Session Replay, Heatmaps, Verhaltensanalyse |
| Vertreter nach Art. 27 | Entfällt. Der Rechtsträger ist in der Union (Polen) niedergelassen. |
| Datenschutzbeauftragter | Nicht benannt. Siehe Abschnitt 9 für die Bewertung nach Art. 37. |
MousePlayer nimmt gegenüber zwei verschiedenen Personengruppen zwei verschiedene Rollen ein, und wer sie vermischt, erhält ein Verzeichnis, das für beide wertlos ist. Für die Daten der BESUCHER von Kundenwebseiten ist MousePlayer Auftragsverarbeiter und der Kunde ist Verantwortlicher — es gilt Art. 30 Abs. 2. Für die Daten der eigenen KUNDEN von MousePlayer (Konten, Abrechnung, Support, Zugriffsprotokolle des Portals) ist MousePlayer Verantwortlicher — es gilt Art. 30 Abs. 1.
Das ist keine Bequemlichkeit der Abfassung. Die Unterscheidung ist im Code bereits umgesetzt und hat für jede Hälfte eine andere technische Folge: class/Server.class.php:416 sagt "REGEL B ... Hier sind wir AUFTRAGSVERARBEITER", und die Zeilen 421-425 trennen "Regel A (volle Adresse) fuer DIREKTE Zugriffe auf die eigene Anwendung" von Regel B (gekürzt) für Besucherdaten. Die IP-Adresse eines Besuchers wird in class/Server.class.php:432-435 gekürzt; die IP-Adresse eines Kundennutzers wird vollständig gespeichert. Das System verhält sich also bereits so, als gäbe es dieses Verzeichnis.
- Teil A (Abschnitt 3) — Art. 30 Abs. 2: zweiundzwanzig Verarbeitungstätigkeiten (A.1 bis A.22), die im Auftrag von Verantwortlichen ausgeführt werden.
- Teil B (Abschnitt 5) — Art. 30 Abs. 1: acht Verarbeitungstätigkeiten (B.1 bis B.8) in eigener Verantwortung von MousePlayer.
- Die Abschnitte 6 bis 8 gelten für beide Hälften: Aufbewahrung, automatisierte Entscheidungsfindung und die allgemeine Beschreibung der technischen und organisatorischen Maßnahmen.
- Abschnitt 10 führt die Lücken auf, deren Bestehen belegt ist. Ein Verzeichnis ist ein Arbeitsmittel, keine Bescheinigung.
3. Teil A — Art. 30 Abs. 2: Verarbeitungen im Auftrag von Verantwortlichen
A.0 Beteiligte
| Feld | Eintrag |
| Auftragsverarbeiter | LW IT Solutions Company Lukas Wójcik, al. Tadeusza Kościuszki 80/82 lok. 301, 90-437 Lodz, Polen. office@mouseplayer.com |
| Verantwortliche | Die Kunden, die die Websites betreiben, auf denen das MousePlayer-Tag (www/mp.js) eingebunden ist. Jeder Verantwortliche ist im System über projects.channelid gekennzeichnet; Kontaktdaten liegen in users und workspaces, Mitgliedschaft und Rolle in workspace_users. Gemessen auf dem Entwicklungssystem: 7 Projekte, 4 Kundenkonten, Rollen 4 owner / 1 admin / 1 viewer. |
| Maßgebliche Liste der Verantwortlichen | Im System geführt, hier nicht doppelt gehalten. Die Liste wird erzeugt, nicht abgeschrieben: im Administrationsbereich unter „Records of Processing (Art. 30)“ erzeugt ein Knopf sie auf Zuruf als CSV — je Workspace der Eigentümer mit Name, E-Mail, Firma, Anschrift, USt-IdNr., Tarif und den betroffenen Domains. Verantwortlich für den Abruf ist Lukas Wójcik, Inhaber; gezogen wird sie zu jeder Überprüfung dieses Verzeichnisses, also jährlich und bei jeder Änderung der Verarbeitung. Jeder Abruf steht im Änderungsprotokoll (export_controllers). Eine hier abgeschriebene Liste wäre ein zweiter Ort für dieselbe Wahrheit und veraltete mit jedem neuen Kunden, ohne dass es jemand bemerkte. (Entscheidung des Verantwortlichen, 17.08.2026) |
| Vertreter des Auftragsverarbeiters | Entfällt (in Polen niedergelassen). |
| Datenschutzbeauftragter | Nicht benannt — siehe Abschnitt 9. |
| Technische und organisatorische Maßnahmen | Abschnitt 8 gilt für jede Verarbeitung in Teil A und wird nicht je Verarbeitung wiederholt. |
A.1 Session Replay — Aufzeichnung von Verhaltensereignissen
| Feld | Eintrag |
| Herkunft der Ereignisse | Zwei Wege. (1) Browser des Besuchers über www/mp.js — dort setzt der Zustandsautomat mpEinw die Einwilligung technisch durch. mp.js überträgt über HTTPS an nginx, wo TLS endet: regulär über den WebSocket unter /mp_wss/; kommt der WebSocket nie zustande, seit dem 11.10.2026 über einen HTTP-Tunnel unter /mp_wst, an dem dieselben Prüfungen des WebSocket-Servers gelten (Einwilligung, Bot-Erkennung, Herkunft, Kontingent); große Seitenabbilder seit dem 07.10.2026 als HTTP-Upload unter /mp_dom mit signiertem, befristetem Zugang (bis zu 120 Sekunden in Redis abgelegt, dann wie ein gewöhnliches Abbild verarbeitet). Der Messpunkt /mp_wsfail zählt nur fehlgeschlagene WebSocket-Verbindungen je Projekt, Grund, Browserfamilie und Geräteart, ohne Besucherkennung; die IP-Adresse wird dort nur gehasht und höchstens eine Stunde zum Entprellen gehalten. (2) Server-seitig über www/api/capi_ingest.php aus einem System des Kunden; dieser Weg ist signaturpflichtig (HMAC-SHA256 über Zeitstempel und Rumpf, Fenster fünf Minuten) und verlangt je Übermittlung die ausdrückliche Angabe, dass eine Einwilligung vorliegt — fehlt sie, wird mit 403 abgewiesen. Technisch prüfen kann MousePlayer die Einwilligung dort nicht; der Kunde als Verantwortlicher sichert sie zu (AVV Abschnitt 2). Der Weg ist über site_settings.capi_ingest_aktiv schaltbar; er war bis zum 18.08.2026 abgeschaltet und ist seither eingeschaltet. Daneben besteht die Vorschau eines nativen App-SDK (Android) mit eigenem Annahmeweg (www/api/native_ingest.php, Tabellen mp_native_apps und mp_native_sessions); sie ist nur auf dem Entwicklungssystem vorhanden und abgeschaltet (native_preview_enabled = 0; Stand 16.10.2026 keine gespeicherte Sitzung). |
| Zweck | Aufzeichnung des Verhaltens von Besuchern auf Kundenwebseiten — Mausbewegung, Klicks, Scrollen, Taps, Tabwechsel —, damit der Kunde die Sitzung wiedergeben und auswerten kann. |
| Kategorien betroffener Personen | Besucher der Websites von MousePlayer-Kunden. |
| Kategorien personenbezogener Daten | Bewegungskoordinaten, Zeitversatz, Scrollposition, Dokumenthöhe; Ereignisart; Viewport- und Bildschirmmaße; Sitzungs- und Seitenaufruf-Kennungen. Gemessene Verteilung der Ereignisse: move 100934, mutation 66153, scroll 28214, tab_focus 6185, resize 2590, screen_info 2034, pageview 2031, click 1863, input 599, input_mode 425, k 407, tap 401. In visitor_sessions zudem: Referrer, UTM-Parameter, Klick-Kennung eines Werbenetzes samt Typ, Einstiegspfad, Herkunftskanal, In-App-Browser, Browserkennung (User-Agent), Bot-Kennzeichen samt Grund, Sitzungsgüte sowie seit dem 26.09.2026 ein Reibungswert samt Gründen (friction_score, friction_gruende). Die Ereignisverteilung oben ist am 10.08.2026 gemessen. |
| Wo gespeichert | mouse_events (event_id, pageview_id, event_type, time_offset_ms, x, y, scroll_y, scroll_x, doc_height, target_selector) — 225892 Zeilen, 322,6 MB, die größte Tabelle des Schemas. session_pageviews (pageview_id, session_id, tab_id, url, viewport_width, viewport_height, start_time, start_time_ms, end_time, page_title). visitor_sessions (session_id, channelid, screen_width, screen_height, start_time, end_time, duration_seconds, is_active, device_type). mouse_events_analytik (id, erfasst_am, pageview_id, channelid, event_type, time_offset_ms, x, y, target_selector) — 11812 Zeilen: eine schlanke Kopie der KLICK- und Kontextereignisse, aus der die Klickebene der Heatmap liest. Sie steht hier eigens, weil sie eine andere Aufbewahrung hat als mouse_events — die wandert nach 7 Tagen ins Archiv, die Kopie bleibt und trägt deshalb die Klickkarte über die ganze Historie. Aus ihr entsteht nächtlich ein Tagesaggregat, mp_hm_klick_tag mit mp_hm_ansicht_tag (seit 07.10.2026): je Tag, Adresse, Geräteart, Bildschirmklasse, Zielkennung und 8-px-Zelle nur eine Anzahl, ohne Sitzung, Besucherkennung oder Seitenansicht. Die Klickkarte nimmt es für Tage, deren Sitzungen nicht mehr vorhanden sind. Eine Löschung einzelner Sitzungen oder Personen berührt es nicht, weil sich keine Zeile einer Person zuordnen lässt. Seit Oktober 2026 zusätzlich mp_aufnahme_quittung: je eingegangener Nachricht eine Kennung und ein Status; für eine Nachricht, die sich nicht verarbeiten lässt, zusätzlich ihr Rohinhalt und der Grund. Die Zeilen werden nach 7 Tagen gelöscht (srv/db_worker.php). Zeilenzahlen in dieser Zeile ohne Datum: Stand 10.08.2026. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Einwilligung. Begründet in ai/migrations/018_consent.sql: Die Aufzeichnung ist Verhaltensbeobachtung (EG 24 DSGVO) und Zugriff auf das Endgerät (§ 25 TDDDG); sie ist einwilligungspflichtig, und berechtigtes Interesse trägt sie nicht. Alle 7 Projekte stehen auf projects.consent_mode='required'. Serverseitige Durchsetzung in class/Server.class.php:977-1004; Notaus site_settings.consent_gate_active=1. |
| Kategorien von Empfängern | (a) Der jeweilige Kunde — Workspace-Mitglieder mit der Rolle owner, admin oder viewer. (b) Jeder Inhaber eines Freigabe-Links, OHNE Anmeldung: /s/<40-Hex-Token> führt auf player.php?share=..., Tabelle session_shares. (c) Optional der Kunde über die REST-API v1 mit eigenem API-Schlüssel, nur in einem bezahlten Tarif; Stand 16.10.2026 besteht kein API-Schlüssel. (d) Optional KI-Agenten des Kunden über den MCP-Server (/mcp): lesender Zugriff mit einem Lese-Schlüssel der REST-API, je Projekt eigens freizuschalten (projects.mcp_active, Vorgabe aus); abrufbar sind Projekte, Kennzahlen, Sitzungslisten samt Wiedergabelink, einzelne Sitzungen mit Seitenansichten und Ereignissen, Seiten, Frustrationssignale und Ziele — nicht das Seitenabbild. Stand 16.10.2026 bei keinem Projekt freigeschaltet. (e) Der Kunde als Datei: CSV-Export der Sitzungsliste und der Umfrageantworten aus seiner Oberfläche, gedeckelt (csv_export_max_zeilen); jeder Export steht im Änderungsprotokoll (csv_export). |
| Drittlandübermittlung | Keine im Aufzeichnungsweg. Es wurde kein ausgehender Aufruf gefunden; die Geo-Auflösung läuft gegen lokale MaxMind-Dateien. Siehe Abschnitt 4. |
| Aufbewahrung | Tarifabhängig, durchgesetzt vom täglichen Löschlauf in srv/db_worker.php (Abschnitt 6.1) über die Löschkette mp_sitzungen_loeschen(): free 7 Tage, small 30, business 90, enterprise nach dem vereinbarten Tarif (Vorgabe 365). Sitzungen, die als automatisiert (Bot) erkannt sind, haben eigene, kürzere Fristen: ihre Aufzeichnung (Seitenabbild und Ereignisse) wird nach Ablauf von retention_bot_recording_days geleert (Frist in Tagen: 1), die Sitzungszeile samt allem, was daran hängt, nach Ablauf von retention_bot_session_days gelöscht (Frist in Tagen: 14); beide sind im Administrationsbereich einstellbar, 0 schaltet die eigene Frist ab, dann gilt die Tariffrist. Ereignisse wandern nach 7 Tagen aus mouse_events in komprimierte Archivdateien je Sitzung (srv/cron_archiv.php); sie teilen die Frist ihrer Sitzung, fallen mit ihr und sind seit dem 06.10.2026 Teil der täglichen Sicherung (Abschnitt 4). Löscht ein Kunde ein Projekt, einen Workspace oder sein Konto, oder wird eine Löschung nach IP-Adresse oder Besucher ausgelöst, wird seit dem 07.10.2026 zuerst archiviert — ausgeblendet, ohne weitere Aufzeichnung, wiederherstellbar — und nach höchstens 30 Tagen endgültig gelöscht (Abschnitt 6.2, mp_loesch_archiv). |
A.2 Aufzeichnung des Seiteninhalts — DOM-Schnappschuss und DOM-Änderungen
| Feld | Eintrag |
| Zweck | Aufzeichnung des Seiteninhalts, damit die Sitzung so wiedergegeben werden kann, wie der Besucher sie gesehen hat. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten; und mittelbar jede Person, deren Daten die Seite des Kunden selbst ausgibt — zum Beispiel eine Bestellbestätigung mit einer Anschrift. |
| Kategorien personenbezogener Daten | Das vollständige HTML der besuchten Seite einschließlich Text, Bild-URLs und Metadaten, so wie der Browser es darstellt, ohne Skripte und mit der Maskierung aus A.3. Dazu serialisierte HTML-Fragmente jeder späteren DOM-Änderung, abgelegt im Feld target_selector der mutation-Ereignisse. Seit dem 30.09.2026 zusätzlich: der Inhalt offener Shadow Roots von Webkomponenten samt ihrer Stylesheets (geschlossene Shadow Roots werden nicht aufgezeichnet); canvas-Elemente als Standbild im Abbild und bei Änderung laufend als Bild (höchstens einmal je Takt von einer Sekunde, gedeckelt je Seitenansicht; nicht in maskierten Bereichen und nicht bei canvas mit Bildern fremder Herkunft); iframes derselben Herkunft mit ihrem Inhalt und seit dem 02.10.2026 mit der Bedienung darin (Zeiger, Klicks, Eingaben, Scrollen); iframes fremder Herkunft nur als Platzhalter ohne Inhalt. |
| Wo gespeichert | session_pageviews.payload_blob (longtext), seit dem 14.08.2026 komprimiert abgelegt (Präfix MPZ1:, gzip, Base64); Stand 16.10.2026 tragen alle befüllten Zeilen dieses Format. session_pageviews.has_recording ist eine gewöhnliche Spalte, keine generierte: der Worker setzt sie beim Schreiben des Abbilds und setzt sie zurück, wenn er es leert; ebenso hat_interaktion, hat_scroll und scroll_max_y. mouse_events.target_selector bei event_type='mutation', darin auch die Inhalte von Shadow Roots, canvas und iframes; nach 7 Tagen in den Archivdateien (A.1). session_pageviews.html_path ist vorhanden, aber Stand 16.10.2026 bei keiner Zeile gesetzt. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Einwilligung, wie A.1. |
| Kategorien von Empfängern | Der Kunde über www/player.php, www/ajax_get_events.php und www/player_theatre.php. Jeder Inhaber eines Freigabe-Links. NICHT über die REST-API — www/api/v1_session_detail.php:25 hält den bewussten Ausschluss des Replay-Payloads fest. |
| Drittlandübermittlung | Keine im Aufzeichnungsweg. |
| Aufbewahrung | Wie A.1: mit der Sitzung über den täglichen Löschlauf und mp_sitzungen_loeschen(); bei als Bot erkannten Sitzungen wird das Abbild nach der Frist aus A.1 geleert (retention_bot_recording_days, Frist in Tagen: 1). Siehe Abschnitt 6. |
| Hinweis zur Reichweite der Maskierung | Die Maskierung wirkt nur INNERHALB von Bereichen, die mit data-mp-mask oder .mp-masked ausgezeichnet sind (www/mp.js:3934-3970). Alles übrige Seiten-HTML wird unverändert gespeichert. Was die Seite des Kunden selbst ausgibt, liegt damit in der Aufzeichnung, und keine Maskierungseinstellung reicht dorthin. |
A.2 ist die Verarbeitung mit der größten und am wenigsten vorhersehbaren Datenbreite im ganzen Produkt. Die Maskierung steuert, was der BESUCHER tippt; sie steuert nicht, was die SEITE des Kunden anzeigt. Gibt eine Kundenseite Gesundheits-, Finanz- oder andere Daten besonderer Kategorien am Bildschirm aus, gelangt dieser Inhalt in den Schnappschuss. Umgang: Zulässig, aber nicht empfohlen. Die Verantwortung trägt der Kunde als Verantwortlicher; MousePlayer stellt die Aufzeichnung bereit und beurteilt nicht, was die Seite anzeigt. Ausdrücklich abgeraten wird von angemeldeten Bereichen, in denen Gesundheits-, Bank- oder ähnliche Daten am Bildschirm stehen: dort hilft keine Feldmaskierung, weil sie an Eingabefeldern greift und nicht an dem, was die Seite ausgibt. (Entscheidung des Verantwortlichen, 17.08.2026) Als Onboarding-Regel und als Hinweis in der Installationsanleitung zu führen.
A.3 Aufzeichnung von Formulareingaben
| Feld | Eintrag |
| Zweck | Aufzeichnung von Formulareingaben, Zeichen für Zeichen, damit die Interaktion mit einem Formular wiedergegeben werden kann. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. |
| Kategorien personenbezogener Daten | Eingabewerte von input-, textarea- und select-Elementen — je nach Maskierungsstufe vollmaskiert, teilmaskiert oder im Klartext. Der Zustand von Checkboxen und Radiobuttons (true/false), der NIE maskiert wird (www/mp.js:4810-4811). Die von classifyFieldName() abgeleitete Feldkategorie (www/mp.js:4657-4674): email, password, phone, payment, address, name, search, coupon, quantity, other. |
| Wo gespeichert | mouse_events.target_selector bei event_type='input', Format {"t":"<data-mp-id>","v":"<Wert>"} — 599 Zeilen. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Einwilligung, wie A.1. |
| Kategorien von Empfängern | Der Kunde (Player); jeder Inhaber eines Freigabe-Links. |
| Drittlandübermittlung | Keine im Aufzeichnungsweg. |
| Aufbewahrung | Keine eigene Frist; wie A.1 mit der Sitzung (Tariffrist, bei Bots die Fristen aus A.1), nach 7 Tagen in den Archivdateien. |
| Wirksame Schutzvorkehrungen | Harter Boden für Kennwörter und Zahlungsdaten unabhängig von der Stufe (www/mp.js:4831-4837). Vollmaskierung bei Stufe 0 (www/mp.js:4818-4819). Alle 7 Projekte stehen auf projects.smart_masking=0, was trotz der Beschriftung die STRENGSTE Einstellung ist. |
| Befund im Altbestand | Am 10.08.2026 enthielten 173 Zeilen in mouse_events UNMASKIERTE Klartexteingaben aus dem Zeitraum 2026-07-21 bis 2026-07-27, darunter Personennamen; Zeilen ab jenem Tag sind maskiert. Stand 16.10.2026 steht in mouse_events keine unmaskierte Eingabe mehr (gemessen mit derselben Abfrage). Die betroffenen Zeilen wurden am 17.08.2026 gelöscht (Folgenabschätzung, R2), also vor Einführung der Archivdateien am 18.08.2026; in den Archivdateien und damit in der Sicherung, die diese seit dem 06.10.2026 enthält, können sie deshalb nicht stehen. Die verschlüsselten Kopien jener Zeit auf Google Drive wurden am 06.09.2026 gelöscht; eine noch bestehende Sicherung aus der Zeit vor dem 17.08.2026 ist nicht bekannt, ihr Fehlen ist aber nicht im Einzelnen nachgewiesen. |
A.4 Wiedererkennung des Besuchers über Sitzungen hinweg
| Feld | Eintrag |
| Zweck | Wiedererkennung eines Besuchers über Sitzungen und Seitenaufrufe hinweg. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. |
| Kategorien personenbezogener Daten | Pseudonyme Besucher-Kennung, erzeugt und gehalten im localStorage des Besuchers unter 'mp_visitor_id' (www/mp.js:5056-5059). Eine vom Kunden gesetzte Klarkennung — Login-ID oder Kundennummer — über MousePlayer.setUserId() (www/mp.js:4909-4913, localStorage 'mp_user_id') und automatisch aus dem dataLayer-Pfad 'uid' (www/mp.js:3585-3637). Spitzname und Browsername je Besucher, PROJEKTÜBERGREIFEND gehalten (UNIQUE auf visitor_id). |
| Wo gespeichert | visitor_sessions.visitor_id (varchar 64), custom_user_id (varchar 128, eigener Index idx_custom_user_id), nickname_key. visitor_nicknames (visitor_id, nickname_key, browser_name, city, created_at) — 329 Zeilen; die Spalte city ist bei allen 329 leer. consent_events.visitor_id. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Einwilligung, wie A.1. |
| Kategorien von Empfängern | Der Kunde. Über custom_user_id ist die Zusammenführung mit dem eigenen Kundenbestand des Kunden ausdrücklich vorgesehen. |
| Drittlandübermittlung | Keine im Aufzeichnungsweg. |
| Aufbewahrung | Mit der letzten Sitzung des Besuchers. mp_sitzungen_loeschen() (srv/db_worker.php) prüft nach jeder Löschung, ob dem Besucher noch eine Sitzung bleibt, und räumt den Spitznamen sonst ab; der Löschweg im Player nimmt denselben Weg. Der tägliche Tarif-Löschlauf ruft dieselbe Funktion auf — eine Waise kann damit nicht mehr entstehen. Eine eigene Frist gibt es nicht und braucht es nicht: der Eintrag lebt nie länger als die Sitzungen, die er benennt. |
A.5 Netzdaten und Grobstandort
| Feld | Eintrag |
| Zweck | Bestimmung von Netz und Grobstandort des Besuchers sowie Bestimmung der Region für die Einwilligungsprüfung. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. |
| Kategorien personenbezogener Daten | IP-Adresse (im Aufzeichnungsweg gekürzt, siehe unten), zweistelliges Länderkennzeichen, Stadt (bestimmt aus der gekürzten Adresse, nicht aus der vollen), ASN-Nummer und Provider-Name, Regionskennzeichen. |
| Wo gespeichert | visitor_sessions.ip_address (varchar 45), country, city, asn_number, asn_org, region_code. ip_lifetime_stats (ip_address, first_seen, total_conns, total_msgs, total_traffic, total_uptime_sec) — 446 Zeilen. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Einwilligung für die Aufzeichnung. Die Landesbestimmung wird bewusst serverseitig vorgenommen, damit vor Vorliegen der Einwilligung kein Dritter kontaktiert wird (class/Server.class.php:941-944). |
| Kategorien von Empfängern | Kein externer Empfänger. Die Geo-Auflösung läuft gegen LOKALE MaxMind-Dateien unter cfg/maxmind/ (GeoLite2-City und GeoLite2-ASN; gelesen in class/IP2CityLite.class.php und class/Server.class.php), die srv/geoip_update.sh regelmäßig bei MaxMind herunterlädt; dabei werden keine Besucherdaten übermittelt. Die aufgelösten Werte stehen in visitor_sessions und sind für den Kunden sichtbar wie der übrige Sitzungssatz. |
| Drittlandübermittlung | Keine. Kein ausgehender Aufruf im Aufzeichnungsweg. |
| Kürzung | Der WebSocket-Server (class/Server.class.php, Regel B) ersetzt das letzte IPv4-Oktett durch 'xxx' und die letzte IPv6-Gruppe durch ':xxxx', unmittelbar nachdem er die Adresse der Verbindung bestimmt hat (hinter nginx aus X-Forwarded-For, nur von der lokalen Gegenstelle geglaubt), und damit vor jedem Verbraucher. Die volle Adresse liegt nur flüchtig im Arbeitsspeicher des WebSocket-Servers, in Redis-Zählern mit wenigen Sekunden Ablauf und — für Adressen, die eine automatische Sperre auslösen — für die Dauer der Sperre (24 h) in Redis (mp_autoban:); die Redis-Instanz schreibt ihren Bestand zur Persistenz auf die Platte (AOF). Stand 16.10.2026 trägt keine Zeile in visitor_sessions und ip_lifetime_stats eine ungekürzte Adresse. |
| Aufbewahrung und Befund im Altbestand | 365 Tage ab first_seen für ip_lifetime_stats, durchgesetzt vom täglichen Lauf in srv/db_worker.php; der Wert steht in site_settings unter retention_ip_stats_days und ist im Administrationsbereich einstellbar. visitor_sessions fällt unter den Tarif-Löschlauf. Der Altbestand ist erledigt: am 17.08.2026 gemessen waren 267 von 267 Adressen in ip_lifetime_stats gekürzt und 881 von 901 in visitor_sessions. Die verbleibenden 20 tragen 0.0.0.0 und stammen aus den Testdaten der Formularauswertung (s_mptest_form_) — es sind keine Besucheradressen. |
A.6 Einwilligungsnachweise
| Feld | Eintrag |
| Zweck | Nachweis der Einwilligung und jeder Änderung an ihr (Art. 7 Abs. 1 DSGVO). |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. |
| Kategorien personenbezogener Daten | Zustand (GRANTED, GRANTED_LATE, withdrawn, region_exempt), Quelle, Zeitpunkt; Name und Version des CMP; SHA-256 des TC-Strings — bewusst nicht der String selbst; GPC-Signal; Regionskennzeichen; Stand der Projektkonfiguration. |
| Wo gespeichert | consent_events (id, session_id, channelid, visitor_id, consent_state, consent_source, cmp_name, cmp_version, tcf_hash, gpc_signal, region_code, consent_config_version, occurred_at, created_at) — 120 Zeilen. visitor_sessions.consent_state, consent_source, consent_ts, cmp_name, cmp_version, tcf_hash, gpc_signal, region_code, consent_config_version, recording_offset_ms. |
| Rechtsgrundlage | Nachweispflicht, begründet in ai/migrations/018_consent.sql: Die Beweislast für eine wirksame Einwilligung liegt beim Verantwortlichen, und ohne Protokoll gibt es im Streitfall nichts vorzuweisen. |
| Kategorien von Empfängern | Der Kunde. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | 730 Tage, gerechnet ab dem Widerruf. Länge und Anker stehen in site_settings (consent_evidence_days, consent_evidence_anchor) und sind im Administrationsbereich einstellbar; durchgesetzt vom täglichen Lauf in srv/db_worker.php. Bei einer Sitzungslöschung wird der Nachweis weiterhin nicht gelöscht, sondern entpersonalisiert: dass eine Entscheidung fiel, muss nachweisbar bleiben (Art. 5 Abs. 2), wer sie traf nicht. Gelöscht wird nur, was keine Sitzung mehr trägt — solange die Aufzeichnung besteht, muss ihr Nachweis bestehen, sonst stünde die Aufzeichnung ohne Erlaubnis da. |
| Datenqualität | 671 von 706 Sitzungen tragen consent_source='testdata' mit consent_ts IS NULL, gesetzt durch ai/devdata/001_altsitzungen_markieren.sql. Das sind KEINE echten Einwilligungsnachweise. Echte Nachweise: 27 (api), 5 (gcm), 2 GRANTED_LATE (api), 1 withdrawn (gcm). |
| Löschung bei Widerruf | Optional und überall abgeschaltet: projects.consent_delete_on_withdraw=0 bei allen 7 Projekten, ausgewertet in srv/db_worker.php:1067-1070. Ein Widerruf hält damit die weitere Aufzeichnung an, löscht aber nichts. |
A.7 Benutzerdefinierte Ereignisse, Frustrationssignale und JavaScript-Fehler
| Feld | Eintrag |
| Zweck | Aufzeichnung kundendefinierter Ereignisse, von Frustrationssignalen und von JavaScript-Fehlern, die auf der Seite des Kunden auftreten. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. |
| Kategorien personenbezogener Daten | Ereignisname — gemessen: dead_click 355, gtm.scrollDepth 290, rage_click 52, text_copied 26, text_selected 26, error_detected 22, consent_status 19, consented_ready 17, consented_update 8, mouse_thrashing 5, add_to_cart 3. Parameterwerte — target 407, tag 386, desc 274, count 57, length 52, snippet 22, message 22, type 19, filename 9, lineno 9, masked_area 4, price 1, currency 1, item_id 1. Zwei davon tragen mehr, als ihr Name vermuten lässt: 'snippet' bei text_copied und text_selected ist der Seitentext, den der Besucher markiert oder kopiert hat; 'filename' enthält vollständige URLs, und dort wurde eine moz-extension://-Adresse gefunden, also eine geräteabhängige Kennung einer Browser-Erweiterung. |
| Wo gespeichert | session_custom_events (event_id, session_id, pageview_id, event_name, created_at) — 823 Zeilen. session_custom_event_params (param_id, event_id, param_key, param_string_value, param_int_value, param_float_value) — 1264 Zeilen. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Einwilligung, wie A.1. |
| Kategorien von Empfängern | Der Kunde. Optional per Webhook an eine vom Kunden frei gewählte URL — siehe Abschnitt 4. |
| Drittlandübermittlung | Über den Webhook ist das Ziel unbestimmt und damit möglicherweise ein Drittland. Derzeit inaktiv: projects.webhook_active=0 und webhook_url NULL bei allen 7 Projekten. |
| Aufbewahrung | Mit der Sitzung über den täglichen Löschlauf und mp_sitzungen_loeschen() (Tariffrist, bei Bots die Fristen aus A.1); session_custom_event_params hängt per FOREIGN KEY ON DELETE CASCADE an session_custom_events. Konsolen-, Netzwerk- und Web-Vitals-Ereignisse in mouse_events wie A.1; mp_cwv fällt mit seiner Seitenansicht (stündlich bereinigt). |
| Konsolenmeldungen und Netzwerkanfragen (seit 30.09.2026) | Was die Seite in die Browserkonsole schreibt (die Stufe stellt der Betreiber ein, Vorgabe: Fehler und Warnungen) und Anfragen der Seite, die scheitern oder länger als eine eingestellte Schwelle brauchen: Methode, Adresse, Statuscode und Dauer. Nie Kopfzeilen oder Inhalt einer Anfrage oder Antwort, nie der Inhalt geloggter Objekte, nur ihre Art. Texte laufen vor dem Senden durch einen Filter (E-Mail-Adressen, IP-Adressen, lange Ziffernfolgen, Zugangstoken), Adressen verlieren die Werte von Parametern mit sensiblen Namen. Anfragen an MousePlayer selbst werden nicht erfasst. Gespeichert wie ein Mausereignis in mouse_events (event_type con bzw. net), mit derselben Aufbewahrung und Löschkette wie die Aufzeichnung (A.1); zu sehen im Player neben der Zeitleiste. |
| Lade- und Reaktionszeiten (Web Vitals, seit 02.10.2026) | Wie schnell die Seite beim Besucher lädt und reagiert, gemessen im Browser je Seitenansicht: Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift, First Contentful Paint und Time to First Byte. Dazu eine kurze Beschreibung des größten sichtbaren Elements und des Elements der langsamsten Interaktion, so wie bei einem Klick (Art, Kennung, sichtbarer Text; in maskierten Bereichen nur die Art). Keine Eingaben, keine Inhalte von Anfragen. Gespeichert wie ein Mausereignis in mouse_events (event_type cwv) und je Seitenansicht in mp_cwv, mit derselben Aufbewahrung und Löschkette wie die Aufzeichnung (A.1); zu sehen im Reiter Web Vitals und im Kopf des Players. |
A.8 Abgeleitete Merkmale und maschinell erzeugte Sitzungs-Zeitleisten
| Feld | Eintrag |
| Zweck | Ableitung von Merkmalen je Sitzung und von maschinell erzeugten Textprotokollen — Bewertung von Auffälligkeit und Aufmerksamkeit. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. |
| Kategorien personenbezogener Daten | Merkmalsvektor: Dauer, Seitenzahl, Scrolltiefe / -median / -umkehrungen, Pausen, Pfadeffizienz, Spitzengeschwindigkeit, Rage- und Dead-Clicks, Taps, Zoom, Herkunft und Kampagne, Verweildauer je Elementrolle (role_dwell_json), Tabverhalten. Bewertungen: engagement_score (0-255), session_quality, is_bot. Eine Fließtext-Zeitleiste der Sitzung — Stichprobe: 't=0.0 landing / src=(direct) kanal=direct attr=direct mode=unknown motion=unavailable viewport=1699x935 / t=2.0 session ende'. |
| Wo gespeichert | ai_session_features — 4043 Zeilen (eine Zeile je Sitzung UND builder_version, eine Sitzung erscheint also einmal je Version). ai_timelines (timeline_id, session_id, channelid, builder_version, input_mode, line_count, char_count, pageviews, duration_s, text als mediumtext, built_at) — 3203 Zeilen, 5,5 MB. mp_session_ziel (channelid, session_id, goal_id, tag, ziel_fp, gebaut_am) — 628 Zeilen: welche Sitzung welches Ziel erreicht hat, einmal gerechnet statt bei jedem Aufruf. ziel_fp ist der Fingerabdruck der Zielregel; ändert der Verantwortliche sie, wird die Zuordnung neu gebaut statt stillschweigend weiterverwendet. mp_hm_tag (channelid, tag, url_md5, url, titel, ansichten, engagiert) und mp_hm_tag_stand (channelid, tag, berechnet_am), seit dem 24.09.2026 (Migration 148): je Projekt, Tag und Seitenadresse die Zahl der Seitenaufrufe und der engagierten Seitenaufrufe, aus denen die Liste der Seiten-Heatmaps gespeist wird. Nur Zähler und Adressen — keine Besucher- oder Sitzungskennung; die Zahl der Besucher je Adresse wird weiterhin aus den Sitzungen selbst gezählt. |
| Rechtsgrundlage | Im Code nicht ausgewiesen. Abgeleitet aus der Aufzeichnung und damit mittelbar von der dafür eingeholten Einwilligung getragen. Weisung: Sie entsteht mit der Registrierung des Kunden und wird ausgeführt, sobald er das Skript auf seiner Seite einbaut und Besucher aufgezeichnet werden (Ansage des Verantwortlichen, 17.08.2026). Die Ableitung von Merkmalen, Zeitleisten und Wertstufen ist Teil der beauftragten Leistung. Zwei Teile werden dabei unterschieden. Die Wertstufen stellt der Kunde selbst am Projekt ein; jede Änderung wird protokolliert (log_audit, save_wertregeln). Die vom Sprachmodell erzeugten Zusammenfassungen liefen bis zum 17.08.2026 allein über eine globale Einstellung im Administrationsbereich — der Kunde hatte darauf keinen Einfluss, und damit beruhten sie nicht auf seiner Weisung. Seit Migration 041 entscheidet zusätzlich projects.ki_texte_aktiv, voreingestellt eingeschaltet; der Kunde kann sie im Einstellungen-Reiter jederzeit abschalten, und jede Änderung steht als ki_texte_changed im Änderungsprotokoll. Der Schalter ist dabei nicht die Weisung, sondern das Mittel, sie zu begrenzen: voreingestellt eingeschaltet heißt, dass der Kunde nicht eingeschaltet, sondern nur nicht ausgeschaltet hat. |
| Kategorien von Empfängern | Der Kunde (cfg/project_ai_overview.php). |
| Drittlandübermittlung | Keine. Die erzeugten Sätze formuliert das Sprachmodell auf eigener Hardware in Łódź (Abschnitt 4); an einen externen KI-Dienst geht nichts. |
| Aufbewahrung | Mit der Sitzung. ai_session_features und ai_timelines stehen seit dem 12.08.2026 in mp_sitzungen_loeschen() (srv/db_worker.php) und werden damit sowohl bei ausdrücklicher Löschung als auch vom täglichen Tarif-Löschlauf mitgenommen. An dieser Stelle stand zuvor das Gegenteil; das war der Stand vor jenem Umbau. Für die daraus gebildete Bewertung je Besucher und Tag (ai_visitor_value) und die erzeugten Texte (ai_insights) gilt zusätzlich eine eigene Frist, siehe Abschnitt 6.2. |
A.9 Zusammenarbeit am Replay — Kommentare und Freigabe-Links
| Feld | Eintrag |
| Zweck | Kommentierung eines Replays an einer Zeitmarke und Teilen eines Replays per Link. |
| Kategorien betroffener Personen | Kundennutzer (die Verfasser) und mittelbar die aufgezeichneten Besucher. |
| Kategorien personenbezogener Daten | Kommentartext (bis 2000 Zeichen), Zeitversatz, Verfasser. Freigabe-Token (40 Hex-Zeichen), Ersteller, Ablauf, Widerruf, Zugriffszahl, letzter Zugriff. |
| Wo gespeichert | session_comments (comment_id, channelid, session_id, user_id, time_offset_ms, body, created_at, updated_at) — 12 Zeilen. session_shares (share_id, channelid, session_id, token, created_by, expires_at, revoked_at, last_seen, view_count, created_at) — 9 Zeilen. |
| Rechtsgrundlage | Im Code nicht ausgewiesen. Weisung: Der Kunde erlaubt das Teilen ausdrücklich, auch außerhalb seiner eigenen Organisation, und trägt dafür die Verantwortung (Entscheidung des Verantwortlichen, 17.08.2026). Dokumentiert ist die Weisung durch die Handlung selbst: den Link erzeugt ein berechtigtes Mitglied des Kunden-Workspace, und die Erzeugung wird protokolliert (log_audit, Aktion create_share; die Rücknahme als revoke_share). MousePlayer stellt die Funktion bereit; die Auswahl der Empfänger und die Rechtmäßigkeit der Weitergabe liegen beim Kunden. Technisch begrenzt: jeder Link läuft ab — voreingestellt 7 Tage, höchstens 90 — und lässt sich jederzeit zurücknehmen. |
| Kategorien von Empfängern | Jeder Inhaber eines Freigabe-Links, OHNE Anmeldung (www/.htaccess:77). Erfundene, abgelaufene und zurückgenommene Token liefern dieselbe Antwort; aus Token lässt sich damit nichts ablesen. |
| Drittlandübermittlung | Bauartbedingt unbestimmt — ein Link lässt sich überallhin weiterreichen. Das ist eine Eigenschaft der Funktion, kein Vorfall. |
| Aufbewahrung | Mit der Sitzung: session_comments und session_shares stehen seit dem 12.08.2026 in mp_sitzungen_loeschen() und werden mit der Sitzung gelöscht. Freigabe-Links haben davon unabhängig eine eigene Höchstlebensdauer: session_shares.expires_at ist NOT NULL, mp_share_erstellen() (cfg/lib.php) setzt voreingestellt 7 Tage und begrenzt auf höchstens 90. Einen unbefristeten Link kann die Anwendung nicht erzeugen. Ist ein Link abgelaufen oder zurückgenommen, löscht der tägliche Lauf seine Zeile 90 Tage danach; die Abrufe in share_views fallen über den Fremdschlüssel mit (B.6). |
A.10 Live-Mitschau — Zusehen bei einer laufenden Sitzung
| Feld | Eintrag |
| Zweck | Beobachtung einer laufenden Sitzung in Echtzeit: Live-Liste der anwesenden Besucher, Follow-Modus mit gespiegeltem Seitenabbild, übertragener Zeigerposition und seit dem 16.08.2026 nachgebautem Überfahr-Zustand (:hover). |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten (beobachtet), Kundennutzer (beobachtend). |
| Kategorien personenbezogener Daten | Dieselben Kategorien wie A.1 und A.2 — Zeiger- und Scrollpositionen, Klicks, Eingabeereignisse, Seitenabbild und dessen Änderungen —, hier jedoch im Augenblick ihres Entstehens. Dazu die Sitzungskennung, damit der Beobachter der richtigen Sitzung folgt. |
| Wo gespeichert | Nicht gespeichert. Der Strom läuft über den WebSocket-Server (class/Server.class.php) und wird prozessintern an die verbundenen Beobachter weitergegeben. Das Zugangsmerkmal liegt in der Datenbanktabelle live_tokens (Kennung, Projekt, Nutzerkennung, gegebenenfalls die verfolgte Sitzung, Zeitpunkt der letzten Bestätigung). Seit dem 17.09.2026 hängt sich auch der Player einer laufenden Sitzung mit einem eigenen Zugang an diesen Strom (Kennung mit dem Präfix pl_, an die verfolgte Sitzung gebunden), um ihre Ereignisse ohne Verzögerung anzuzeigen. Die Aufzeichnung derselben Sitzung entsteht davon unabhängig über A.1 und A.2. |
| Rechtsgrundlage | Weisung: Die Beobachtung löst ein berechtigtes Mitglied des Kunden-Workspace selbst aus; der Zugang läuft über ein befristetes Merkmal in live_tokens, das an seine Nutzerkennung gebunden ist. Der Endnutzer wird im Augenblick des Zusehens nicht gesondert unterrichtet (Entscheidung des Verantwortlichen, 17.08.2026). Die Unterrichtung erfolgt vorab: über die Einwilligung, die jeder Aufzeichnung vorausgeht, und über die Datenschutzerklärung, die seit dem 17.08.2026 ausdrücklich nennt, dass eine laufende Sitzung in Echtzeit mitverfolgt werden kann. Bis dahin nannte sie die Live-Ansicht nur als Merkmal in einer Aufzählung — die Entscheidung stützte sich also auf einen Satz, den es noch nicht gab. |
| Kategorien von Empfängern | Der Kunde, beschränkt auf berechtigte Mitglieder des Workspace. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | Der Strom selbst wird nicht gespeichert. Eine Zeile in live_tokens entfernt der WebSocket-Server nach Ende der Ansicht, mit einer kurzen Frist für ein Neuladen; ein Zugang, der nicht mehr bestätigt wird, verliert nach kurzer Zeit seine Wirkung und wird später abgeräumt. |
Dieser Eintrag stand bis zum 17.08.2026 nicht im Verzeichnis. Er ist von A.1 und A.2 zu trennen, obwohl dieselben Daten fließen: dort werden sie später abgespielt, hier sieht ein Mensch in dem Augenblick zu, in dem der Besucher handelt. Genau diese Gleichzeitigkeit ist das Merkmal, an dem Art. 35 Abs. 3 die systematische Überwachung festmacht, und die Folgenabschätzung stützt ihre eigene Erforderlichkeit darauf.
A.11 Zustellprotokoll der Integrationen
| Feld | Eintrag |
| Zweck | Nachweis und Fehlersuche für die unter 4.1 genannten Übermittlungen. Ohne ihn ist für den Verantwortlichen nicht erkennbar, ob eine Brücke arbeitet — ein Fehlschlag wäre von seiner Seite stumm. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, soweit der Verantwortliche für sie eine eigene Kundenkennung gesetzt hat. Ohne gesetzte Kennung enthält der Eintrag keinen Personenbezug. |
| Kategorien personenbezogener Daten | Zeitpunkt, Art der Brücke, ein Bezeichner (die vom Verantwortlichen per setUserId gelieferte Kundenkennung, das Werbenetz oder der Ereignisname), Erfolg oder Fehlschlag, Dauer in Millisekunden, Versuchszahl und der Antwort- beziehungsweise Fehlertext des Empfängers. Dieser Text kann eine Datensatzkennung des Fremdsystems enthalten. Keine Verhaltensdaten, kein Seiteninhalt, keine IP-Adresse. |
| Wo gespeichert | Redis, Schlüssel mp_webhook_log:<channelid>. Je Projekt die letzten 25 Einträge; ältere fallen durch lTrim heraus. Nicht in der Datenbank und damit auch nicht in der täglichen Sicherung. |
| Rechtsgrundlage (vom Verantwortlichen bestimmt) | Wie A.1. Der Eintrag entsteht ausschließlich, wenn der Verantwortliche eine Brücke eingeschaltet hat — er ist die Aufzeichnung der Ausführung seiner eigenen Weisung. |
| Kategorien von Empfängern | Der Verantwortliche, über die Projekteinstellungen (Reiter Integrationen). Keine Weitergabe an Dritte. |
| Drittlandübermittlung | Keine. Der Eintrag verlässt den eigenen Server nicht. |
| Aufbewahrung | 30 Tage. Gesetzt als Ablaufzeit in Redis beim Schreiben; zusätzlich begrenzt auf 25 Einträge je Projekt. Läuft von selbst ab und braucht keinen Löschlauf. Die Zahl steht in site_settings.retention_intlog_days und ist im Administrationsbereich einstellbar. |
A.12 Verhaltensprofile — automatisierte Gruppierung der Besuche
| Feld | Eintrag |
| Zweck | Automatisierte Gruppierung der aufgezeichneten BESUCHE nach ihrem Verlauf, damit der Verantwortliche nicht Sitzung für Sitzung durchsieht, sondern Gruppen erkennt — und je Gruppe einen typischen Besuch abspielen kann. Daneben wiederkehrende Abfolgen von Seiten und Ereignissen innerhalb des Rechenfensters. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten. Gruppiert werden BESUCHE, nicht Menschen: derselbe Mensch mit zwei Besuchen kann in zwei Gruppen fallen, und die Oberfläche ist so formuliert. Ein Profil je PERSON wird nicht gerechnet — es setzt die über setUserId gelieferte Kundenkennung voraus, und 0 von 4226 Sitzungen tragen eine (gemessen 27.08.2026). |
| Kategorien personenbezogener Daten | Keine neuen Kategorien. Der Merkmalsvektor aus A.8, eingeengt auf die sieben Merkmale mit einem Füllgrad über 90 %: Dauer, Seitenzahl, Aufmerksamkeitsbewertung, Pausen, Wutklicks, tote Klicks, Tabwechsel. Daraus abgeleitet: zu welcher Gruppe eine Sitzung gehört und ihr Abstand zum Gruppenzentrum. Je Gruppe zusätzlich die Sitzungskennung des typischsten und des untypischsten Besuchs, damit beide abspielbar sind. Bei den Abfolgen die Musterkette aus Pfaden und Ereignisnamen sowie bis zu drei Sitzungskennungen als Beispiel. Kein Seiteninhalt, keine IP-Adresse, keine Formulareingabe. |
| Wo gespeichert | mp_profile — eine Zeile je Kanal und Gruppe (Größe, Anteil, Zentrum, Kennzahlen, gerechneter Name, selbst vergebener Name, Vertreter, Ausreißer); 15 Zeilen. mp_profil_sitzung — Sitzung auf Gruppe samt Abstand; 4226 Zeilen. mp_sequenzmuster — Kette, Support, Lift, bis zu drei Beispiele; 115 Zeilen. Alle drei sind ABLEITUNGEN: sie dürfen jederzeit verloren gehen und neu gerechnet werden und enthalten kein Rohdatum, das nicht auch anderswo liegt. Seit dem 06.09.2026 trägt mp_profil_sitzung zusätzlich den Personenschlüssel (person_key, Migration 112): eine Kopie des Schlüssels aus A.4 (Kundenkennung, ersatzweise Besucherkennung), die der Profillauf täglich nachzieht; daraus wird die Liste der wiederkehrenden Besucher gerechnet. Zeilenzahlen in dieser Zeile: Stand 27.08.2026. |
| Rechtsgrundlage | Wie A.8. Abgeleitet aus der Aufzeichnung und damit mittelbar von der dafür eingeholten Einwilligung getragen. Weisung: Teil der beauftragten Leistung; sie entsteht mit der Registrierung des Kunden und wird ausgeführt, sobald Besucher aufgezeichnet werden. Zwei Grenzen sind es wert, benannt zu werden. Die Gruppierung wird GERECHNET, nicht erzeugt: zu welcher Gruppe ein Besuch gehört, entscheidet k-Means über die sieben Merkmale in ai/profile.py, und die Gruppennamen entstehen aus der relativen Lage des Zentrums, nicht aus einem Text. Wo ein Sprachmodell doch einen Satz über eine Gruppe schreibt, bekommt es ausschließlich die GRUPPENzahlen — Prozentwerte und Mittelwerte —, nie eine Sitzungs- oder Besucherkennung, und derselbe Wächter wie in A.8 lehnt jede Zahl ab, die nicht unter diesen Zahlen vorkommt. Es gibt allerdings keinen Schalter je Projekt: profile_aktiv ist eine globale Einstellung des Betreibers, und die projektweise Auswahl der KI-Abschnitte (projects.ki_module) deckt diesen Reiter nicht ab. Als Lücke in Abschnitt 10 vermerkt. |
| Kategorien von Empfängern | Der Kunde, über den Reiter Verhaltensprofile (cfg/project_profiles.php). Keine Weitergabe an Dritte: die Gruppenzugehörigkeit geht in keine der Brücken aus 4.1. Geprüft durch eine Suche nach profil_key über cfg/, srv/, www/ und class/ — sie kommt nur im Leseweg und im Player vor, weder in www/mp.js noch in class/Server.class.php, erreicht also auch den Browser des Besuchers nicht. |
| Drittlandübermittlung | Keine. Gerechnet wird auf derselben Maschine (ai/profile.py, gestartet von srv/ai_worker.php). Den freiwilligen Satz je Gruppe formuliert das Sprachmodell auf einem eigenen Rechner mit Grafikkarte im selben lokalen Netz (siehe Abschnitt 4), der dafür nur die Gruppenzahlen über HTTPS abholt. An einen externen KI-Dienst geht nichts. |
| Aufbewahrung | Mit der Sitzung: mp_profil_sitzung steht in mp_sitzungen_loeschen(). Darüber hinaus 180 Tage, verankert am BEGINN DER SITZUNG und nicht am Zeitpunkt der Berechnung — den setzt der Tageslauf jedes Mal neu, eine daran hängende Frist wäre nie abgelaufen, und es wäre niemandem aufgefallen. Zeilen, deren Sitzung es nicht mehr gibt, fallen ganz ohne Frist, denn jede Frist skaliert über eine Zeile, die es nicht mehr gibt. Die Zahl steht in site_settings.retention_profile_days, ist im Administrationsbereich einstellbar und wird auf mindestens das Rechenfenster angehoben, damit der Löschlauf nicht wegräumt, was der Profillauf am selben Tag geschrieben hat. mp_profile fällt, sobald ihm keine Zuordnung mehr bleibt, und zwar in derselben Nacht — deshalb steht diese Anweisung hinter den beiden darüber. mp_sequenzmuster fällt nach 180 Tagen ohne Nachrechnung und sofort, sobald sein Kanal gar keine Sitzung mehr hat. Dort IST der Anker der Zeitpunkt der Berechnung, und das ist richtig so: anders als eine Zuordnung beschreibt ein Muster das AKTUELLE Fenster und wird je Kanal vollständig neu geschrieben, ein frischer Zeitstempel heißt dort also wirklich „beschreibt heutige Daten“. |
A.13 Eigener Name für einen Besucher — vom Verantwortlichen vergeben
| Feld | Eintrag |
| Zweck | Der Verantwortliche gibt einem einzelnen Besucher einen eigenen Namen, um ihn in Listen und Aufzeichnungen wiederzuerkennen. Der Name ersetzt den erzeugten Spitznamen aus A.4 überall dort, wo dieser sonst stünde. Anlass ist der Supportfall: „das ist der Kunde, der angerufen hat“. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten — und zwar einzelne, vom Verantwortlichen ausgewählte. Anders als A.1 bis A.12 entsteht diese Verarbeitung nicht von selbst, sobald jemand die Seite aufruft, sondern ausschließlich durch eine bewusste Eingabe. Ohne diese Eingabe gibt es keine Zeile: am 28.08.2026 tragen 0 von 3830 Besuchern einen eigenen Namen. |
| Kategorien personenbezogener Daten | Ein FREITEXT von höchstens 64 Zeichen, dazu Zeitpunkt und Benutzerkonto der Vergabe. Der Bezug ist die Besucherkennung aus A.4. Der Inhalt wird weder vorgegeben noch geprüft — er kann eine Vertragsnummer sein, ein Spitzname oder ein Klarname samt Abteilung. Damit unterscheidet sich diese Verarbeitung von allen übrigen in Teil A: dort stammen die Daten vom Besucher oder werden aus seinem Verhalten gerechnet, hier gibt sie der Verantwortliche ein. Als Lücke in Abschnitt 10 vermerkt. |
| Wo gespeichert | visitor_nicknames.custom_label, label_set_at, label_set_by (Migration 093) — dieselbe Zeile, die schon den erzeugten Spitznamen trägt, eine je Besucher, 3830 Zeilen. Bewusst keine eigene Tabelle: der Name ersetzt genau den Spitznamen, der dort steht, hängt am selben Schlüssel und fällt damit ohne Zutun mit ihm. Eine eigene Tabelle wäre ein fünfter Ort in der Löschkette, den man vergessen kann. |
| Rechtsgrundlage | Weisung des Verantwortlichen (Art. 28 Abs. 3 Buchstabe a), erteilt durch die Eingabe selbst — es gibt keinen Lauf und keine Voreinstellung, die einen Namen erzeugt. Ob für den eingegebenen Inhalt eine Rechtsgrundlage besteht, kann MousePlayer nicht beurteilen: der Verantwortliche wählt den Text und kennt den Zusammenhang, aus dem er ihn nimmt. Der Hinweis im Eingabefeld nennt deshalb den Zweck („nur Ihr Team sieht diesen Namen“) und nicht bloß das Feld. |
| Kategorien von Empfängern | Der Kunde, in seinen eigenen Listen und im Player. Keine Weitergabe an Dritte: das Feld geht in keine der Brücken aus 4.1 — geprüft durch eine Suche nach custom_label über cfg/, srv/, www/ und class/; es kommt weder in www/mp.js noch in class/Server.class.php vor, erreicht also auch den Browser des Besuchers nicht. Der Freigabe-Link (B.6) zeigt ihn ausdrücklich NICHT, sondern den erzeugten Spitznamen: wer einen Link ohne Anmeldung weitergibt, teilt eine Aufzeichnung und nicht die Identität dahinter. Dieselbe Überlegung wie in www/selbstauskunft.php. |
| Drittlandübermittlung | Keine. Das Feld verlässt die Datenbank nur in die Oberfläche des angemeldeten Kunden. |
| Aufbewahrung | Mit der letzten Sitzung des Besuchers, wie die Zeile, in der er steht: mp_sitzungen_loeschen() entfernt sie, sobald zu dieser Besucherkennung keine Sitzung mehr existiert — auf beiden Wegen, dem täglichen Löschlauf und der Kontolöschung. Keine eigene kalendarische Frist, und das ist Absicht: eine Frist auf den Namen hieße, ihn zu löschen, während der Besucher noch da ist und weiter aufgezeichnet wird. Der Verantwortliche kann ihn jederzeit selbst entfernen; ein leeres Feld löscht ihn, und danach gilt wieder der erzeugte Spitzname. |
A.14 Import aus Google Analytics 4 — Zahlen und Sitzungen aus dem Konto des Verantwortlichen
| Feld | Eintrag |
| Zweck | Der Verantwortliche lässt Daten aus seinem eigenen Google-Analytics-4-Konto nach MousePlayer holen. Zwei getrennt einschaltbare Wege: Die Data API liefert reine Tagessummen und beantwortet damit die Deckungsfrage — GA4 zählt für einen Tag 3.000 Sitzungen, MousePlayer hat 40 aufgezeichnet, und ohne die Bezugsgröße lässt sich dieser Unterschied weder erklären noch überhaupt bemerken. Der BigQuery-Import liest den Rohdatenexport der Property und legt einzelne GA4-Sitzungen samt ihrer Ereignisse ab, damit sichtbar wird, was in einem Besuch geschah, den MousePlayer nicht aufzeichnen konnte. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten — dieselben Menschen wie in A.1, nur von einem zweiten Messsystem beobachtet. Der Unterschied zu A.1 bis A.13 liegt in der Herkunft: Diese Daten sind nicht hier erhoben worden, sondern liegen bereits im Google-Konto des Verantwortlichen, und MousePlayer holt sie ab. Der Data-API-Weg betrifft überdies gar keine einzelne Person; er liefert ausschließlich Tagessummen. |
| Kategorien personenbezogener Daten | Für den Data-API-Weg: keine — je Tag vier Zahlen (Sitzungen, Nutzer, Seitenaufrufe, aktive Sitzungen) ohne jeden Personenbezug. Für den BigQuery-Weg je GA4-Sitzung: die Pseudonymkennung user_pseudo_id, also die client_id aus dem _ga-Cookie; Beginn, Ende und Dauer; die Zahl der Ereignisse und der Seitenaufrufe; der Einstiegspfad; Gerätekategorie und Land; sowie Quelle, Medium und Kampagne. Dazu je Ereignisname ein Zähler, der letzte Zeitpunkt und, falls GA4 einen meldet, eine Wertsumme. Keine IP-Adresse, kein Seitenabbild, keine Mausbewegung — GA4 führt nichts davon, und es wird nichts davon erzeugt. Eine importierte Sitzung lässt sich deshalb nie abspielen. |
| Wo gespeichert | ga4_daily, ga4_sessions und ga4_events (Migration 097) — drei EIGENE Tabellen. Ausdrücklich nicht in visitor_sessions, session_pageviews oder session_custom_events. Der Grund ist keine Ordnungsliebe: Diese drei Tabellen führen keine Spalte, die sagt, woher eine Zeile stammt — alles darin ist hier gemessen worden. Eine importierte Zeile wäre von einer gemessenen nicht zu unterscheiden, und damit änderte sich stillschweigend die Bedeutung jeder daraus abgeleiteten Zahl: der Verhaltensprofile aus A.12, der Bewertung je Besucher, der Frustrationsauswertung. Der Import steht deshalb neben den Messdaten, so wie es ai_visitor_value und mp_profile schon tun. |
| Rechtsgrundlage | Weisung des Verantwortlichen (Art. 28 Abs. 3 Buchstabe a), erteilt durch das Einschalten des jeweiligen Weges und das Hinterlegen eines eigenen Dienstkontos. Für die ursprüngliche Erhebung bei Google ist der Verantwortliche zuständig, nicht MousePlayer: Sie ist geschehen, bevor hier irgendetwas abgerufen wird, und lässt sich nachträglich nicht prüfen. Ein technischer Riegel besteht dennoch — importiert wird nur, was eine user_pseudo_id trägt. Bei abgelehnter Einwilligung schickt GA4 im Consent Mode cookielose Treffer, und die tragen keine; sie fallen mechanisch heraus, nicht aufgrund einer Zusicherung. Das ist ein Indiz und kein Nachweis, und genau so steht es als Lücke in Abschnitt 10. |
| Kategorien von Empfängern | Keine neuen. Der Weg ist HOLEND und nicht zustellend: Es verlässt kein Datum eines Besuchers das Haus. Empfänger ist der Kunde in seiner eigenen Oberfläche. Google steht hier nicht als Empfänger, sondern als QUELLE — und zwar aus einem Konto, das der Verantwortliche selbst führt und dessen Inhalt er selbst bestimmt. |
| Drittlandübermittlung | Keine Übermittlung von Besucherdaten. Der Abruf richtet sich an analyticsdata.googleapis.com und an BigQuery; übermittelt werden dabei die Anmeldung des Dienstkontos und der Abfragetext, nicht Daten von Besuchern. Die Daten fließen in die Gegenrichtung. Wo die GA4-Daten bei Google liegen und unter welchen Garantien, richtet sich nach dem Konto des Verantwortlichen und ist Gegenstand seines Vertrages mit Google — nicht dieses Verzeichnisses. |
| Aufbewahrung | 180 Tage, verankert an dem Tag, den die Zeile BESCHREIBT (ga4_daily.tag, ga4_sessions.start_time) und nicht an ihrem Importzeitpunkt. Der wird bei jedem Lauf nachgeführt, weil GA4 bis zu 48 Stunden nachschreibt und dieselben Tage deshalb erneut geholt werden; eine daran hängende Frist liefe nie ab. Durchgesetzt vom täglichen Lauf in srv/db_worker.php, Ereignisse vor ihren Sitzungen. Ein Verlangen nach Art. 17 nimmt sie seit dem 01.09.2026 mit, soweit sich die Zeile über die Kundenkennung zuordnen lässt; der Tarif-Löschlauf dagegen NICHT — GA4-Daten haben ihre eigene Uhr, und ein Kunde im freien Tarif verlöre sie sonst nach 7 statt nach 180 Tagen. Mit dem Projekt gehen sie in jedem Fall, dort auch die Zeilen, die nie zu einer unserer Sitzungen gehört haben. Was davon nicht erreicht wird, steht in Abschnitt 10. |
A.15 Absprungvorhersage und Ausspielung eines Angebots
| Feld | Eintrag |
| Zweck | Aus den ersten Sekunden eines Besuchs schätzen, wie wahrscheinlich es ist, dass der Besucher die Seite bald ohne eine zweite Ansicht verlässt. Der Verantwortliche kann daran ein Angebot knüpfen, das dem Besucher auf SEINER Website eingeblendet wird. Anders als A.8 bis A.14 endet diese Verarbeitung damit nicht in einer Auswertung für den Kunden, sondern wirkt auf den Besucher zurück — deshalb steht sie als eigener Eintrag und nicht als Unterpunkt von A.8. Daneben kann sich der Verantwortliche Text und Gestaltung eines solchen Angebots vorschlagen lassen: ein Sprachmodell entwirft sie aus dem Kontext seiner Website. Ein Vorschlag geht nie von selbst live; übernommen wird er nur Teil für Teil durch den Verantwortlichen. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, und zwar nur beim ERSTEN Seitenaufruf einer Sitzung: eine spätere Ansicht ist kein Eintreten mehr und wird nicht bewertet. Ohne Einwilligung läuft nichts davon — die Bewertung sitzt hinter demselben Riegel wie die Aufzeichnung. |
| Kategorien personenbezogener Daten | Sechzehn gemessene Merkmale des laufenden Besuchs, alle im Browser gebildet: Gerät (mobil ja/nein), Wiederkehrer, bezahlter Klick, Suchmaschine, soziales Netz, Einstieg auf der Startseite, Pfadtiefe der Einstiegsseite, Nachtstunde, Zahl der Mausbewegungen, Scroll- und Klickereignisse im Fenster, die Sekunden bis zur ersten Eingabe, die tiefste Scrollposition in Prozent der Seite, die Zahl der Scrollumkehrungen, ob der Tab den Fokus verlor und ob es gar keine Eingabe gab. Daraus entsteht EIN Prozentwert und bis zu drei Klartextgründe. Keine Inhalte, keine Koordinaten, keine Feldwerte. Der Merker mp_seen_before im lokalen Speicher des Browsers hält fest, dass der Besucher schon einmal da war; mp_offer_<Datum> zählt, wie oft ihm heute ein Angebot gezeigt wurde. Für den Angebotsvorschlag kommen keine Angaben über einzelne Besucher hinzu, sondern Angaben über die Website: Titel, Beschreibung, Überschriften und Navigation aus höchstens zehn Seitenabbildern, die höchstens 40 Adressen, die menschliche Besucher in 30 Tagen mindestens fünfmal aufgerufen haben, der Anteil der Seitensprachen und die im Browser gemessenen Farben, Eckenrundung und Schrift von Seitengrund und häufigstem Knopf. Die Sprache wird dafür je Seitenansicht festgehalten (das lang-Attribut der Seite). Adressen und Überschriften können enthalten, was die Website selbst ausgibt (siehe A.17). |
| Wo gespeichert | Das MODELL in projects.exit_modell (Migration 100) — Gewichte, Mittelwerte, Streuungen, Güte und Trainingszeitpunkt; es enthält keine personenbezogenen Daten, sondern nur Zahlen über die Gesamtheit. Das ERGEBNIS je Besuch als Ereignis in session_custom_events: exit_risk mit dem Prozentwert und den Gründen, dazu exit_offer_shown, exit_offer_click und exit_offer_dismiss, wenn ein Angebot gezeigt wurde. Der jeweils letzte Wert steht zusätzlich flüchtig im Verbindungsdatensatz des WebSocket-Servers (Redis, mp_websockets), damit die Live-Ansicht ihn zeigen kann; er verschwindet mit der Verbindung. Der Angebotsvorschlag steht in projects.exit_offer_vorschlag (Migration 114), die Gestaltungsmessungen als die letzten 60 je Kanal in Redis (mp_design:<Kanal>), die Seitensprache in session_pageviews.lang. Für die Formulierung geht der Kontext durch ai_ki_queue zu den eigenen Rechnern, auf denen das Sprachmodell läuft (Abschnitt 4). |
| Rechtsgrundlage | Weisung des Verantwortlichen. Trainiert wird je Projekt und nur auf dessen eigenen Sitzungen, mindestens 200; darunter entsteht kein Modell. Die Einwilligung des Besuchers deckt die Aufzeichnung, aus der die Merkmale stammen — dieselbe Grundlage wie A.8. Ob ein Angebot ausgespielt wird, entscheidet allein der Verantwortliche; für diese Ausspielung auf seiner Website ist er Verantwortlicher, nicht wir. |
| Kategorien von Empfängern | Der Kunde in seiner Oberfläche. Der Prozentwert und die Gründe erreichen zusätzlich den BROWSER DES BESUCHERS — sie werden dort gebildet, nicht dorthin geschickt — und stehen dem Code des Verantwortlichen über MousePlayer.on('exit_risk') und den dataLayer zur Verfügung. Ein Angebot, das daraufhin erscheint, sieht der Besucher selbst. Einen Angebotsvorschlag sieht allein der Verantwortliche in seiner Oberfläche; auf die Website gelangt er erst, wenn er ihn übernimmt. An Dritte geht nichts. |
| Drittlandübermittlung | Keine. Training und Bewertung laufen auf der Infrastruktur in Łódź beziehungsweise im Browser des Besuchers. Den Angebotsvorschlag formuliert das Sprachmodell auf eigener Hardware in Łódź (Abschnitt 4); an einen externen KI-Dienst geht nichts. |
| Aufbewahrung | Die Ereignisse teilen die Frist der Sitzung, zu der sie gehören (A.7), und fallen mit ihr. Das Modell wird bei jedem Lauf überschrieben; eine Historie gibt es nicht. Die beiden Merker im Browser liegen im lokalen Speicher des Besuchers: mp_seen_before ohne Ablauf, bis er den Speicher leert oder seine Einwilligung widerruft, mp_offer_<Datum> nur für den laufenden Tag (ältere Einträge entfernt mp.js beim nächsten Setzen). Dazu hält mp_design_sent im Sitzungsspeicher des Tabs fest, dass die Gestaltung schon gemessen wurde. Beim Widerruf entfernt mp.js alle drei. Der Angebotsvorschlag bleibt stehen, bis ein neuer ihn ersetzt; die Gestaltungsmessungen laufen in Redis nach 30 Tagen ab; die Seitensprache teilt die Frist ihrer Seitenansicht. |
A.16 Abwanderungsindikator für wiederkehrende Besucher
| Feld | Eintrag |
| Zweck | Aus den früheren Besuchen desselben Menschen abschätzen, ob er sich abwendet, damit der Verantwortliche darauf reagieren kann. Anders als A.15 sieht diese Bewertung nicht auf den laufenden Besuch, sondern auf die Geschichte. |
| Kategorien betroffener Personen | Wiederkehrende Besucher der Kundenwebseiten mit mindestens 2 Sitzungen. Wer nur einmal da war, bekommt keine Zeile. Der Schlüssel ist die Person im Sinne von A.4 — die vom Verantwortlichen gesetzte Kundenkennung, ersatzweise die Besucherkennung. |
| Kategorien personenbezogener Daten | Ein Risikowert zwischen 0 und 1, bis zu vier Klartextgründe aus einer festen Liste (sinkendes Engagement, Kurzbesuche, Reibung, überfällig; ein Kauf in den letzten beiden Besuchen senkt den Wert), die Zahl der Besuche und der Zeitpunkt des letzten. Keine Inhalte, keine Koordinaten. Es ist kein gelerntes Modell, sondern vier abzählbare Beobachtungen — jede steht als Grund in der Zeile, damit ein Wert nicht ohne Begründung dasteht. |
| Wo gespeichert | ai_churn (Migration 100): channelid, person_key, visitor_id, risiko, gruende, sitzungen, letzte_sitzung, berechnet_am. Zusätzlich je Kanal ein Redis-Hash mp_churn:<Kanal> mit zwei Tagen Ablauf, aus dem der WebSocket-Server beim Verbindungsaufbau liest; aufgenommen wird dort nur, wer über der Schwelle liegt. |
| Rechtsgrundlage | Weisung des Verantwortlichen; die zugrunde liegenden Sitzungen stehen unter der Einwilligung des Besuchers (A.1). Gerechnet wird je Projekt, nie über Kunden hinweg. |
| Kategorien von Empfängern | Der Kunde in seiner Oberfläche. Der Wert wird außerdem an den BROWSER DES BESUCHERS gesendet, sobald dieser sich verbindet, und steht dem Code des Verantwortlichen über MousePlayer.on('churn_risk') zur Verfügung; er kann daran ein Angebot knüpfen. Diese Übermittlung an das Endgerät des Betroffenen ist der Grund, warum der Eintrag hier steht und nicht unter A.8. An Dritte geht nichts. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | Die Zeile wird bei jedem Lauf für den Kanal neu geschrieben und fällt mit den Sitzungen, aus denen sie stammt. Der Redis-Eintrag läuft nach zwei Tagen von selbst ab. |
A.17 Zusammenfassender Bericht über einen Besucher
| Feld | Eintrag |
| Zweck | Alle Besuche EINES Menschen zu einem lesbaren Bericht zusammenfassen: woher er kam, wofür bezahlt wurde, woran er hängen blieb und ob daraus ein Ziel wurde. Die Befunde werden gerechnet; ein Sprachmodell formuliert sie höchstens um. Angefordert wird ein Bericht entweder vom Kunden für einen bestimmten Besucher oder selbsttätig für höchstens 5 Besucher je Projekt und Nacht — ausgewählt werden bezahlte Besuche ohne Kauf. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, für die mehr als ein Besuch vorliegt. Der Schlüssel ist die Person im Sinne von A.4. |
| Kategorien personenbezogener Daten | Höchstens vierzehn gerechnete Befunde in Textform: Zahl der Besuche und Seiten, Zeitraum, Geräte, Herkunft samt Kampagne, Käufe und erreichte Ziele, die drei größten Engpässe mit Pfad, die letzte Sitzung und die BESCHRIFTUNGEN der angeklickten Elemente (bis fünf, je 60 Zeichen). Dazu der erzeugte Text. Feldwerte aus Formularen sind nicht dabei — sie verlassen den Browser nie. Beschriftungen und Pfade stammen dagegen aus dem, was die Website des Verantwortlichen selbst ausgibt, und können deshalb einen Namen oder eine Adresse enthalten, wenn er sie dort anzeigt oder in die URL schreibt; als Lücke in Abschnitt 10 vermerkt. |
| Wo gespeichert | ai_besucher_bericht (Migration 100) mit channelid, person_key, lang, den Befunden, ihrem Hash, dem Text und dem Namen des Modells. Für die Formulierung wandern die BEFUNDE — nicht die Aufzeichnung — durch ai_ki_queue zu den Rechnern, auf denen das Sprachmodell läuft (eigene Hardware im selben lokalen Netz, siehe Abschnitt 4). Verbraucht wird je Bericht ein Kontingent (ai_ki_kontingent je Workspace und Monat, 3 im freien Tarif, sonst 200). |
| Rechtsgrundlage | Weisung des Verantwortlichen; die zugrunde liegenden Sitzungen stehen unter der Einwilligung des Besuchers (A.1). Das Sprachmodell wird nicht trainiert und nicht verändert; es formuliert nur. |
| Kategorien von Empfängern | Der Kunde in seiner Oberfläche. Der Besucher selbst erfährt davon nichts — anders als bei A.15 und A.16 wirkt hier nichts auf ihn zurück. |
| Drittlandübermittlung | Keine. Das Sprachmodell läuft auf eigener Hardware in Łódź (Abschnitt 4); an einen externen KI-Dienst geht nichts. |
| Aufbewahrung | 180 Tage ab Anforderung, durchgesetzt vom Nachlauf des KI-Prozesses. Fällt die letzte Sitzung des Besuchers vorher weg, fällt der Bericht mit ihr. |
A.18 Selbstauskunft und Löschverlangen des Besuchers
| Feld | Eintrag |
| Zweck | Einem Besucher zeigen, was über ihn gespeichert ist, und ihm die Löschung ermöglichen — die Unterstützung des Verantwortlichen bei den Betroffenenrechten nach Art. 28 Abs. 3 Buchst. e DSGVO. Erreichbar unter /meine-daten, /my-data und /moje-dane. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, und zwar nur die, die ihre eigene Kennung mitbringen. Der Verantwortliche muss den Link setzen; für seine Besucher ist er der Verantwortliche, und der Hinweis nach Art. 13 gehört in seine Erklärung. |
| Kategorien personenbezogener Daten | Angezeigt werden Zahl, Zeitraum und Domains der Sitzungen — keine Aufzeichnungen. Die Kennung ist ein Trägerausweis; wer eine fremde kennt, soll nicht das Verhalten eines Fremden sehen. Aus demselben Grund bleibt die Auskunft beim GERÄT und führt nicht über mp_person_sql() zusammen, was zu einem Menschen gehört: die Zusammenführung gäbe MEHR preis, nicht weniger. Vom Löschverlangen gespeichert werden Kennung, Zeitpunkt und Ausführungszeitpunkt. |
| Wo gespeichert | visitor_deletion_requests (visitor_id, requested_at, done_at) — 0 Zeilen. Die Seite selbst speichert nichts; sie liest. Ausgeführt wird das Verlangen vom Worker über dieselbe Löschkette, die auch der Verantwortliche auslöst — ein zweiter Löschweg wäre ein zweiter Ort für dieselbe Wahrheit. |
| Rechtsgrundlage | Art. 28 Abs. 3 Buchst. e DSGVO (Unterstützung des Verantwortlichen) und dessen Weisung. Die Kennung wird gegen ihre Form geprüft (^v_[a-z0-9]{9}_\d{13}$); alles andere wird abgewiesen. |
| Kategorien von Empfängern | Der Besucher selbst. An den Kunden geht nichts — er erfährt von einem Löschverlangen nur daran, dass die Sitzungen verschwinden. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | Die Zeile bleibt als Nachweis, dass und wann gelöscht wurde. Sie enthält keine Verhaltensdaten. Wird eine Sicherung zurückgespielt, werden die verzeichneten Verlangen erneut ausgeführt, bevor das System wieder in Betrieb geht (Ziffer 24.2 der Nutzungsbedingungen). |
A.19 Nachkontrolle der Bot-Erkennung — Entscheidungen des Betreibers als Lernbeispiele
| Feld | Eintrag |
| Zweck | Sitzungen, die die Wellenerkennung rückwirkend als Bot markiert hat, prüft ein Wächter noch einmal und meldet Zweifelsfälle in Urgent Logs. Der Betreiber entscheidet dort per Klick: Mensch oder Bot. Jede Entscheidung wird ein Lernbeispiel, aus dem die Gewichte der sieben Signale neu gerechnet werden — nur die Gewichte, nicht die Schwelle, und erst ab einer im Administrationsbereich einstellbaren Mindestzahl von Entscheidungen (bot_revision_lern_min). Darunter gelten feste Werte. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, deren Sitzung als Zweifelsfall gemeldet wurde, sowie die Person, die entschieden hat (Beschäftigte des Kunden oder von uns). |
| Kategorien personenbezogener Daten | Kein Besucherinhalt. Gespeichert werden Kanal, Sitzungskennung, die Entscheidung, die Punktzahl, die Namen der zutreffenden Signale (etwa: Kennung weicht von der Welle ab, Referrer vorhanden, Adresse aus einem privaten Netz) und die Kennung des Entscheidenden. Der Merkmalsvektor steht MIT im Beispiel, weil die Sitzung selbst nach ihrer Frist weg ist und das Lernen sie trotzdem braucht. |
| Wo gespeichert | bot_review_labels (Migration 140): eine Zeile je Sitzung, wer sich umentscheidet, überschreibt. Gelesen wird sie von cfg/bot_revision_lib.php. Ohne die Tabelle laufen die Wächter mit festen Gewichten. |
| Rechtsgrundlage | Weisung des Verantwortlichen; für die Sitzungen selbst gilt A.1. Das Verfahren verbessert die Trennung von Bots und Menschen und damit die Richtigkeit der Auswertung (Art. 5 Abs. 1 Buchst. d DSGVO). Es hängt keine Entscheidung gegenüber dem Besucher daran; eine Freigabe befreit eine Sitzung von der Markierung, mehr nicht. |
| Kategorien von Empfängern | Keine außerhalb der Oberfläche; die Beispiele sind nur dem Betreiber sichtbar. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | Vorgabe: keine automatische Löschung — ein Beispiel ist pseudonym und trägt keinen Besucherinhalt, und seine Aussagekraft wächst mit dem Bestand. Die Frist ist im Administrationsbereich in Jahren einstellbar (retention_bot_labels_years, 0 = unbegrenzt); ab 1 löscht der Statuswächter (srv/cron_status.php) Zeilen nach so vielen Jahren. Sie steht in keiner Löschkette der Sitzung: fällt die Sitzung weg, bleibt das Beispiel — beabsichtigt, aber als Lücke in Abschnitt 10 vermerkt. |
A.20 Element-Tracking — Klicks auf markierte Seitenelemente
| Feld | Eintrag |
| Zweck | Der Verantwortliche markiert im Element-Assistenten Elemente seiner Seiten — einzeln oder als Gruppe ähnlicher Elemente, per CSS-Selektor — und erhält je Markierung Klicks, Sitzungen mit Klick, Besucher und Klickrate. Gezählt wird rückwirkend: srv/element_worker.php ordnet bereits aufgezeichnete Klicks (A.1, mouse_events_analytik) im Abbild ihrer eigenen Seitenansicht dem markierten Element zu. Eine Markierung kann außerdem ein Ziel oder die Stufe eines Trichters sein; dann zählen ihre Treffer als erreichtes Ziel bzw. erreichte Stufe. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, deren Klicks aufgezeichnet wurden. |
| Kategorien personenbezogener Daten | Eine Ergänzung der Klickaufzeichnung (A.1), sonst keine neue Erhebung: Klickt ein Besucher auf ein Element, das erst nach dem Abbild entstanden ist (etwa ein aufgeklapptes Menü oder ein Pop-up), schickt mp.js seit dem 27.09.2026 dessen Aufbau mit — Tag, Klassen, einige Attribute (role, type, name, Linkpfad ohne Query, data-*), die Stellung unter gleichartigen Geschwistern und die sichtbare Beschriftung; in maskierten Bereichen nur Tag und Kennung. Er liegt bei den Ereignissen der Seitenansicht (A.1) und teilt deren Aufbewahrung. Je Treffer werden gespeichert: Kanal, Sitzungs- und Seitenansichtskennung, Beginn der Sitzung, die Art des Klicks (Klick oder Tippen), die sichtbare Beschriftung des getroffenen Elements aus dem Abbild — genau so maskiert, wie die Aufzeichnung sie enthält — und, wenn der Verantwortliche das wählt, der Wert eines Attributs dieses Elements (etwa data-id) zum Aufschlüsseln. Seit dem 27.09.2026 merkt sich der Element-Worker Klicks vor, deren Ziel im Abbild fehlt und für die kein Aufbau mitkam (ältere Klicks): Kanal, Sitzungs- und Seitenansichtskennung, Zeitpunkt und einen Hash aus Seitenpfad und Beschriftung — die Beschriftung selbst steht dort nicht. Aus aufgelösten Klicks lernt er je Markierung, welche Beschriftung auf welchem Seitenpfad die Markierung trifft (Pfad, Beschriftung, zwei Zähler, ohne Besucherbezug). Sagen alle Beobachtungen dasselbe, wird ein vorgemerkter Klick als Treffer — gekennzeichnet als übertragen — oder als kein Treffer zugeordnet. Die Markierung selbst (Name, Selektor, Seitenbereich) und die Tageszähler der Abdeckung tragen keinen Besucherbezug. |
| Wo gespeichert | mp_element_regeln, mp_element_klicks und mp_element_tag (Migration 152), mp_element_offen und mp_element_muster (Migration 155). Gelesen von cfg/element_lib.php. |
| Rechtsgrundlage | Weisung des Verantwortlichen (Art. 28 Abs. 3 Buchst. a DSGVO), erteilt durch das Anlegen einer Markierung; für die Klicks selbst gilt A.1. Die Auswertung fasst vorhandene Aufzeichnungen zusammen; hinzu kommt allein der Aufbau nachträglich entstandener Klickziele (oben), der dasselbe beschreibt wie das Abbild der Seite. Es hängt keine Entscheidung gegenüber dem Besucher daran. |
| Kategorien von Empfängern | Keine außerhalb der Oberfläche, solange die Markierung nur ausgewertet wird. Verwendet der Verantwortliche sie als Ziel oder als Stufe eines Trichters, gehen erreichte Ziele und Trichterabbrüche an die Übermittlungen, die er eingeschaltet hat (4.1) – mit Sitzungskennung, Ziel- bzw. Trichtername und der Beschriftung des angeklickten Elements, und nur für Klicks, die höchstens so alt sind, wie im Admin eingestellt (Vorgabe zwei Stunden). Ältere Treffer zählen in der Oberfläche mit, werden aber nicht übermittelt. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | Ein Treffer fällt mit der Sitzung, aus der er stammt: mp_element_klicks steht in der Löschkette (mp_sitzungen_loeschen() in srv/db_worker.php), und der Element-Worker entfernt stündlich Treffer, deren Seitenansicht es nicht mehr gibt — damit auch nach Löschwegen außerhalb dieser Kette spätestens nach einer Stunde. Vorgemerkte Klicks (mp_element_offen) fallen auf denselben Wegen mit ihrer Sitzung. Das Löschen einer Markierung löscht ihre Treffer, Zähler, Vormerkungen und Muster; die Muster tragen keinen Besucherbezug und fallen außerdem mit einem geänderten Selektor oder nach einem Jahr ohne neue Beobachtung. Eine eigene Frist gibt es bewusst nicht: sie wäre länger oder kürzer als die der Aufzeichnung, und beides wäre falsch. |
A.21 Feedback-Umfragen — eine Frage an den Besucher, die Antwort neben der Aufzeichnung
| Feld | Eintrag |
| Zweck | Der Verantwortliche stellt Besuchern seiner Seite eine kurze Frage — Weiterempfehlung von 0 bis 10, fünf Gesichter, Ja/Nein oder eine Auswahl — und auf Wunsch eine Nachfrage als Freitext. Die Antwort wird dem Besuch zugeordnet, damit er die Aufzeichnungen der Besucher ansehen kann, die unzufrieden waren. Frage, Zeitpunkt, Anteil der Besucher und Sprache legt der Verantwortliche fest. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, denen eine Umfrage gezeigt wurde — nach einer vom Verantwortlichen eingestellten Stichprobe und höchstens einmal je eingestellter Pause —, sowie Besucher, die eine Umfrage über einen Knopf am Seitenrand selbst geöffnet haben; dort beginnt die Pause erst mit einer Antwort. Erhoben wird nur, was der Besucher selbst eingibt: wer die Frage wegklickt, hinterlässt allein die Tatsache, dass sie gezeigt und geschlossen wurde. |
| Kategorien personenbezogener Daten | Die Bewertung (eine Zahl oder die gewählte Option) samt Stimmung (negativ, neutral, positiv), Zeitpunkt und Kennung der Umfrage als Ereignis des Besuchs (A.7): survey_shown, survey_answer und survey_dismiss. Bei einer Nachfrage ein FREITEXT von höchstens 500 Zeichen mit der Sprache der Seite. Vor dem Senden entfernt mp.js E-Mail-Adressen, IP-Adressen und Telefonnummern, der Worker ein zweites Mal (mp_umfrage_text_filtern()); unter dem Feld steht die Bitte, keine persönlichen Daten einzugeben. Im Browser des Besuchers hält mp_umfrage (localStorage) je Umfrage das Los der Stichprobe und den Zeitpunkt der letzten Anzeige fest, beim Knopf am Seitenrand den der letzten Antwort. |
| Wo gespeichert | Die Bewertung in session_custom_events und session_custom_event_params (A.7); der Freitext in mp_umfrage_text (Migration 157) — bewusst getrennt: er ist die heikelste Angabe der Umfrage und gehört nicht in die Tabelle, aus der Webhooks und Brücken lesen. Die Umfragen selbst, also allein der Text des Verantwortlichen, in projects.survey_json. |
| Rechtsgrundlage | Weisung des Verantwortlichen (Art. 28 Abs. 3 Buchst. a DSGVO), erteilt durch das Anlegen und Einschalten einer Umfrage. Die Antwort ist freiwillig. Ob für Frage und Nachfrage eine Rechtsgrundlage besteht und ob sie in seiner Datenschutzerklärung genannt sind, verantwortet er; der Textbaustein für Kunden nennt die Umfrage als eigene Stelle. Es hängt keine Entscheidung gegenüber dem Besucher daran. |
| Kategorien von Empfängern | Der Kunde, in der Auswertung und im Player. Die Bewertung ist ein benutzerdefiniertes Ereignis und geht deshalb an die Übermittlungen, die der Verantwortliche für solche Ereignisse eingeschaltet hat (4.1). Der Freitext geht an keine Brücke: mp_umfrage_text wird allein von cfg/umfrage_lib.php gelesen. |
| Drittlandübermittlung | Keine — außer über eine vom Verantwortlichen eingeschaltete Übermittlung (4.1), und dort nur die Bewertung. |
| Aufbewahrung | Mit der Sitzung: mp_umfrage_text steht in mp_sitzungen_loeschen(), im Löschweg des Players, in mp_konto_loeschen() und in der Projekt- und Workspace-Löschung des Dashboards; die Bewertung fällt mit session_custom_events. Eine eigene Frist gibt es bewusst nicht — sie wäre länger oder kürzer als die der Aufzeichnung, und beides wäre falsch. Der Schlüssel mp_umfrage im Browser wird beim Widerruf entfernt. |
A.22 Suche nach angezeigtem Text — welche Besuche einen bestimmten Text auf der Seite hatten
| Feld | Eintrag |
| Zweck | Der Kunde findet die Besuche, in denen ein bestimmter Text auf seiner Seite stand — beim Laden oder später eingeblendet, etwa eine Fehlermeldung, ein Hinweis oder „Ausverkauft“ —, um ihre Aufzeichnungen anzusehen. Gesucht wird im User Explorer. |
| Kategorien betroffener Personen | Besucher der Kundenwebseiten, deren Besuch aufgezeichnet wurde (A.2) und nicht als automatisiert erkannt ist. |
| Kategorien personenbezogener Daten | Die Textstücke, die in Abbild und Änderungen der Seite standen (A.2), je Textknoten, dazu die Zuordnung zur Seitenansicht. Gelesen wird, was bereits aufgezeichnet ist: maskierte Bereiche und Formulareingaben sind dort schon ersetzt und werden nicht gefunden. Gibt eine Seite selbst Personendaten aus (eine Bestätigungsseite mit Name und Anschrift), stehen sie auch hier — wie in der Aufzeichnung. |
| Wo gespeichert | mp_text_block (Wörterbuch je Projekt, jedes Textstück einmal), mp_text_pv (welche Seitenansicht welches Stück trug) und mp_text_stand (welche Ansicht gelesen ist), Migration 175. Gefüllt alle zehn Minuten von srv/textsuche_lauf.php auf dem eigenen Server. |
| Rechtsgrundlage | Weisung des Verantwortlichen (Art. 28 Abs. 3 Buchst. a DSGVO): die Suche erschließt dieselbe Aufzeichnung, die er beauftragt hat. Es hängt keine Entscheidung gegenüber dem Besucher daran. |
| Kategorien von Empfängern | Der Kunde, als Filter im User Explorer. Keine Übermittlung, keine Brücke. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | 30 Tage ab Beginn der Seitenansicht, kürzer als die Aufzeichnung: danach fallen Zuordnung und Stand, ein Textstück mit seiner jüngsten Ansicht. Wird die Sitzung früher gelöscht (Frist, Löschverlangen, Löschung im Player, Projekt- oder Kontolöschung), fällt die Zuordnung mit ihr — in mp_sitzungen_loeschen() und der Kanallöschung direkt, auf allen anderen Wegen spätestens nach zehn Minuten durch den Lauf, der Zuordnungen ohne Seitenansicht entfernt. |
4. Teil A — Empfänger, Unterauftragsverarbeiter und Drittlandübermittlungen
Der Aufzeichnungsweg selbst enthält keinen ausgehenden Aufruf an Dritte. Festgestellt wurde das am 10.08.2026 durch eine Suche in cfg/, srv/, class/ und www/ (ohne vendor und node_modules) nach curl_init, curl_exec, file_get_contents mit http, fsockopen und stream_context_create sowie nach allen https-Literalen. Die Geo-Auflösung läuft gegen lokale MaxMind-Dateien, das Stylesheet der Oberfläche wird als vorab gebaute Datei vom eigenen Server ausgeliefert, Flaggenbilder kommen aus /img/flags/. E-Mail geht seit dem 23.09.2026 über SMTP an Namecheap Private Email (mail.privateemail.com, Port 465, TLS) mit dem Absender office@mouseplayer.com; die PHP-Funktion mail() würde nur genutzt, wenn kein SMTP-Server eingetragen ist, was nicht der Fall ist. Grenze dieser Suche: Die vendor-Verzeichnisse (Stripe-SDK, Google-Cloud-SDK, PHPMailer, Symfony) wurden nicht durchsucht — dort stehen die Endpunkte der unten genannten Dienste.
| Empfänger | Rolle und was übermittelt wird | Ziel | Garantie | Stand |
| Stripe | Zahlungsabwicklung für KUNDENKONTEN. E-Mail, Name, Rechnungsanschrift und Zahlungsdaten der Kunden. www/billing_ajax.php:134 setzt den API-Schlüssel; die Zeilen 381 und 687 übergeben customer_email; Zeile 48 setzt billing_address_collection='required'; Zeile 54 customer_update für Adresse und Name; die Zeilen 462/527/672 übergeben Metadaten. Rückkanal www/api/webhook_stripe.php, Tabelle stripe_events. Keine Besucherdaten. | USA | AVV angenommen am 01.08.2026 als Bestandteil der bei Kontoeröffnung angenommenen Bedingungen (Angabe des Verantwortlichen). Vertragspartner: Stripe Payments Europe, Ltd.; für Übermittlungen in die USA Stripe, Inc. Modul 2 (Verantwortlicher an Auftragsverarbeiter). Das folgt aus der Rollenverteilung und nicht aus einem Nachschlagen: MousePlayer ist für die übermittelten Konto- und Abrechnungsdaten Verantwortlicher, Stripe insoweit Auftragsverarbeiter. Die angenommene Fassung selbst ist nicht eingesehen worden; weicht sie ab, gilt sie. | Stand 16.10.2026 nicht im Echtbetrieb: beide Schlüsselplätze tragen Testschlüssel, es werden keine echten Zahlungen abgewickelt. |
| VIES (Europäische Kommission) | Prüfung einer angegebenen Umsatzsteuer-Identifikationsnummer eines KUNDEN über die öffentliche REST-Schnittstelle des MwSt-Informationsaustauschsystems (cfg/lib.php). Übermittelt werden Ländercode und USt-IdNr.; zurück kommen die Gültigkeit sowie gegebenenfalls Name und Anschrift des Unternehmens, gespeichert am Konto (B.1). Keine Besucherdaten. | EU | Öffentliche Stelle der Union; kein Auftragsverarbeiter, kein Vertrag erforderlich. Die Abfrage dient der Prüfung der Steuerangaben des Kunden. | In Nutzung, sobald ein Kunde eine USt-IdNr. angibt. |
| Telegram | Supportbenachrichtigung. Bis 11.08.2026 übermittelte cfg/lib.php den GESAMTEN Supportvorgang: Nutzerstatus samt Nutzer-ID, E-Mail-Adresse, Thema, 'IP / Kraj' mit der UNGEKÜRZTEN IP-Adresse, die Herkunfts-URL und den vollständigen Nachrichtentext. Seit 11.08.2026 (Commit 02846c2, cfg/lib.php) geht ausschließlich eine feste Zeichenkette hinaus: 'MousePlayer: es liegt eine neue Supportanfrage vor.' Keine einzige Variable, kein parse_mode, bewusst auch keine Vorgangsnummer und kein Link aus der Anfrage. Die Anfrage selbst wird unverändert in support_requests gespeichert — die Daten gehen nicht mehr hinaus, sie verschwinden nicht. | Außerhalb der EU | Bis 11.08.2026: keine — Telegram bietet für Bots keinen Auftragsverarbeitungsvertrag. Seit 11.08.2026 wird keiner mehr benötigt: die Benachrichtigung enthält keine personenbezogenen Daten, Telegram ist damit weder Auftragsverarbeiter noch Empfänger. Entscheidung des Inhabers vom 11.08.2026: der Kanal bleibt, die Nachricht wird auf ein reines Signal reduziert, die IP-Adresse ist entfernt. Ein Wächter (ai/pruefstand/test_telegram_signal.php) prüft nicht das Ergebnis, sondern die Möglichkeit — welche Variablen die Nachricht überhaupt erreichen können; vier sind erlaubt, 15 Merkmale verboten, der Text muss eine einfach zitierte Zeichenkette ohne Einsetzung sein. | AKTIV, aber ohne personenbezogene Daten — entschärft am 11.08.2026. TELEGRAM_BOT_TOKEN und TELEGRAM_CHAT_ID sind weiterhin in .env gesetzt; hinaus geht nur noch das Signal. |
| Google reCAPTCHA | Anmeldung, Registrierung, Supportformular, Abrechnungsseite. Serverseitige Prüfung in www/login.php:31-45 und cfg/lib.php:6337 gegen https://www.google.com/recaptcha/api/siteverify; browserseitig www/billing.php:1290. | USA | reCAPTCHA bleibt im Produktivbetrieb. Datenverarbeitungsbedingungen von Google angenommen am 01.08.2026 (Angabe des Verantwortlichen). Vertragspartner: Google Ireland Limited; für Übermittlungen in die USA Google LLC. Auf dem Entwicklungssystem ist der Dienst aus (mp_recaptcha_aktiv() liefert !mp_ist_dev()), im Produktivbetrieb an — dort findet die Übermittlung bei jedem Anmelde-, Registrierungs-, Passwort- und Abrechnungsvorgang statt. | Nur auf diesem System inaktiv: mp_recaptcha_aktiv() ist in cfg/config.php:131-133 als !mp_ist_dev() definiert, und APP_ENV=dev. Im Produktivbetrieb aktiv. |
| Google BigQuery | Nächtlicher Export in das EIGENE GCP-Projekt des Kunden. srv/cron_integration_bigquery.php:95-100 selektiert session_id, channelid, visitor_id, custom_user_id, ip_address, country, referrer, user_agent, screen_width, screen_height, start_time, end_time, duration_seconds, device_type und lädt sie als NDJSON in visitor_sessions_YYYYMMDD. | Vom Kunden gewählte Region | Das Ziel ist das eigene Projekt des Kunden, der Kunde ist damit der Importeur. Der Service-Account-Schlüssel liegt verschlüsselt in projects.bigquery_sa_json (decrypt_sa_key, Schlüssel BIGQUERY_SA_AES_KEY aus .env). | INAKTIV. projects.bigquery_active=0 bei allen 7 Projekten, bigquery_project_id überall NULL, und der Prozess läuft nicht. |
| Kunden-Webhooks | srv/cron_integration_webhook.php:63-80. Inhalt gebaut in srv/db_worker.php:1313-1323: timestamp, event_type, channel_id, session_id, ein direkter Player-Link 'https://<host>/player?id=...&session=...' und die Ereignisparameter. Sonderformatierung für Slack und Discord (mp_format_webhook_body, cfg/lib.php:5978). | Unbestimmt — vom Kunden gesetzt | Das Ziel wählt der Kunde und liegt damit in der eigenen Verantwortung des Verantwortlichen. Ja, das Ziel wird je Kunde festgehalten (Entscheidung des Verantwortlichen, 17.08.2026). Es steht bereits am Projekt; was fehlt, ist der Nachweis, WER es wann gesetzt hat. Seit dem 17.08.2026 steht jede Änderung des Webhook-Ziels im Änderungsprotokoll (log_audit, Aktion update_integrations, Feld webhook_host). Festgehalten wird nur der Host, nicht die vollständige Adresse: ein Webhook-Pfad trägt oft ein Geheimnis — Slack und Discord legen den Schlüssel in die URL —, und ein Änderungsprotokoll ist der falsche Ort dafür. Für die Frage, wohin Ereignisdaten das Haus verlassen, reicht der Host. | INAKTIV. projects.webhook_active=0 und webhook_url NULL bei allen 7 Projekten. Der Dispatcher-Prozess läuft. |
| Meta (Conversions API) | Nur wenn der Verantwortliche die Brücke einschaltet und seinen eigenen Zugriffstoken hinterlegt. Übermittelt werden ausschließlich erfüllte Ziele des jeweiligen Projekts: Zielname, Zeitpunkt, eine aus Sitzung und Ziel gebildete Ereigniskennung zur Entdopplung, gegebenenfalls Wert und Währung, dazu die Cookies _fbp und _fbc sowie die User-Agent-Zeichenkette. Nicht übermittelt werden Name, E-Mail, Telefonnummer und die IP-Adresse — die IP liegt bei MousePlayer ohnehin nur gekürzt vor und bliebe für die Zuordnung wertlos. Gesendet wird ausschließlich für Sitzungen mit consent_state = 'granted'; ohne _fbp/_fbc unterbleibt die Übermittlung ganz, weil sie ohne Zuordnungsmerkmal keinen Zweck hätte. Code: mp_capi_meta_ausloesen() und mp_capi_meta_zustellen() in cfg/lib.php, Versand über srv/cron_integration_webhook.php. | USA | Meta ist kein Unterauftragsverarbeiter von MousePlayer. MousePlayer führt die Übermittlung auf Weisung des Verantwortlichen aus — die Weisung besteht im Einschalten der Brücke und im Hinterlegen des Tokens. Empfänger ist das Werbekonto des Verantwortlichen; das Vertragsverhältnis zu Meta einschließlich der Garantien für die Übermittlung in die USA besteht zwischen dem Verantwortlichen und Meta, nicht zwischen Meta und MousePlayer. Meta verarbeitet die Daten zu eigenen Zwecken und insoweit in eigener Verantwortung. | Brücke vorhanden seit 19.08.2026, im Auslieferungsstand bei keinem Projekt eingeschaltet. |
| HubSpot / Pipedrive | Nur wenn der Verantwortliche die Brücke einschaltet und seinen eigenen API-Token hinterlegt. Übermittelt wird die Kundenkennung, die der Verantwortliche selbst gesetzt hat (setUserId()), zum Auffinden des Kontakts, und anschließend eine Notiz mit der Adresse der Sitzungsaufzeichnung. Keine Verhaltensdaten, keine Aufzeichnungsinhalte. Findet die Suche keinen Kontakt, endet der Vorgang ohne weitere Übermittlung. Code: mp_crm_kontakt_suchen() und mp_crm_notiz_anhaengen() in cfg/lib.php. | USA (HubSpot), EU (Pipedrive) | Wie bei Meta: Empfänger ist das CRM-Konto des Verantwortlichen, das Vertragsverhältnis besteht zwischen ihm und dem Anbieter. MousePlayer übermittelt auf seine Weisung. | Brücke vorhanden seit 19.08.2026, im Auslieferungsstand bei keinem Projekt eingeschaltet. |
| Google Cloud Storage (Warschau) | Ausgelagerte Kopie der täglichen Sicherung. Dokumentiert in OFFENE_PUNKTE.md Abschnitt 3.3: 'mysqldump --all_databases' und 'tar /var/www/' — jede Datenbank und der gesamte Webbaum einschließlich jeder .env. Lokal belegt mit 653 MB Datenbank und 678 MB Dateien. Bis 11.08.2026 lief die Sicherung täglich um 02:00 und ging unverschlüsselt hinaus. Seit 11.08.2026 wird sie auf dem eigenen Server verschlüsselt, bevor sie übertragen wird (rclone crypt; auch Datei- und Verzeichnisnamen sind verschlüsselt), und die beiden Schlüsseldateien liegen mit Modus 600 auf dem eigenen Server — Google hat sie nicht; der planmäßige Lauf findet seither um 03:00 statt. Der bisherige, unverschlüsselte Zielordner mit den Kopien aus der Zeit vor dem 11.08.2026 wurde am 12.08.2026 gelöscht. | Polen (EU) – Bucket in der Region europe-central2 (Warschau), seit dem 05.09.2026. Bis dahin lag die Kopie auf einem privaten Google-Drive-Konto ohne buchbare Datenregion; als Ziel war USA / weltweit anzugeben. | Auftragsverarbeitung nach den Google Cloud Datenverarbeitungsbedingungen, die für das Cloud-Projekt angenommen sind; Vertragspartner Google Ireland Limited. Damit ist die Abweichung beseitigt, die hier vom 17.08.2026 bis zum 05.09.2026 stand: für ein privates Google-Konto sind diese Bedingungen nicht verfügbar, und die allgemeinen Nutzungsbedingungen begründen keine Auftragsverarbeitung nach Art. 28 DSGVO. Die Kopie wird weiterhin vor der Übertragung verschlüsselt (rclone crypt, einschließlich Datei- und Verzeichnisnamen), die Schlüssel liegen ausschließlich beim Verantwortlichen — Google sieht Blöcke ohne Bedeutung. Das nimmt Google den Inhalt, nicht die Rolle. | AKTIV. Bis 11.08.2026 unverschlüsselt und am Ziel unbelegt — der Lauf nutzte die rclone-Konfiguration von root, und das Skript protokollierte nichts. Seit 11.08.2026 verschlüsselt; die Läufe vom 11.08.2026 (von Hand angestoßen) und vom 12.08.2026 (planmäßig um 03:00) sind protokolliert und haben am Ziel beide eine Gegenprobe bestanden (Byte-Zahl des Datenbankauszugs). Der tägliche Betrieb ist damit belegt, nicht nur der erste Versuch. Der Inhaber hat die Entschlüsselung geprüft; eine eigene Messung dazu liegt nicht vor. Der bisherige, unverschlüsselte Zielordner wurde am 12.08.2026 gelöscht. Seit dem 05.09.2026 geht die Kopie nach Google Cloud Storage in Warschau; die zuvor auf dem Drive-Konto abgelegten Kopien wurden am 06.09.2026 gelöscht, nachdem eine Wiederherstellung aus dem neuen Ziel gegengeprüft war. Kontoart, Datenregion und Vertrag sind damit geklärt. Seit dem 06.10.2026 enthält die Sicherung auch das Archiv der ausgelagerten Aufzeichnungsereignisse (/mnt/mouseplayer-dev-archive, A.1); dieses Archiv liegt lokal auf derselben Platte wie das System, die Auslagerung an einen anderen Ort leistet allein die verschlüsselte Kopie. Wiederherstellungstests aus der Kopie wurden am 05./06.09.2026 und am 07.10.2026 (vollständige Wiederherstellung der Daten) durchgeführt. Tagessicherungen werden 7 Tage, Wochensicherungen 364 Tage gehalten. |
| Namecheap | Domainregistrierung, autoritatives DNS, Weiterleitung eingehender E-Mail; seit dem 23.09.2026 auch Versand ausgehender E-Mail über Namecheap Private Email. Domaindaten; Inhalt und Absender von E-Mail an MousePlayer. Bei ausgehender E-Mail: Name, E-Mail-Adresse und Inhalt der Nachricht an den Kontoinhaber, bei der Anmeldemeldung zusätzlich IP-Adresse, Gerät und ungefährer Ort. | USA | Data Processing Addendum angenommen am 01.08.2026 (Angabe des Verantwortlichen); es deckt die aktuellen Standardvertragsklauseln ab. Eingehende Post läuft dauerhaft über die Weiterleitung von Namecheap; ein weiterer Postfachanbieter ist nicht beteiligt (Entscheidung des Verantwortlichen, 17.08.2026). Ausgehende Post geht seit dem 23.09.2026 über den SMTP-Dienst von Namecheap Private Email (TLS) hinaus: Vertragsmitteilungen, Kontohinweise, Anmeldemeldungen und die Meldungen der Wächter. | In Nutzung. |
| Let's Encrypt (ISRG) | Ausstellung und Erneuerung von TLS-Zertifikaten. Nur Domainnamen. | USA | Öffentliche Zertifizierungsstelle; verarbeitet keine personenbezogenen Daten in unserem Auftrag. | In Nutzung. |
| consented.eu | CMP auf den EIGENEN Seiten von MousePlayer, im Browser des Besuchers geladen: cfg/header.php:48 (stub.js) und Zeile 50 (cmp.js). Betrifft Besucher von mouseplayer.com, nicht die Aufzeichnung bei Kunden. | Verarbeitungsort: derselbe Server wie MousePlayer (/var/www/html/ConsentedEU auf demselben Rechner, gemessen am 17.08.2026). Vertragliche Grundlage: entfällt — consented.eu wird vom selben Rechtsträger betrieben (Angabe des Verantwortlichen). Es liegt keine Übermittlung an einen Dritten vor. | Entfällt aus demselben Grund: kein Dritter, also kein Vertrag. | Auf den eigenen Seiten in Nutzung. |
Hosting: entfällt — Eigenbetrieb auf eigener Hardware am Toya-Anschluss (AS16342, Łódź), keine Übermittlung an einen Dritten (Entscheidung des Verantwortlichen, 17.08.2026); bei einem Wechsel auf ein Rechenzentrum oder einen Cloud-Anbieter ist dieser Absatz neu zu fassen. Zur eigenen Hardware gehören der Server, auf dem Anwendung, Datenbank und Aufzeichnung laufen, und die Rechner mit Grafikkarte, auf denen das Sprachmodell läuft — derzeit einer, mit unserer eigenen KI, die wir selbst auf eigener Hardware betreiben (selbst gehostet). Alle stehen am selben Ort im selben lokalen Netz und gehören MousePlayer; für einen weiteren Rechner gilt dasselbe. Sie holen die gerechneten Befunde über HTTPS aus ai_ki_queue ab, jede Anfrage mit einem eigenen Geheimnis signiert, und liefern den formulierten Text zurück. Die Aufzeichnung selbst erreicht sie nicht, und an einen externen KI-Dienst geht nichts (A.8, A.12, A.15, A.17). Ist ein solcher Rechner zur Wartung außer Betrieb, warten die Aufträge, bis er zurück ist; in dieser Zeit zeigt die Oberfläche die gerechnete Fassung, und kein Auftrag wird an einen anderen Dienst weitergegeben.
4.1 Vom Verantwortlichen eingeschaltete Empfänger
Die Tabelle darüber führt Empfänger, die MousePlayer selbst einschaltet. Daneben gibt es Brücken, die der Verantwortliche einschaltet und für die er seinen eigenen Zugang hinterlegt. Sie sind keine Unterauftragsverarbeiter von MousePlayer; das Vertragsverhältnis zu ihnen besteht zwischen dem Verantwortlichen und dem Empfänger, einschließlich der Garantien für Drittländer. Genannt sind Kategorien statt Namen — welche Anbieter innerhalb einer Kategorie wählbar sind, ändert sich mit dem Funktionsumfang; maßgeblich ist die Auswahl in den Projekteinstellungen. Ausgelöst wird jede Übermittlung serverseitig aus srv/cron_integration_webhook.php; das Ergebnis steht im Zustellprotokoll (A.11).
| Kategorie | Was hinausgeht | Wodurch ausgelöst |
| Webhook an eine frei gewählte Adresse | Ereignisname, Kanal- und Sitzungskennung, Replay-Adresse, Ereignisparameter. Signiert mit HMAC-SHA256 über Zeitstempel und Rumpf. | ein vom Verantwortlichen abonniertes Ereignis |
| Kundenverwaltung (CRM) | Die vom Verantwortlichen selbst gesetzte Kundenkennung des Besuchers und die Replay-Adresse, angehängt als Notiz an einen bereits vorhandenen Kontakt. Ist kein Kontakt vorhanden, wird nichts angelegt. | Sitzungsende mit gesetzter Kundenkennung |
| Helpdesk und Ticketsystem | Dieselbe Angabe als interne Notiz am jüngsten offenen Ticket des Absenders. Gibt es kein offenes Ticket, geschieht nichts. | Sitzungsende mit gesetzter Kundenkennung |
| E-Mail- und Lebenszyklus-Marketing | Kundenkennung, Ereignisname und Replay-Adresse als Ereignis im System des Verantwortlichen. | Sitzungsende mit gesetzter Kundenkennung |
| Werbenetze (Conversions API) | Die Klick-Kennung aus dem eigenen Cookie des Werbenetzes, Ereignisname, Wert und Währung. Nicht übermittelt werden Name, E-Mail-Adresse, Telefonnummer und IP-Adresse. | ein erfülltes Ziel bei erteilter Einwilligung |
| Objektspeicher und Tabellenablage | Kundenkennung, Zeitpunkt und Replay-Adresse als Objekt bzw. als Zeile im eigenen Speicher des Verantwortlichen. | Sitzungsende mit gesetzter Kundenkennung |
| Fehler- und Aufgabenverfolgung | Titel und Beschreibung eines Vorgangs mit der Replay-Adresse. | ein Frustrationssignal oder ein JavaScript-Fehler |
| KI-Agenten des Verantwortlichen über den MCP-Server | Lesend: Projekte, Kennzahlen, Sitzungslisten samt Wiedergabelink, einzelne Sitzungen mit Seitenansichten und Ereignissen, Seiten, Frustrationssignale und Ziele — nicht das Seitenabbild. Angemeldet wird mit einem Lese-Schlüssel der REST-API des Verantwortlichen. | eine Abfrage des Agenten, nur bei je Projekt eingeschaltetem Zugang (projects.mcp_active) und in einem bezahlten Tarif |
Drittlandübermittlung: unbestimmt. Ziel und Anbieter wählt der Verantwortliche; die Garantie nach Kapitel V DSGVO obliegt damit ihm. Übermittelt wird in keinem Fall der aufgezeichnete Seiteninhalt, kein Mausverlauf und kein Formulartext — die Brücken tragen Kennungen und Ereignisnamen, nicht das Replay.
5. Teil B — Art. 30 Abs. 1: Verarbeitungen in eigener Verantwortung
Verantwortlicher für alles in diesem Teil: LW IT Solutions Company Lukas Wójcik, al. Tadeusza Kościuszki 80/82 lok. 301, 90-437 Lodz, Polen, office@mouseplayer.com. Kein Vertreter erforderlich (in der Union niedergelassen). Kein Datenschutzbeauftragter benannt — Abschnitt 9. Technische und organisatorische Maßnahmen: Abschnitt 8.
B.1 Kundenkonten, Workspaces und Abrechnung
| Feld | Eintrag |
| Zweck | Betrieb der eigenen Kundenkonten von MousePlayer, der Workspace-Mitgliedschaft und der Abrechnung. |
| Kategorien betroffener Personen | Kundennutzer. Gemessen: 4 Konten; workspace_users 4 owner, 1 admin, 1 viewer. |
| Kategorien personenbezogener Daten | E-Mail, normalisierte E-Mail, Vor- und Nachname, Geschäftsart, Kontoart (Unternehmen oder Verbraucher, customer_type), Sprache, Theme. Firmendaten: Firmenname und Anschrift, Land und Umsatzsteuer-Identifikationsnummer samt Ergebnis, Zeitpunkt und Quelle der Prüfung sowie Name und Anschrift laut VIES. Firmenlogo (Dateiname und Zeitpunkt; die Datei selbst außerhalb des Webverzeichnisses). Passwort-Hash, Verify- und Reset-Token, Ablauf des Reset. Zwei-Faktor-Anmeldung (TOTP, Migration 132): das Geheimnis verschlüsselt, der zuletzt verwendete Zeitschritt, der Zeitpunkt der Einrichtung und gehashte Wiederherstellungscodes. Schalter für die Anmeldemeldung (login_alert, B.7). Gerätekennung (device_id), Verdachtskennzeichen is_suspicious. Letzte VOLLE IP-Adresse, Land, Stadt, ASN-Nummer und ASN-Organisation. Abrechnungsdaten: Tarif, Währung, Stripe-Kundennummer, Stripe-Abonnement, Abrechnungszeitraum, Status, Kündigung zum Periodenende. Zeitpunkt einer Warnung wegen Untätigkeit. IP-Historie je Nutzer. |
| Wo gespeichert | users (user_id, email, normalized_email, device_id, password_hash, first_name, last_name, business_type, customer_type, status, lang, verify_token, reset_token, reset_expires, is_superadmin, is_suspicious, new_email, email_verify_token, last_country, last_city, last_asn_number, last_asn_org, last_ip, created_at, last_login, subscription_tier, stripe_customer_id, stripe_subscription_id, billing_period_end, billing_status, retention_grace_until, retention_grace_days). user_ip_history (user_id, ip_address, asn_number, asn_org, last_seen) — 5 Zeilen, davon 0 gekürzt. workspace_users (workspace_id, user_id, role); workspace_invites (token, workspace_id, email, role, invited_by, created_at). In users seit dieser Fassung zusätzlich genannt: company_name, company_street, company_postcode, company_city, company_country, vat_country, vat_number, vat_valid, vat_checked_at, vat_source, vat_name, vat_address, company_logo, company_logo_at, login_alert, totp_secret, totp_enabled_at, totp_last_step, totp_recovery, theme_mode, cancel_at_period_end, inactive_warned_at, sessions_revoked_at. Zeilenzahlen in dieser Zeile: Stand 10.08.2026. |
| Rechtsgrundlage | Im Code nicht ausgewiesen. Art. 6 Abs. 1 Buchstabe b für die Durchführung des Vertrags (Konto, Workspace, Abrechnung) und Art. 6 Abs. 1 Buchstabe c für die steuerliche Aufbewahrung der Rechnungen (Entscheidung des Verantwortlichen, 17.08.2026). Die Frist steht in der Zeile zur Aufbewahrung. |
| Kategorien von Empfängern | Stripe (Abrechnung, siehe Abschnitt 4). VIES der Europäischen Kommission (Prüfung der USt-IdNr., Abschnitt 4). Namecheap Private Email als Versanddienst der E-Mails an den Kontoinhaber: Kontobestätigung, Passwort-Reset, Einladungen, Anmeldemeldung, Warnung vor der Löschung wegen Untätigkeit, Mitteilung geänderter Vertragsunterlagen, Wochenbericht, Supportantworten (Abschnitt 4). Mitglieder desselben Workspace sehen Name, E-Mail-Adresse und Rolle der übrigen Mitglieder sowie die Kontoart des Workspace, also die seines owner (Nutzungsbedingungen Ziffer 6.6), und das Firmenlogo des Eigentümers; eine eingeladene Person sieht dieses Logo über den Einladungslink, solange die Einladung offen ist. |
| Drittlandübermittlung | Stripe (USA) und Namecheap (USA); Vertragspartner und Garantien in Abschnitt 4. VIES liegt in der Union. |
| Aufbewahrung | Beim Ende des Kontos vollständig — und das Ende tritt auch ohne Zutun ein. Löst der Inhaber die Löschung in den Kontoeinstellungen aus, räumt mp_konto_loeschung_ausfuehren() (cfg/lib.php) unter anderem user_ip_history, live_tokens, login_sessions, remember_tokens, report_subscriptions, die Zähler des Aufnahme-Kontingents, api_keys, workspace_invites, workspace_users, workspaces und users ab; audit_logs, bot_review_labels und die Einträge in mp_loesch_archiv werden entpersonalisiert. Seit dem 07.10.2026 (Migration 189) archiviert dieser Weg zuerst: Das Konto wird gesperrt, Anmeldungen werden widerrufen, eigene Workspaces und Projekte werden ausgeblendet und nicht mehr aufgezeichnet; was zurückgeholt werden kann, steht in mp_loesch_archiv. Nach 30 Tagen – oder sofort, wenn der Inhaber es wählt – löscht der db_worker endgültig über die genannte Kette und zählt danach nach, ob etwas übrig ist. Ein endgültig gelöschtes Konto hinterlässt im Archiv weder eine Kennung noch eine Bezeichnung. Bleibt der Inhaber untätig, warnt der tägliche Lauf nach 24 Monaten ohne Anmeldung und löscht 30 Tage später über dieselbe Kette. Gerechnet wird ab der letzten Anmeldung, bei einem nie benutzten Konto ab seiner Anlage. Gelöscht wird ausschließlich nach einer zugestellten Warnung; schlägt der Versand fehl, beginnt die Frist gar nicht erst. Beide Werte stehen in site_settings und sind im Administrationsbereich einstellbar. Rechnungen und die zugehörigen Abrechnungsunterlagen werden fünf Jahre aufbewahrt, gerechnet ab dem Ende des Kalenderjahres, in dem die Zahlungsfrist der Steuer ablief (Angabe des Verantwortlichen, 17.08.2026: „5 lat, licząc od końca roku kalendarzowego, w którym upłynął termin płatności podatku"). Von der Löschung des Kontos ausgenommen bleiben deshalb die Rechnungsdaten; die übrigen Kontofelder gehen mit dem Konto. Seit dem 16.10.2026 werden wegen Untätigkeit nur noch Konten im freien Tarif gewarnt und gelöscht: eigener Tarif free und keine Mitgliedschaft in einem Workspace, dessen Eigentümer einen bezahlten Tarif hat. Diese Löschung archiviert nicht vorher, sondern löscht direkt über die genannte Kette. Das Firmenlogo fällt mit dem Konto, als letzter Schritt der Löschung. |
| Firmenlogo (seit 07.10.2026) | Der Kunde kann in den Einstellungen ein Logo hochladen (PNG, JPEG, WebP). Gespeichert wird nicht die angelieferte Datei, sondern ein auf dem Server neu gezeichnetes Bild, außerhalb des Webverzeichnisses (daten/firmenlogos/, Migration 184). Sichtbar ist es dem Konto selbst, dem Superadmin, den Mitgliedern der Workspaces, deren Eigentümer das Konto ist, und Eingeladenen über den Einladungslink, solange die Einladung offen ist; alle anderen Abrufe erhalten dieselbe Antwort wie bei einem fehlenden Logo. |
| Kontoexport (Art. 15 Abs. 3, Art. 20 DSGVO) | Der Kontoinhaber kann in den Einstellungen nach Eingabe seines Passworts ein ZIP-Archiv mit den Daten seines Kontos als JSON und dem Firmenlogo herunterladen. Die Tabellen werden aus dem Schema ermittelt (Spalten, die auf das Konto verweisen); Geheimnisse wie Passwort-Hash, Token und das TOTP-Geheimnis fallen heraus. Fehlversuche werden im Änderungsprotokoll gezählt und sperren den Export nach fünf Versuchen in 15 Minuten. Das Archiv entsteht nur als temporäre Datei für die Auslieferung. |
| Weitere Kontodaten (Stand 16.10.2026) | legal_acceptances: Annahme der Vertragsunterlagen (einschließlich Widerrufsbelehrung und Verlangen nach sofortigem Beginn) und zugestellte Mitteilungen über Änderungen, je mit Konto, vollständiger IP-Adresse, Browserkennung, Sprache, Prüfsummen der Fassungen und Herkunft des Eintrags; die jüngste Zustimmung (nicht die Mitteilungen) eines bestehenden Kontos bleibt erhalten, solange das Konto besteht, damit sich belegen lässt, welcher Fassung ein laufender Kunde zugestimmt hat (seit 16.10.2026); ältere Zustimmungen, Mitteilungen und die Zeilen gelöschter Konten werden 730 Tage nach der jeweiligen Zustimmung bzw. Mitteilung gelöscht (Einordnung der Rechtsgrundlage für die Aufbewahrung nach dem Ende des Kontos durch den Verantwortlichen offen). report_subscriptions: Abonnement des Wochenberichts mit Abmeldetoken und letztem Versand; fällt mit dem Konto. workspace_transfers: Übertragung eines Workspace an eine E-Mail-Adresse mit Token und Ablauf; fällt mit dem Workspace. mp_dashboards: eigene Dashboards eines Kontos je Projekt; fallen mit Konto oder Projekt. Unternehmens-SSO (sso_providers, sso_identities, sso_requests, sso_assertions, sso_policies, Migrationen 187 und 188): die Konfiguration des vom Workspace-Eigentümer gewählten Identitätsanbieters verschlüsselt, je Konto nur ein Hash der Kennung beim Anbieter, Anmeldeanfragen fünf Minuten gültig; der Server ruft dabei die Endpunkte dieses Anbieters ab, Empfänger ist der vom Kunden gewählte Anbieter. Stand 16.10.2026 ist bei keinem Workspace ein Anbieter eingerichtet. Aufnahme-Kontingent (mp_aufnahme_monat, mp_aufnahme_sitzung, Migration 178): Zähler je Eigentümer und Monat, je Sitzung nur ein Hash aus Projekt und Sitzungskennung; die Hashes vergangener Monate löscht ein täglicher Lauf, die Zähler fallen mit dem Konto. |
B.2 Zugriffs-, Sicherheits- und Änderungsprotokolle des Portals
| Feld | Eintrag |
| Zweck | Zugriffs-, Sicherheits- und Änderungsprotokollierung für das eigene Portal von MousePlayer. |
| Kategorien betroffener Personen | Besucher und Nutzer von mouseplayer.com und www.mouseplayer.com. |
| Kategorien personenbezogener Daten | VOLLE IP-Adresse, User-Agent, vollständiger Anfragepfad, Land, Stadt, Gerätetyp, Betriebssystem, Browser, ASN. Sicherheitsereignisse mit teilweise gekürzter IP: WSS_CONNECT 1261, url_excluded 71, consent_blocked 24. Änderungsprotokoll: Nutzer, Workspace, Aktion, Ziel, Details als JSON, IP. |
| Wo gespeichert | mouseplayer_logs (log_id, ip_address, user_agent, page_url, created_at, country_code, asn_number, asn_org, city, device_type, os_name, browser_name) — am 10.08.2026 36409 Zeilen, 8,5 MB, ohne gekürzte IP-Werte. Seit dem 17.08.2026 legt log_mouseplayer_traffic() (cfg/lib.php) je Aufruf nur eine Rohzeile in die Redis-Warteschlange queue:traffic_logs; GeoIP- und ASN-Auflösung, Einordnung von Browser und Gerät sowie das Schreiben — samt users.last_ip und der Standortfelder des Kontos — übernimmt der db_worker. Die Adresse bestimmt getBestClientIP(); Kopfzeilen werden nur geglaubt, wenn die Verbindung vom vorgeschalteten nginx kommt. security_access_logs (id, ip_address, user_agent, event_type, details, created_at) — am 10.08.2026 1354 Zeilen, davon 350 gekürzt. audit_logs (log_id, user_id, workspace_id, action, target_id, details, ip_address, created_at) — am 10.08.2026 666 Zeilen, ungekürzt. banned_ips (ip_address, scope, reason, banned_at, expires_at). |
| Rechtsgrundlage | Im Code nicht ausgewiesen. Die einzige festgehaltene Begründung ist der Kommentar in class/Server.class.php:421-425, der Regel A (volle Adresse, für DIREKTE Zugriffe auf die eigene Anwendung) von Regel B (gekürzt, für Besucherdaten) unterscheidet. Das erklärt die Entwurfsentscheidung, ist aber keine Rechtsgrundlage. Art. 6 Abs. 1 Buchstabe f. Zweck: Missbrauchsabwehr und Nachvollziehbarkeit (bestätigt vom Verantwortlichen, 17.08.2026). Abwägung: Ohne Protokoll lässt sich weder ein Angriff erkennen noch nachträglich feststellen, wer eine Änderung vorgenommen hat. Ein milderes Mittel, das dasselbe leistet, gibt es nicht — ein anonymisiertes Protokoll verliert genau die Zuordnung, um die es geht. Der Eingriff wird über die Frist begrenzt (72 Stunden für das Sicherheitsprotokoll, 60 Tage für das Zugriffsprotokoll, 60 Tage für das Änderungsprotokoll) und dadurch, dass die Protokolle ausschließlich Zugriffe auf die eigene Anwendung betreffen und nicht die aufgezeichneten Besucher. Betroffen sind Kundennutzer, die den Dienst bewusst nutzen und mit einer Protokollierung ihrer Verwaltungshandlungen rechnen. |
| Kategorien von Empfängern | MousePlayer selbst. audit_logs ist zusätzlich für den Superadmin sichtbar (www/admin.php). |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | mouseplayer_logs: 60 Tage. security_access_logs: 72 Stunden. banned_ips: bei Ablauf von expires_at; von Hand gesetzte Einträge ohne Ablauf bleiben, bis der Betreiber sie aufhebt. audit_logs: 60 Tage, neu seit dem 17.08.2026. user_ip_history: 90 Tage ab dem letzten Auftreten einer Adresse, neu seit dem 24.09.2026; spätestens mit dem Konto. Alle Werte stehen in site_settings und sind im Administrationsbereich einstellbar. Dass das Änderungsprotokoll länger steht als das Sicherheitsprotokoll, ist gewollt: das Zugriffsprotokoll beantwortet, wer da war; das Änderungsprotokoll, wer etwas verändert hat. Letzteres ist der Nachweis nach Art. 5 Abs. 2 und muss einen Streit überleben, der erst Monate später aufkommt. |
B.3 Supportanfragen
| Feld | Eintrag |
| Zweck | Entgegennahme und Bearbeitung von Supportanfragen. Seit 30.09.2026 gehört dazu, eine Nachricht von einem Sprachmodell auf eigener Hardware übersetzen und einen Antwortentwurf vorbereiten zu lassen; jeden Entwurf prüft und verschickt eine Person. |
| Kategorien betroffener Personen | Anfragende Personen, angemeldet oder nicht. |
| Kategorien personenbezogener Daten | E-Mail-Adresse, Anliegen, Freitext der Nachricht. VOLLE IP-Adresse — REMOTE_ADDR, überschrieben mit HTTP_X_FORWARDED_FOR, ohne Kürzung. User-Agent, Herkunfts-URL. Das Feld für ein Länderkennzeichen wird aus der Kopfzeile HTTP_CF_IPCOUNTRY gelesen; da kein Cloudflare vorgeschaltet ist, steht dort stets der Ersatzwert XX oder nichts. |
| Wo gespeichert | support_requests (id, user_id, channelid, email, reason, message, status, ip_address, user_agent, source_url, country_code, created_at). Seit 30.09.2026 zusätzlich mp_support_ki: je Auftrag (Übersetzung, Entwurf, Übersetzung des eigenen Entwurfs) eine Zeile mit dem für das Modell vorbereiteten Text, dem Ergebnis, dem Modellnamen und der Dauer; per Fremdschlüssel an die Anfrage gebunden. |
| Rechtsgrundlage | Art. 6 Abs. 1 Buchstabe b, soweit die anfragende Person Kunde ist und die Anfrage die Durchführung des Vertrags betrifft; sonst Art. 6 Abs. 1 Buchstabe f. Auf dieselbe Grundlage wird die vollständige IP-Adresse gestützt: sie dient der Abwehr von Missbrauch des Supportkanals. Massenhafte oder wiederholte Zusendungen, Drohungen und sonstige Benachteiligungen lassen sich ohne sie weder erkennen noch unterbinden, und eine gekürzte Adresse trägt diese Unterscheidung nicht. Entscheidung des Verantwortlichen vom 17.08.2026. |
| Kategorien von Empfängern | Bis 11.08.2026: Telegram. cfg/lib.php sandte Nutzerstatus, E-Mail-Adresse, Thema, die UNGEKÜRZTE IP-Adresse mit Land, die Herkunfts-URL und den vollständigen Nachrichtentext an api.telegram.org. Seit 11.08.2026: keine. An api.telegram.org geht nur noch die feste Zeichenkette 'MousePlayer: es liegt eine neue Supportanfrage vor.', ohne jede Variable; Telegram erhält damit keine personenbezogenen Daten und ist kein Empfänger. Die Anfrage bleibt unverändert in support_requests. Sprachmodell (seit 30.09.2026): keiner. Es läuft auf eigenen Rechnern mit Grafikkarte, im selben lokalen Netz und am selben Ort wie der Server; sie holen den Auftrag über HTTPS ab, jede Anfrage mit eigenem Geheimnis signiert. Sie erhalten den Nachrichtentext, das Anliegen, ob die anfragende Person ein Konto hat, und den Pfad der Herkunftsseite – E-Mail-Adressen und Ziffernfolgen ab sechs Stellen werden vorher ersetzt (mp_supki_saeubern() in cfg/support_ki_lib.php), im eigenen Entwurf nur E-Mail-Adressen. Nicht die IP-Adresse, nicht die E-Mail-Adresse der anfragenden Person. Kein externer KI-Dienst, auch nicht als Rückfall. |
| Drittlandübermittlung | Bis 11.08.2026: Telegram, außerhalb der EU; für Bots ist kein Auftragsverarbeitungsvertrag verfügbar — siehe Abschnitt 4. Seit 11.08.2026: keine. Die Benachrichtigung an api.telegram.org enthält keine personenbezogenen Daten mehr, eine Übermittlung in ein Drittland findet daher nicht mehr statt. Der Kanal besteht als reines Signal fort — siehe Abschnitt 4. |
| Automatisierte Entscheidung | Keine. Das Modell schlägt nur Text vor; verschickt wird nichts von selbst – eine Person liest den Entwurf, ändert ihn bei Bedarf und verschickt ihn. Keine Entscheidung im Sinne von Art. 22 DSGVO. |
| Aufbewahrung | 730 Tage, durchgesetzt vom täglichen Lauf in srv/db_worker.php; der Wert steht in site_settings unter retention_evidence_days und ist im Administrationsbereich einstellbar. Bei einer Kontolöschung bleibt die Anfrage bestehen, verliert aber ihren Bezug zum Konto (user_id wird NULL); die Datenschutzerklärung sagt das ausdrücklich. Zeilen in mp_support_ki fallen mit ihrer Anfrage (ON DELETE CASCADE, Migration 168), über jeden Löschweg. |
B.4 Annahme der regionsbezogenen Aufzeichnungsregeln durch den Kunden
| Feld | Eintrag |
| Zweck | Nachweis, dass der Kunde die regionsbezogenen Aufzeichnungsregeln angenommen hat — eine vertragliche Erklärung. |
| Kategorien betroffener Personen | Kundennutzer. |
| Kategorien personenbezogener Daten | Nutzer-ID, E-Mail, Regionen, Textversion, Textprüfsumme, Sprache. VOLLE IP-Adresse und User-Agent — bewusst, und der Grund ist in ai/migrations/018_consent.sql festgehalten: Das ist die Vertragsannahme eines Geschäftspartners, kein Besucherdatum. |
| Wo gespeichert | consent_region_acceptances (id, channelid, workspace_id, user_id, user_email, regions, text_version, text_checksum, text_lang, ip_address, user_agent, accepted_at) — 0 Zeilen. |
| Rechtsgrundlage | Nachweis einer vertraglichen Erklärung, so im Kopf der Migration begründet. |
| Kategorien von Empfängern | MousePlayer selbst. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | 730 Tage ab der Annahme — dieselbe Frist wie für die übrigen Nachweise (support_requests, legal_acceptances; bei legal_acceptances bleibt die jüngste Zustimmung eines bestehenden Kontos darüber hinaus erhalten, siehe B.1), weil sie dieselbe Frage beantworten: was hat wer wann zugesagt. Der Wert steht in site_settings unter retention_evidence_days; durchgesetzt vom täglichen Lauf in srv/db_worker.php. |
B.5 Besucher unserer eigenen Website
| Feld | Eintrag |
| Zweck | Betrieb von mouseplayer.com selbst: Einwilligungsdialog, Abwehr automatisierter Zugriffe, die Demonstration auf der Startseite und die Protokolle des Webservers. |
| Kategorien betroffener Personen | Besucher von mouseplayer.com. |
| Kategorien personenbezogener Daten | IP-Adresse — in den Serverprotokollen ungekürzt —, Zeitpunkt, angeforderte Adresse, Statuscode, Browserkennung. Für die Demonstration zusätzlich Zeiger- und Klickpositionen, eine zufällig vergebene Sitzungskennung und das aus der Adresse abgeleitete Land. Für reCAPTCHA Adresse sowie Geräte- und Verhaltensmerkmale. |
| Wo gespeichert | Zugriffsprotokolle von nginx (/var/log/nginx/) und Apache, beide mit voller Adresse, logrotate täglich mit 14 Rotationen. Seit dem 16.08.2026 ist nginx die erste Schicht, die eine Besucheradresse sieht; Apache steht dahinter auf dem Loopback und bekommt sie über das PROXY-Protokoll beziehungsweise X-Forwarded-For gereicht. Die Daten der Demonstration werden nicht gespeichert, sondern nur im Augenblick weitergereicht. |
| Rechtsgrundlage | Demonstration: Einwilligung, Art. 6 Abs. 1 Buchstabe a — der Riegel dafür ist seit dem 17.08.2026 gebaut. reCAPTCHA und Serverprotokolle: berechtigtes Interesse, Art. 6 Abs. 1 Buchstabe f. Art. 6 Abs. 1 Buchstabe f. Zweck: Missbrauchsabwehr und Nachvollziehbarkeit (bestätigt vom Verantwortlichen, 17.08.2026). reCAPTCHA: Ohne Schutz gegen automatisierte Zugriffe stehen Anmeldung, Registrierung, Supportformular und Abrechnungsseite Angriffen offen. Das mildere Mittel — eine reine Ratenbegrenzung — ist seit dem 17.08.2026 zusätzlich vorhanden, ersetzt die Bewertung aber nicht vollständig. Serverprotokolle: Die ungekürzte Adresse ist erforderlich, um wiederholte oder massenhafte Zugriffe demselben Absender zuzuordnen; eine gekürzte Adresse trägt diese Unterscheidung nicht. Der Eingriff wird durch die Frist von 14 Tagen begrenzt und dadurch, dass die Protokolle nicht mit anderen Daten zusammengeführt werden. |
| Kategorien von Empfängern | Google Ireland Limited (reCAPTCHA) und consented.eu (Einwilligungsdialog). Bei der Demonstration zusätzlich die übrigen Besucher, die die Startseite im selben Augenblick geöffnet haben — sie sehen den Zeiger und das Land, nicht die Adresse. |
| Drittlandübermittlung | Vereinigte Staaten über reCAPTCHA; Grundlage und Annahmedatum siehe Abschnitt 4. |
| Aufbewahrung | Serverprotokolle 14 Tage. Die Demonstration speichert nichts. |
Dieser Eintrag fehlte bis zum 17.08.2026, obwohl Abschnitt 4 den Einwilligungsdialog und reCAPTCHA als Empfänger bereits nannte — die zugehörige Verarbeitung stand nirgends. Die öffentliche Datenschutzerklärung ist am selben Tag um denselben Gegenstand ergänzt worden (Abschnitt 10 dort); beide Texte sind gegeneinander zu lesen.
B.6 Abrufe eines Freigabe-Links
| Feld | Eintrag |
| Zweck | Nachweis, wie oft und von wo ein Freigabe-Link benutzt wurde. Ein solcher Link öffnet eine vollständige Aufzeichnung ohne Anmeldung; ohne dieses Protokoll lässt sich hinterher weder feststellen, wie oft er benutzt wurde, noch ob er den vorgesehenen Kreis verlassen hat. |
| Kategorien betroffener Personen | Personen, die einen Freigabe-Link öffnen — in der Regel Mitarbeiter des Kunden oder von ihm ausgewählte Empfänger. Nicht die aufgezeichneten Besucher; das sind zwei verschiedene Personen. |
| Kategorien personenbezogener Daten | IP-Adresse des Abrufenden (ungekürzt), Browserkennung, Zeitpunkt, Kennung des Links. |
| Wo gespeichert | share_views (Migration 043), verknüpft mit session_shares über einen Fremdschlüssel mit ON DELETE CASCADE. |
| Rechtsgrundlage | Art. 6 Abs. 1 Buchstabe f. Zweck: Missbrauchsabwehr — ein Link ohne Anmeldung ist genau die Art von Adresse, die weitergereicht wird. Abwägung: Ein milderes Mittel gibt es nicht: eine gekürzte Adresse trägt die Frage nicht, ob zwei Abrufe von derselben Stelle kommen, und ohne sie ist eine Weitergabe weder erkennbar noch belegbar. Der Eingriff ist eng begrenzt — er trifft nicht die aufgezeichnete Person, sondern den Abrufenden, und die Zeile stirbt mit dem Link. Betroffen sind Personen, die einen Link zu einer fremden Aufzeichnung öffnen und mit einer Protokollierung dieses Zugriffs rechnen müssen. (Entscheidung des Verantwortlichen, 17.08.2026) |
| Kategorien von Empfängern | Keine. Das Protokoll verlässt die eigene Datenbank nicht. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | Mit dem Link. Läuft er ab oder wird er zurückgenommen, geht das Protokoll über den Fremdschlüssel mit. Ein Link lebt höchstens 90 Tage, voreingestellt 7 — länger kann die Anwendung ihn nicht erzeugen. |
Dass die Zeile mit dem Link stirbt, ist hier kein Komfort, sondern die halbe Rechtsgrundlage: ein Protokoll, das den Link überlebt, hat keinen Zweck mehr, der es trägt.
B.7 Aktive Anmeldungen und ihr Widerruf
| Feld | Eintrag |
| Zweck | Dem Kontoinhaber zeigen, wo sein Konto angemeldet ist, und ihm erlauben, ein einzelnes Gerät oder alle übrigen zu beenden. Ohne diese Liste ist eine übernommene Anmeldung weder erkennbar noch beendbar: Bis zum 28.08.2026 entwertete ein Passwortwechsel nur die „Angemeldet bleiben“-Cookies, während die laufenden Sitzungen als Dateien weiterlebten — gemessen 24 bis 54 Minuten. |
| Kategorien betroffener Personen | Inhaber und Mitglieder eines Kundenkontos. Nicht die aufgezeichneten Besucher; das sind zwei verschiedene Personen. |
| Kategorien personenbezogener Daten | IP-Adresse (ungekürzt), Browserkennung, daraus abgeleitet Browser, Betriebssystem und Geräteart, Grobstandort (Stadt und Land) aus der Adresse, Zeitpunkt der Anmeldung und der letzten Aktivität. Die Sitzungskennung selbst wird nicht gespeichert, sondern nur ihr SHA-256-Hash. Dazu ein Geräteabdruck — ein Hash aus Browser, Betriebssystem, Geräteart und Adressbereich (/24 bzw. /48, nie der vollen Adresse), an dem ein schon bekanntes Gerät wiedererkannt wird. |
| Wo gespeichert | login_sessions (Migration 094), über remember_selector verknüpft mit remember_tokens (Migration 037). |
| Rechtsgrundlage | Art. 6 Abs. 1 Buchstabe b in Verbindung mit Art. 32. Zweck: Sicherheit des Kontos — die Verarbeitung ist die technische Maßnahme, nicht ihr Nebenprodukt. Abwägung: Ein milderes Mittel gibt es nicht. Eine gekürzte Adresse beantwortet gerade die Frage nicht, für die die Liste da ist („war das ich?“), und ohne Browser und Ort ist eine Zeile von der anderen nicht zu unterscheiden. Die Daten fallen bei jeder Anmeldung ohnehin an; neu ist allein, dass sie sichtbar und widerrufbar werden. Sichtbar sind sie ausschließlich dem Kontoinhaber selbst. |
| Kategorien von Empfängern | Keine. Die Liste verlässt die eigene Datenbank nicht. |
| Drittlandübermittlung | Keine. |
| Aufbewahrung | 90 Tage ab der letzten Aktivität, dazu vollständig mit dem Ende des Kontos. Verankert an der letzten Aktivität und nicht am Anlegen: ein Gerät, das seit Monaten angemeldet ist und gestern benutzt wurde, ist eine aktuelle Anmeldung und gehört in die Liste. |
Seit dem 28.08.2026 entsteht aus denselben Daten zusätzlich eine Benachrichtigung an den Kontoinhaber, wenn sein Konto von einem Gerät aus geöffnet wird, das noch nicht in Erscheinung getreten ist. Sie geht an die hinterlegte Adresse des Betroffenen selbst und an niemanden sonst; ein Empfänger im Sinne von Art. 4 Nr. 9 kommt dadurch nicht hinzu. Jedes Konto kann sie in den Einstellungen abschalten, ohne dass die Liste selbst entfällt — die Voreinstellung ist an, weil eine Sicherheitsmeldung, die man erst einschalten muss, gerade die nicht erreicht, die sie braucht. Der Abdruck stützt sich bewusst auf den Adressbereich statt auf die volle Adresse: ein Anschluss erhält beim nächtlichen Neuaufbau eine andere IP, und mit der vollen Adresse käme jeden Morgen eine Meldung — das Merkmal wäre entwertet und die Meldung damit auch.
Zwei Entscheidungen daran sind erklärungsbedürftig. Gespeichert wird der Hash der Sitzungskennung und nie sie selbst: ein Datenbankauszug gäbe sonst gültige Sitzungs-Cookies her, und ein Auszug in falschen Händen ist genau der Fall, gegen den die ganze Tabelle gebaut ist. Und eine widerrufene Zeile wird nicht gelöscht, sondern als widerrufen markiert — eine gelöschte Zeile wäre für die Prüfung bei jedem Aufruf eine unbekannte Sitzung, und eine unbekannte kann unter Umständen nachgetragen werden. Der Widerruf hätte sich selbst aufgehoben.
B.8 Betriebsmeldungen und zurückgehaltene E-Mails (urgent_logs)
| Feld | Eintrag |
| Zweck | Betriebsmeldungen für den Superadmin: Störungen, die die Wächter in srv/cron_status.php feststellen, Zweifelsfälle der Bot-Nachkontrolle (A.19), auf Wahl des Superadmins die Auffälligkeiten eines Projekts statt einer E-Mail, sowie ausgehende E-Mails, die eine Sperrliste zurückhält. Die Sperre verhindert, dass E-Mails an eingetragene eigene Adressen oder an reservierte Test- und Beispieldomains hinausgehen; die zurückgehaltene E-Mail wird hier abgelegt, damit nachvollziehbar bleibt, was versandt worden wäre. |
| Kategorien betroffener Personen | Kundennutzer und andere Empfänger einer zurückgehaltenen E-Mail; mittelbar Besucher, deren Sitzungskennung in einer Meldung der Bot-Nachkontrolle steht. |
| Kategorien personenbezogener Daten | Quelle, Betreff, Meldungstext, Zeitpunkte von Entstehung, letzter Wiederholung, Erledigung und Mailversand. Bei einer zurückgehaltenen E-Mail die Empfängeradresse und der vollständige Text der E-Mail als Klartext — je nach Art etwa Name und E-Mail-Adresse, bei einer Anmeldemeldung zusätzlich IP-Adresse, Gerät und ungefährer Ort. |
| Wo gespeichert | urgent_logs (id, quelle, betreff, meldung, erstellt_am, zuletzt_am, erledigt_am, mail_status, mail_am, stoerung_beendet_am). |
| Rechtsgrundlage | Art. 6 Abs. 1 Buchstabe f. Zweck: Betriebssicherheit und Nachvollziehbarkeit des E-Mail-Versands. Die Meldungen sind nur dem Superadmin zugänglich und werden nach der Erledigung befristet gelöscht. |
| Kategorien von Empfängern | Der Superadmin. Störungsmeldungen gehen zusätzlich per E-Mail an die Alarmadresse des Betreibers (über Namecheap Private Email, Abschnitt 4); eine zurückgehaltene E-Mail geht an niemanden. |
| Drittlandübermittlung | Keine; für den Versand an die Alarmadresse siehe Namecheap in Abschnitt 4. |
| Aufbewahrung | Eine Zeile bleibt, bis sie erledigt ist — durch den Wächter, sobald die Störung behoben ist, oder von Hand; eine zurückgehaltene E-Mail wird nie von selbst erledigt. Erledigte Zeilen löscht der Statuswächter 180 Tage nach der Erledigung (site_settings.retention_urgent_days, im Administrationsbereich einstellbar, mindestens 7 Tage). |
6. Aufbewahrung — was der tägliche Löschlauf erfasst und was nicht
Es gibt eine automatische Löschung, und sie erfasst seit dem 17.08.2026 alle Tabellen mit personenbezogenen Daten, entweder über eine eigene Frist oder über die Löschkette der Sitzung. Der Kern steht in srv/db_worker.php im Block mit der Marke DAILY DATA PRUNING und läuft innerhalb des dauerhaft laufenden Worker-Prozesses einmal je Kalendertag (gesteuert über $lastPurgeDate). Eigene Takte im selben Prozess haben die Fristen für Bot-Sitzungen (stündlich), die endgültige Löschung archivierter Einträge (alle 30 Sekunden) und die Löschverlangen der Selbstauskunft. Geplante Aufgaben laufen seit dem 07.10.2026 aus /etc/cron.d/mouseplayer über srv/cron_run.sh mit einer Sperre je Aufgabe, darunter die Auslagerung der Ereignisse ins Archiv (stündlich) und die Pflege des Textindex (alle zehn Minuten); das Tagesaggregat der Klickkarte wird nächtlich gebaut.
Beleg, dass sie läuft (Stand 16.10.2026): Das Protokoll des Workers verzeichnet den Tageslauf täglich, zuletzt am 16.10.2026 um 00:00:11 mit Abschluss zehn Sekunden später, und die stündliche Frist für Bot-Sitzungen mit gelöschten Sitzungen und Zeilen (etwa um 10:00:18 desselben Tages 478 Sitzungen mit 3294 Zeilen). Die Tariffrist hatte bis zu diesem Tag nichts zu löschen: die Projekte mit älteren Sitzungen stehen auf dem Enterprise-Tarif (365 Tage), und die ältesten Sitzungen im freien Tarif sind jünger als dessen Frist. Ob ein geplanter Lauf scheitert oder ausbleibt, prüft der Cron-Wächter in srv/cron_status.php und meldet es in Urgent Logs (B.8) und per E-Mail.
6.1 Vom täglichen Löschlauf erfasst
| Tabelle | Auslöser und Frist | Beleg |
| mouseplayer_logs | Älter als 60 Tage (site_settings.log_retention_days) | srv/db_worker.php, DAILY DATA PRUNING |
| security_access_logs | Älter als 72 Stunden (site_settings.security_log_retention_hours) | srv/db_worker.php, DAILY DATA PRUNING |
| banned_ips | expires_at liegt in der Vergangenheit; Einträge ohne expires_at bleiben bis zur Aufhebung durch den Betreiber | srv/db_worker.php, DAILY DATA PRUNING |
| visitor_sessions und alles, was daran hängt (mouse_events, session_pageviews, session_custom_events samt Parametern und die übrigen Tabellen der Löschkette) | Je Sitzung, sobald die Tariffrist abgelaufen ist: free 7 Tage, small 30, business 90, enterprise IFNULL(enterprise_custom_tiers.retention_days, 365). Sonderfall free + is_suspicious = 24 Stunden. Schonfrist nach einem Downgrade über GREATEST(...) mit users.retention_grace_until und retention_grace_days. Gelöscht über mp_sitzungen_loeschen(). | srv/db_worker.php, DAILY DATA PRUNING |
| payload_blob und mouse_events von Bot-Sitzungen | Die Aufzeichnung einer als Bot erkannten Sitzung wird nach Ablauf der Frist geleert (site_settings.retention_bot_recording_days, Frist in Tagen: 1; 0 schaltet ab) | srv/db_worker.php, stündlich |
| visitor_sessions von Bot-Sitzungen samt allem, was daran hängt | 14 Tage nach Beginn der Sitzung (site_settings.retention_bot_session_days, mindestens 8; 0 = keine eigene Frist) | srv/db_worker.php, stündlich, mp_sitzungen_loeschen() |
| mouse_events → Archivdateien | nach 7 Tagen in komprimierte Archivdateien je Sitzung ausgelagert; die Dateien fallen mit ihrer Sitzung | srv/cron_archiv.php (stündlich), mp_sitzungen_loeschen() |
6.2 Was seit dem 17.08.2026 zusätzlich erfasst wird
An dieser Stelle stand eine Liste von dreizehn Tabellen ohne jede Frist. Sie ist erledigt. Fünf Tabellen stehen seit dem 12.08.2026 in der gemeinsamen Löschkette mp_sitzungen_loeschen(), sechs weitere haben am 17.08.2026 eine eigene Frist bekommen, und zwei kannte die Liste noch gar nicht: die je Besucher und Tag gebildete Bewertung und die daraus erzeugten Texte.
Die Zahlen in der folgenden Tabelle sind keine Abschriften. Sie werden beim Aufruf dieser Seite aus site_settings gelesen — aus derselben Zeile, aus der auch der Löschlauf liest — und sind im Administrationsbereich einstellbar. Eine abgeschriebene Zahl wäre ein zweiter Ort für dieselbe Wahrheit und liefe irgendwann auseinander.
| Tabelle | Frist | Wer sie durchsetzt |
| ai_session_features | mit der Sitzung | mp_sitzungen_loeschen() |
| ai_timelines | mit der Sitzung | mp_sitzungen_loeschen() |
| session_comments | mit der Sitzung | mp_sitzungen_loeschen() |
| session_shares | mit der Sitzung; der Link selbst läuft nach höchstens 90 Tagen ab, voreingestellt 7; die Zeile eines abgelaufenen oder zurückgenommenen Links wird 90 Tage danach gelöscht, die Abrufe in share_views fallen mit | mp_sitzungen_loeschen(), mp_share_erstellen(), täglicher Lauf |
| visitor_nicknames | mit der letzten Sitzung des Besuchers — seit dem 28.08.2026 gilt das auch für den vom Verantwortlichen vergebenen Namen (A.13), der in derselben Zeile steht | mp_sitzungen_loeschen() |
| ai_visitor_value | 60 Tage ab dem bewerteten Tag; bei Enterprise die Frist des Tarifs. Zusätzlich mit dem Besucher, sobald ihm keine Sitzung mehr bleibt | täglicher Lauf, mp_sitzungen_loeschen() |
| ai_insights (Bereich „visitor“) | ebenso | täglicher Lauf, mp_sitzungen_loeschen() |
| consent_events | 730 Tage ab dem Widerruf — nie, solange eine Sitzung darauf verweist | täglicher Lauf |
| ip_lifetime_stats | 365 Tage ab first_seen | täglicher Lauf |
| audit_logs | 60 Tage | täglicher Lauf |
| support_requests | 730 Tage | täglicher Lauf |
| consent_region_acceptances | 730 Tage | täglicher Lauf |
| legal_acceptances | 730 Tage nach der Zustimmung bzw. Mitteilung; die jüngste Zustimmung eines bestehenden Kontos bleibt, solange das Konto besteht (seit 16.10.2026) | täglicher Lauf |
| user_ip_history | 90 Tage ab dem letzten Auftreten der Adresse; spätestens mit dem Konto | täglicher Lauf |
| users (einschließlich last_ip), workspace_users, workspace_invites | mit dem Konto; ohne Anmeldung nach 24 Monaten und einer Warnfrist von 30 Tagen | mp_konto_loeschung_ausfuehren(), täglicher Lauf |
| heatmap_page_stats | entfällt — die Tabelle ist seit dem 18.08.2026 abgebaut (Migration 045) | — |
| mp_profil_sitzung | 180 Tage ab dem BEGINN der Sitzung, mindestens das Rechenfenster; ganz ohne Frist, sobald die Sitzung selbst fehlt | täglicher Lauf, mp_sitzungen_loeschen() |
| mp_profile, mp_sequenzmuster | mp_profile, sobald ihm keine Zuordnung mehr bleibt; mp_sequenzmuster nach 180 Tagen ohne Nachrechnung und sofort, sobald sein Kanal keine Sitzung mehr hat | täglicher Lauf |
| ga4_daily, ga4_sessions, ga4_events | 180 Tage ab dem beschriebenen Tag beziehungsweise ab dem Beginn der GA4-Sitzung — nicht ab dem Importzeitpunkt (A.14) | täglicher Lauf |
| mp_hm_tag, mp_hm_tag_stand | keine eigene Frist: ein gespeicherter Tag wird spätestens 7 Tage nach seiner letzten Berechnung beim nächsten Öffnen der Liste aus den noch vorhandenen Sitzungen neu gerechnet; Tage vor der ältesten verbliebenen Sitzung des Projekts fallen dabei weg; alles mit dem Projekt (A.8) | beim Öffnen der Heatmap-Liste; mp_konto_loeschen() |
| mp_umfrage_text | mit der Sitzung (A.21) — eine eigene Frist gibt es bewusst nicht | mp_sitzungen_loeschen(), Löschweg des Players, mp_konto_loeschen() |
| mp_loesch_archiv, mp_loesch_archiv_sitzung | archivierte Konten, Workspaces, Projekte und archivierte Besucher oder IP-Adressen (DSGVO-Löschung): höchstens 30 Tage, dann endgültig gelöscht. Danach bleibt ein Nachweis ohne Bezeichnung – bei Besuchern und IP-Adressen ein HMAC der Kennung, damit sich die Löschung nach dem Zurückspielen einer Sicherung wiederholen lässt, bei Konten gar keine Kennung –, der nach 730 Tagen entfällt | db_worker, alle 30 Sekunden |
| mp_hm_klick_tag, mp_hm_ansicht_tag | 730 Tage ab dem Tag, den die Zeile beschreibt; mit dem Projekt sofort. Keine Löschung je Person: die Zeilen tragen keinen Personenbezug (A.1) | srv/hm_aggregat_lauf.php, mp_konto_loeschen() |
| mouse_events_analytik | mit der Seitenansicht – seit dem 07.10.2026 auch auf allen Wegen, die einzelne Sitzungen löschen; vorher nur mit dem ganzen Projekt (A.8) | mp_sitzungen_loeschen(), Löschweg des Players, mp_konto_loeschen() |
| login_sessions | 90 Tage ab der letzten Aktivität; vollständig mit dem Konto (B.7) | täglicher Lauf, Kontolöschung |
| share_views | mit dem Freigabe-Link, über den Fremdschlüssel mit ON DELETE CASCADE (B.6) | Fremdschlüssel |
| ai_churn | bei jedem Lauf je Projekt neu geschrieben; fällt mit den Sitzungen, aus denen die Zeile stammt (A.16) | srv/ai_worker.php |
| ai_besucher_bericht | 180 Tage ab Anforderung; früher mit der letzten Sitzung des Besuchers (A.17) | Nachlauf in srv/ai_worker.php |
| mp_cwv, mp_element_klicks, mp_element_offen | mit der Sitzung bzw. Seitenansicht; Zeilen, deren Seitenansicht fehlt, werden stündlich entfernt (A.7, A.20) | mp_sitzungen_loeschen(), srv/cwv_nachtragen.php, srv/element_worker.php |
| mp_text_block, mp_text_pv, mp_text_stand | 30 Tage ab Beginn der Seitenansicht; früher mit der Sitzung (A.22) | srv/textsuche_lauf.php, mp_sitzungen_loeschen() |
| bot_review_labels | Vorgabe: keine automatische Löschung; in Jahren einstellbar (retention_bot_labels_years) (A.19) | srv/cron_status.php |
| urgent_logs | 180 Tage nach der Erledigung (site_settings.retention_urgent_days) (B.8) | srv/cron_status.php |
| mp_aufnahme_quittung | 7 Tage (A.1) | srv/db_worker.php |
| mp_native_apps, mp_native_sessions | bis zum Ablauf der je Sitzung gesetzten Frist oder bis zum Widerruf; die Vorschau ist abgeschaltet und nur auf dem Entwicklungssystem vorhanden (A.1) | cfg/native_store.php |
Zwei Punkte, die dabei gemessen und nicht angenommen wurden. Erstens läuft der tägliche Lauf wirklich. Hier stand zeitweise, er sei nie gelaufen; belegt ist der Lauf vom 17.08.2026 um 17:37:09 im Protokoll des Workers. Er löschte an jenem Tag nichts, weil die beiden Projekte mit Sitzungen auf dem Enterprise-Tarif stehen und die älteste Sitzung 27 Tage alt war — das ist der bestimmungsgemäße Zustand und kein Ausfall. Zweitens ist die Frist der abgeleiteten Bewertung an dem Tag verankert, den die Zeile beschreibt, und nicht an ihrem Berechnungszeitpunkt. Gemessen trugen 167 Zeilen 28 verschiedene beschriebene Tage, aber nur 6 verschiedene Berechnungszeitpunkte, den jüngsten von wenigen Minuten zuvor: die Vorberechnung rechnet nach, und jedes Nachrechnen hätte eine daran hängende Frist zurückgesetzt. Sie wäre nie abgelaufen, ohne dass es jemand bemerkt hätte.
6.3 Befunde zur Löschkette (Stand 16.10.2026)
- DIE KETTE LÄUFT IM BETRIEB. Am 10.08.2026 war sie noch nie gelaufen, und hier stand deshalb, sie sei ungeprüft. Seit dem 17.09.2026 löscht die Frist für Bot-Sitzungen stündlich über dieselbe Löschkette
mp_sitzungen_loeschen(), die auch die Tariffrist und das Löschverlangen benutzen; am 16.10.2026 etwa 401 bzw. 478 Sitzungen je Lauf. Die Tariffrist selbst hatte bis zu diesem Tag nichts zu löschen (Abschnitt 6).
- GELÖSCHTE PROJEKTE. Die Auswahl der Tariffrist verbindet visitor_sessions weiterhin per INNER JOIN mit Projekt, Workspace und Eigentümer und sieht Sitzungen ohne Projekt nicht. Eine solche Sitzung entsteht im regulären Ablauf aber nicht mehr: seit dem 07.10.2026 wird ein Projekt zuerst archiviert und bei der endgültigen Löschung mit allen Sitzungen über die Kanallöschung entfernt (
mp_kanaele_loeschen()). Stand 16.10.2026 gibt es keine Sitzung ohne Projekt.
- WAISEN. Was aus einer Sitzung abgeleitet ist, steht in der Löschkette oder hat eine eigene Frist (Abschnitt 6.2). Seitenansichten, deren Sitzung fehlt — etwa nach einem Abbruch mitten in einer Löschung —, zählt der Statuswächter einmal täglich und entfernt sie samt ihrer Ereignisse selbsttätig, sobald sie älter als zehn Minuten sind.
- DER LÖSCHLAUF HÄNGT DARAN, DASS DER WORKER LÄUFT. Ein angehaltener Worker hält auch die Löschung an. Seit dem 19.08.2026 melden die Wächter Ausfälle per E-Mail, seit dem 23.09.2026 geht diese Post über SMTP tatsächlich hinaus, und seit dem 02.10.2026 prüft ein eigener Rechner im selben lokalen Netz jede Minute von außen, ob Datenbank, Redis, WebSocket-Server, Dauerprozesse und Warteschlange in Ordnung sind. Zu beachten bleibt: ActiveState=active ist kein Beweis, dass der Worker lebt; belastbar ist die Prozessliste.
Manuelle Löschwege, der Vollständigkeit halber: der Player (delete_session und delete_visitor, auf die channelid begrenzt, Rollen owner und admin) und mp_sitzungen_loeschen() in srv/db_worker.php. Ein Widerruf löscht nur dort, wo projects.consent_delete_on_withdraw gesetzt ist; Stand 16.10.2026 ist der Wert bei keinem Projekt gesetzt. Es gibt kein ON DELETE CASCADE von visitor_sessions abwärts: Die Kette läuft von Hand über alle abhängigen Tabellen, und die Stolperstelle ist mouse_events, weil die Ereignisse an pageview_id hängen statt an session_id; seit dem 07.10.2026 nimmt sie auch die Klick-Kopie mouse_events_analytik mit.
Außerhalb der Datenbank: Die Zugriffsprotokolle von nginx und Apache enthalten volle IP-Adressen und werden über 14 tageweise Rotationen gehalten (logrotate). Die Redis-Instanz des Entwicklungssystems lauscht nur auf 127.0.0.1 (Port 6381), ist zugangsbeschränkt und schreibt ihren Bestand zur Persistenz auf die Platte (AOF und RDB-Snapshots); in den Warteschlangen stehen die gekürzte IP, die vollständige URL und der DOM-Payload, bis der Worker sie abholt, in mp_autoban: für die Dauer der Sperre (24 h) die volle Adresse eines gesperrten Absenders. Die Archivdateien der ausgelagerten Ereignisse liegen unter /mnt/mouseplayer-dev-archive auf derselben Platte wie das System und sind seit dem 06.10.2026 in der Sicherung enthalten.
7. Automatisierte Entscheidungsfindung, Profiling und Bewertung
Bewertung und Einstufung finden statt. Eine Entscheidung, die gegenüber einem BESUCHER rechtliche Wirkung entfaltet oder ihn in ähnlicher Weise erheblich beeinträchtigt, wurde nicht gefunden — keine Bonitäts-, Preis- oder Zugangsentscheidung und keine Weitergabe der Bewertungen an andere als den Kunden. Nach der Beleglage ist Art. 22 gegenüber Besuchern nicht einschlägig. Drei automatisierte Folgen bestehen gleichwohl, und zwei davon verdienen einen genaueren Blick, als ein Verzeichnis ihn üblicherweise gibt. Die dritte ist seit dem 02.09.2026 hinzugekommen und ist die einzige, die auf den BESUCHER zurückwirkt: Aus der Absprungvorhersage (A.15) oder dem Abwanderungsindikator (A.16) kann eine Einblendung auf der Website des Verantwortlichen folgen. Sie erscheint nur, wenn er sie einschaltet, ihren Inhalt gibt er selbst vor, und sie lässt sich wegklicken. Eine rechtliche Wirkung oder eine ähnlich erhebliche Beeinträchtigung im Sinne von Art. 22 Abs. 1 DSGVO folgt daraus nicht — es ist ein Hinweis, kein Bescheid über Preis, Zugang oder Bonität. Benannt gehört sie trotzdem, denn hier verlässt eine Bewertung erstmals das Kundenpanel.
| Mechanismus | Was er tut | Wo |
| Aufmerksamkeitsbewertung (engagement_score) | Eine kleine ganze Zahl aus Punkten für TIEFE (Dauer, Seitenzahl, Scrolltiefe) und AUFFÄLLIGKEIT (Rage- und Dead-Clicks, Zurücksprünge, parallele Tabs). Bots und triviale Sitzungen erhalten 0. Gespeichert in ai_session_features.engagement_score (TINYINT UNSIGNED), Index idx_engagement. Wirkung: Sortierung der Empfehlungsliste im Kundenpanel. | ai/features.py:33-70; cfg/project_ai_overview.php:126-136 und 150; cfg/project_live_users.php:190 |
| Sitzungsgüte | Trennt Sitzungen ab, in denen fast nichts passiert ist. | visitor_sessions.session_quality; srv/db_worker.php:706-780 und 1103-1140 |
| Bot-Einstufung | Setzt visitor_sessions.is_bot und bot_reason (varchar 32), Index idx_is_bot. Zu beachten: Die Bot-Prüfung in mp.js läuft VOR dem Einwilligungsriegel. | srv/db_worker.php:963-1000 |
| Frustrationserkennung im Browser | Erzeugt rage_click, dead_click und mouse_thrashing. Gemessen: dead_click 355, rage_click 52, mouse_thrashing 5. Bei rage_click übergibt das Skript zusätzlich ein Merkmal an fremde Chat-Widgets, die im Browser des BESUCHERS vorhanden sind — Intercom('update', {'mouseplayer_rage_click':'DETECTED_NOW'}) und LiveChatWidget.call('set_session_variables', ...). Das ist eine automatisierte Weitergabe eines Verhaltensurteils an ein Drittsystem auf der Kundenseite. | www/mp.js:5786 und 5793-5794 |
| Textprotokoll der Sitzung | Maschinell erzeugter Fließtext über den Verlauf der Sitzung, erzeugt von ai/build.py. Seit dem 12.08.2026 ruft srv/ai_worker.php den Bau selbst auf (mit Arbeitsverzeichnis und PYTHONPATH); Stand 16.10.2026 läuft er, die jüngste Zeitleiste stammt vom selben Tag. Die Fehlermeldungen in ai_build.log stammen aus dem früheren, inzwischen entfernten Aufruf, zuletzt geschrieben am 18.08.2026. | ai/build.py; srv/ai_worker.php; ai_timelines |
| is_suspicious bei der Registrierung | Wird bei der Registrierung automatisch gesetzt, unter anderem über device_id und die normalisierte E-Mail. Folge: Im Tarif free wird die Aufbewahrungsfrist auf 24 Stunden gekürzt. | www/register.php:159-191; srv/db_worker.php:824 |
| Automatische Sperre | Mehr als 15 Verbindungen in 10 Sekunden, mehr als 15 gleichzeitige Verbindungen von einer IP, mehr als 50 Nachrichten je Sekunde sowie zu große (ausgenommen ein großes Seitenabbild) oder unlesbare Nachrichten führen im WebSocket-Server zu einer Sperre von 24 h (site_settings.autoban_stunden, 1 bis 168), gehalten in Redis (mp_autoban:) und ohne volle Adresse protokolliert. Vor dem Webserver sperrt fail2ban eine Adresse für eine Stunde, wenn sie in einer Minute mehr als 100 Mal an die Ratenbegrenzung von nginx stößt (Jail mp-nginx-429). Einträge in banned_ips setzt nach dem Stand des Codes vom 16.10.2026 nur noch der Betreiber; frühere automatische Einträge liefen nach 7 Tagen ab. | class/Server.class.php (autoBanIp); /etc/fail2ban/jail.d/mp-nginx-429.conf; /etc/nginx/conf.d/mouseplayer.conf |
| Verhaltensprofile — Gruppierung der Besuche (A.12) | k-Means über sieben Merkmale je Sitzung ordnet jeden sehenswerten Besuch einer von höchstens acht Gruppen zu und benennt sie aus der relativen Lage des Gruppenzentrums. Triviale und als Bot erkannte Sitzungen werden vorher über eine Regel abgetrennt und gar nicht geclustert. Wirkung: eine ANZEIGE — ein Reiter, eine Filterpille und eine Abspielreihe. Es hängt keine Entscheidung daran. | ai/profile.py; cfg/project_profiles.php; mp_profil_sitzung |
| Reibungswert und Auffälligkeiten | Je Sitzung ein Wert von 0 bis 100 aus gewichteten Frustrations- und Fehlersignalen samt Gründen (seit 26.09.2026); er sortiert und filtert Listen und kann bei einer Schwelle einen vom Kunden abonnierten Webhook auslösen. Einmal täglich wird der Vortag jedes Projekts gegen die Wochen davor gehalten (Sitzungen, Zielquote, Anteil mit Reibung oder JavaScript-Fehler, Web Vitals) und eine Auffälligkeit gemeldet — Zählungen über das Projekt, keine Bewertung einzelner Besucher. Es hängt keine Entscheidung gegenüber dem Besucher daran. | cfg/reibung_lib.php; cfg/anomalie_lib.php; visitor_sessions.friction_score; mp_anomalie |
Die automatische Sperre ist der einzige Mechanismus hier, der ohne menschliche Beteiligung den Zugang zu einem Dienst verweigert, und sie kann einen Kundennutzer treffen, nicht nur einen Besucher. Ob das die Schwelle des Art. 22 Abs. 1 erreicht, entscheidet dieses Verzeichnis nicht. Bewertet am 17.08.2026, nachgeführt am 16.10.2026: Die Sperre im WebSocket-Server läuft nach 24 h von selbst ab, die Sperre durch fail2ban nach einer Stunde; die frühere automatische Sperre in banned_ips lief nach 7 Tagen ab. Ein Widerspruch geht über das Supportformular oder an office@mouseplayer.com und wird von einem Menschen bearbeitet; der Betreiber kann eine Sperre vorzeitig aufheben. Damit hat der Vorgang eine begrenzte Wirkung, eine menschliche Überprüfung auf Verlangen und einen benannten Weg dorthin — die Merkmale, an denen Art. 22 hängt. Die Einordnung selbst bleibt eine Rechtsfrage; entschieden ist die Vorkehrung, nicht die Auslegung. (Entscheidung des Verantwortlichen, 17.08.2026)
Die Gruppierung aus A.12 ist Profiling im Sinne des Art. 4 Nr. 4 DSGVO: Verhaltensdaten werden automatisiert ausgewertet, um Aspekte des Verhaltens zu bewerten. Art. 22 Abs. 1 verlangt darüber hinaus eine ENTSCHEIDUNG, die rechtliche Wirkung entfaltet oder in ähnlicher Weise erheblich beeinträchtigt. Eine solche wurde nicht gefunden, geprüft auf drei Wegen. Die Gruppenzugehörigkeit schreibt ai/profile.py, gelesen wird sie auf genau vier Wegen: den Lesefunktionen in cfg/lib.php, dem Reiter cfg/project_profiles.php, dem Player www/player.php und dem Satzbauer cfg/ki_lib.php — sonst nirgends. Sie geht in keine der Brücken aus 4.1: eine Suche nach profil_key über cfg/, srv/, www/ und class/ liefert weder www/mp.js noch class/Server.class.php, sie erreicht den Browser des Besuchers also auch nicht. Und sie verändert weder die Aufbewahrungsdauer noch die Aufzeichnung noch irgendetwas, was dem Besucher auf der Kundenseite begegnet. Gruppiert werden überdies BESUCHE und nicht Menschen: ein Profil je Person setzte die Kundenkennung aus setUserId voraus, und 0 von 4226 Sitzungen tragen eine. Was bleibt, sind Art. 13 Abs. 1 lit. c und Art. 30 — die Unterrichtung und dieser Eintrag. Beides ist erfüllt. Die Einordnung selbst bleibt eine Rechtsfrage; entschieden ist der gemessene Sachverhalt, nicht seine Auslegung. (Bewertet am 27.08.2026.)
8. Technische und organisatorische Maßnahmen (Art. 32) — allgemeine Beschreibung
Dieser Abschnitt ist die allgemeine Beschreibung, die Art. 30 Abs. 1 Buchstabe g und Art. 30 Abs. 2 Buchstabe d verlangen. Jede Maßnahme unten wurde in Code oder Konfiguration überprüft; Datei und Zeile stehen dabei, damit ein Leser nachprüfen kann, statt zu vertrauen. Die Lücken am Ende dieses Abschnitts sind ebenso überprüft und werden im selben Atemzug genannt, denn eine TOM-Beschreibung, die nur aufführt, was vorhanden ist, ist eine Werbeanzeige.
| Bereich | Wirksame Maßnahme | Beleg |
| Transportverschlüsselung | Verbindungen aus dem Internet sind TLS-verschlüsselt: TLS endet in nginx (192.168.20.2:443), jede HTTP-Anfrage wird auf HTTPS umgeleitet. Der WebSocket-Server lauscht nur auf 127.0.0.1:8081 ohne eigenes TLS und ist ausschließlich über nginx erreichbar (Pfad /mp_wss/); ebenso laufen der HTTP-Tunnel /mp_wst, der Upload großer Seitenabbilder /mp_dom und der Messpunkt /mp_wsfail über HTTPS. Innerhalb des eigenen lokalen Netzes am selben Ort laufen Datenbank- und Redis-Verbindungen unverschlüsselt (siehe 8.1). | /etc/nginx/conf.d/mouseplayer.conf; srv/server.php (MP_WSS_BIND, MP_WSS_TLS); www/.htaccess |
| Datenminimierung bei der Erhebung — IP | Die IP-Adresse des Besuchers wird unmittelbar nach ihrer Bestimmung und damit vor jedem Verbraucher gekürzt (letztes IPv4-Oktett, letzte IPv6-Gruppe). Am 10.08.2026 hielten noch 236 Altzeilen volle Adressen; Stand 16.10.2026 trägt keine Zeile in visitor_sessions und ip_lifetime_stats eine ungekürzte Adresse. | class/Server.class.php (Regel B) |
| Datenminimierung bei der Erhebung — Formulareingaben | Maskierung mit hartem Boden: Bei Stufe 0 wird jedes Zeichen ersetzt; unabhängig von der Stufe werden Kennwörter und Zahlungsdaten immer ersetzt (Kategorien password und payment, Typen password/email/tel/hidden, Klassen- und Namensmuster card|cc|cvv|cvc|password|credit|social|pesel|nip). Alle 7 Projekte laufen auf smart_masking=0. | www/mp.js:4818-4853 |
| Datenminimierung bei der Erhebung — DOM | Innerhalb von data-mp-mask oder .mp-masked wird jedes Nicht-Leerzeichen durch '*' ersetzt und jedes Attribut außerhalb von MASK_KEEP_ATTRS auf '[FILTERED]' gesetzt. Gilt auch für laufende Mutationen. | www/mp.js:3934-3970 und 4732-4768 |
| Datenminimierung bei der Erhebung — Feldnamen | Der rohe name oder id eines Eingabefeldes wird nicht übertragen; gesendet wird nur die klassifizierte Kategorie, weil der rohe Name bei vielen Shops sprechend genug ist, um auf die Person zu schließen. | www/mp.js:4653-4674 |
| Durchsetzung der Einwilligung | Ausschlussliste für Seitenpfade, ausgewertet VOR dem Einwilligungsriegel und auf dem Pfad statt der vollen Adresse (71 geblockte Verbindungen). Serverseitige Durchsetzung als zweites Netz: Nur GRANTED, GRANTED_LATE oder eine ausdrückliche Regionsfreigabe kommen durch; WITHDRAWN, unbekanntes Land und alles Unklare führen zu close(1008) (24 geblockte Verbindungen). Notaus site_settings.consent_gate_active=1. | class/Server.class.php:963-975 und 977-1004 |
| Minimierung des Einwilligungsnachweises | Der TC-String wird nicht im Klartext gespeichert; gehalten wird nur sein SHA-256. | visitor_sessions.tcf_hash CHAR(64); ai/migrations/018_consent.sql |
| Anwendungssicherheit | CSRF-Token aus random_bytes(32), verglichen mit hash_equals(). Sitzungscookie mit httponly=true, samesite='Lax' und secure abhängig von HTTPS. Passwörter als Hash gespeichert und mit password_verify() geprüft. Durchgängig vorbereitete Anweisungen in den geprüften Schreibpfaden. Ratenbegrenzung bei der Anmeldung. | cfg/lib.php:118-132 und 110-112; www/login.php:60 und 28 |
| Missbrauchsabwehr | Automatische Sperre und Verbindungsbegrenzung im WebSocket (Redis-Zähler mit 10 s Ablauf; 15 gleichzeitige Verbindungen je IP; Sperre 24 h in Redis, im Protokoll gekürzt). Ratenbegrenzung und Verbindungsdeckel je Adresse in nginx für Seiten und WebSocket-Handshakes. fail2ban mit dem Jail mp-nginx-429: wer in einer Minute mehr als 100 Mal abgewiesen wird, ist eine Stunde für HTTP und HTTPS gesperrt. | class/Server.class.php; /etc/nginx/conf.d/mouseplayer.conf; /etc/fail2ban/jail.d/mp-nginx-429.conf |
| Zugriffssteuerung | Rollenmodell je Workspace (owner / admin / viewer). Das Löschen im Player ist auf owner und admin begrenzt, und jede Löschung ist zusätzlich auf die channelid eingeschränkt — im Code als die eigentliche Sicherheitsgrenze bezeichnet. | workspace_users.role; www/player.php:267 und 275-282 |
| Änderungsprotokollierung | log_audit() schreibt Nutzer, Workspace, Aktion, Ziel, Details und IP. 666 Einträge, darunter create_share, revoke_share, delete_comment, player_delete_*, firewall_auto_ban (24) und superadmin_*. | cfg/lib.php:2878-2890 |
| Freigabe-Links | channelid und session_id kommen ausschließlich aus dem Token; der übrige Query-String wird ERSETZT statt ignoriert; user_role bleibt NULL, damit Löschen und erneutes Teilen serverseitig wegfallen und nicht nur in der Oberfläche; alle drei Endpunkte schränken auf die Sitzung des Tokens ein; erfundene, abgelaufene und zurückgenommene Token liefern dieselbe Antwort. | www/share.php; www/.htaccess:77 |
| API-Oberfläche | Der vollständige Replay-Payload ist bewusst nicht Teil der öffentlichen API. | www/api/v1_session_detail.php:25 |
| Schlüsselverwaltung | Der Google-Service-Account-Schlüssel liegt verschlüsselt in projects.bigquery_sa_json und wird über decrypt_sa_key() mit BIGQUERY_SA_AES_KEY aus .env entschlüsselt; die Oberfläche nennt AES-256. | srv/cron_integration_bigquery.php:57; cfg/lib.php:993 |
| Geheimnisse außerhalb der Versionsverwaltung | Für den aktuellen Index bestätigt: .gitignore listet .env, und git ls-files findet nur .env.example. | git ls-files |
| Netzexposition | Aus dem Internet erreichbar sind nur die Ports 80 und 443 über nginx; für Datenbank und Redis besteht keine Portweiterleitung. Die Redis-Instanz des Entwicklungssystems ist nur an 127.0.0.1 gebunden (Port 6381); eine ältere, gemeinsam genutzte Redis-Instanz (Port 6379) lauscht zusätzlich im lokalen Netz. MariaDB lauscht auf 127.0.0.1 und im lokalen Netz. Datenbank und Redis sind zugangsbeschränkt und nur aus dem eigenen lokalen Netz erreichbar. Vor www.mouseplayer.com liegt eine zusätzliche Zugangsbeschränkung. | ss -ltn; Redis-Konfiguration; www/.htaccess |
8.1 Maßnahmen, die nachweislich NICHT bestehen
- Keine Verschlüsselung im Ruhezustand. innodb_encrypt_tables, innodb_encrypt_log und innodb_encrypt_temporary_tables stehen alle auf OFF, und es gibt keinen verschlüsselten Datenträger (lsblk zeigt sda1 ohne crypt).
- Kein TLS auf den Datenbankverbindungen. have_ssl=YES, aber ssl_cert, ssl_key und ssl_ca sind leer. MariaDB lauscht auf 127.0.0.1 und im lokalen Netz (192.168.20.2:3306); Verbindungen aus dem lokalen Netz laufen damit unverschlüsselt. Sie sind zugangsbeschränkt und aus dem Internet nicht erreichbar (keine Portweiterleitung).
- Keine Transportverschlüsselung für Redis. Die Verbindungen zu Redis laufen über die lokale Schnittstelle beziehungsweise im lokalen Netz unverschlüsselt; beide Instanzen sind zugangsbeschränkt. Die Instanz des Entwicklungssystems schreibt ihren Bestand zur Persistenz auf die Platte (AOF), darunter die Warteschlangen mit gekürzter IP, vollständiger URL und DOM-Payload sowie für die Dauer der Sperre (24 h) die volle Adresse gesperrter Absender.
- KEIN PROTOKOLL DARÜBER, WER WELCHE AUFZEICHNUNG ANGESEHEN HAT. audit_logs kennt nur schreibende Aktionen; ein Aufruf von player.php, ajax_get_events.php oder player_theatre.php wird überhaupt nicht protokolliert. Es lässt sich deshalb nachträglich nicht beantworten, wer eine bestimmte Sitzung angesehen hat.
- Die Apache-Zugriffsprotokolle enthalten volle IP-Adressen und werden 14 Tage gehalten.
- Die Archivdateien der ausgelagerten Aufzeichnungsereignisse liegen auf derselben Platte wie System und Datenbank. Ein Ausfall dieser Platte trifft beide; die Auslagerung an einen anderen Ort leistet allein die verschlüsselte Kopie der Sicherung, die das Archiv seit dem 06.10.2026 enthält.
- Alle Grenzen gegen Überlastung — nginx, fail2ban und die Sperre im WebSocket-Server — zählen je Adresse. Gegen einen verteilten Angriff aus vielen Adressen hilft nichts, was vor dem Rechner läge: Es ist kein CDN und kein Filterdienst vorgeschaltet.
- Gebäudesicherung: Zutritt hat ausschließlich der Verantwortliche selbst. Der Raum ist mit Schlüssel abgesperrt und videoüberwacht; weitere Personen — auch Vermieter oder Reinigungsdienste — haben keinen Zutritt (Angabe des Verantwortlichen, 17.08.2026). Die genaue Anschrift ist hier bewusst nicht genannt.
- Überwachung und Wiederherstellung: Seit dem 19.08.2026 melden die Wächter in
srv/cron_status.php Störungen, knappen Plattenplatz, ausbleibende Sicherungen und gescheiterte geplante Läufe in Urgent Logs (B.8) und per E-Mail; seit dem 23.09.2026 geht diese Post über SMTP tatsächlich hinaus. Seit dem 02.10.2026 prüft ein eigener Rechner im selben lokalen Netz jede Minute über einen Gesundheitsendpunkt (www/health.php) Datenbank, Redis, WebSocket-Server, Dauerprozesse und Warteschlange und meldet einen Ausfall; einen Ausfall des Internetanschlusses selbst sieht er nicht. Angestrebte Wiederherstellungszeit: höchstens 24 Stunden. Wiederherstellungstests aus der ausgelagerten Kopie wurden am 05./06.09.2026 und am 07.10.2026 (vollständige Wiederherstellung der Daten) durchgeführt; vorgesehen sind sie monatlich (Angabe des Verantwortlichen, 17.08.2026). Die USB-Sicherungsplatte liegt im selben Raum wie der Server — ein einzelnes Ereignis an diesem Ort erfasst damit beide; die Auslagerung nach außerhalb leistet allein die verschlüsselte Kopie. Die beiden Schlüsseldateien liegen ausgedruckt in einem Safe, zu dem ausschließlich der Verantwortliche Zugang hat, und überleben damit den Verlust des Rechners.
9. Datenschutzbeauftragter — Bewertung nach Art. 37 DSGVO
ERGEBNIS: Nach den heute verfügbaren Zahlen ist keine Pflicht zur Benennung eines Datenschutzbeauftragten belegt — die Bewertung hängt aber an einer einzigen Größe, diese Größe bewegt sich nur in eine Richtung, und bis zum 19.08.2026 beobachtete sie niemand. Sie wird jetzt täglich gemessen (siehe Folge 2). Die Antwort lautet "noch nicht", nicht "nein".
Art. 37 Abs. 1 verlangt eine Benennung in drei Fällen. Fall a, eine Behörde oder öffentliche Stelle, entfällt. Fall c, Kerntätigkeiten, die in der umfangreichen Verarbeitung besonderer Kategorien nach Art. 9 oder von Daten über strafrechtliche Verurteilungen nach Art. 10 bestehen, ist nicht erfüllt: Daten besonderer Kategorien werden nicht absichtlich verarbeitet. Damit ist der Punkt nicht erledigt — wie unter A.2 vermerkt, speichert der DOM-Schnappschuss, was die Seite des Kunden ausgibt, sodass Daten besonderer Kategorien auf einer Gesundheits- oder Finanzseite beiläufig in eine Aufzeichnung gelangen können. Eine beiläufige Erfassung ist keine Kerntätigkeit, die in einer solchen Verarbeitung besteht, weshalb Fall c nicht greift; das Risiko ist aber real und gehört ins Kunden-Onboarding, statt hier weggeschrieben zu werden.
Fall b ist der entscheidende, und er hat zwei Glieder. Das erste Glied — Kerntätigkeiten, die in Verarbeitungen bestehen, die eine REGELMÄSSIGE UND SYSTEMATISCHE ÜBERWACHUNG betroffener Personen erfordern — ist ohne Diskussion erfüllt. Session Replay ist fortlaufende, automatisierte Beobachtung individuellen Verhaltens; sie ist dem Geschäft nicht beigeordnet, sie IST das Geschäft. Wer dieses Verzeichnis liest und versucht ist, über das erste Glied zu streiten, sollte es lassen: Es ist erfüllt, und der Streit darüber verbraucht die Glaubwürdigkeit, die für das zweite Glied gebraucht wird.
Das zweite Glied ist der UMFANGREICHE UMFANG, und hier fällt die Antwort derzeit negativ aus. Die Leitlinien der Artikel-29-Datenschutzgruppe wägen vier Faktoren: die Zahl der betroffenen Personen, Umfang und Bandbreite der Daten, die Dauer oder Dauerhaftigkeit der Verarbeitung und die geografische Reichweite. Am 10.08.2026 gemessen: 706 Besuchersitzungen, 329 verschiedene Besucherdatensätze, 7 Projekte, 4 Kundenkonten. Gemessen an der Zahl der betroffenen Personen ist das weit von einem umfangreichen Umfang entfernt — und es sind zudem Zahlen des Entwicklungssystems. Stand 16.10.2026: 3514 verschiedene, als Mensch eingestufte Besucherkennungen in den letzten 30 Tagen über alle Projekte, weiterhin weit unter der Schwelle aus Folge 2.
Zwei der vier Faktoren zeigen gleichwohl in die Gegenrichtung, und das Verzeichnis sollte das sagen, statt sich auf den bequemen Faktor zu stützen. Die BANDBREITE der Daten je Person ist außergewöhnlich groß: das vollständige Seiten-HTML einschließlich dessen, was die Seite anzeigt, Formulareingaben auf Tastenanschlagsebene, Bewegungs- und Klickverhalten, abgeleitete Verhaltensbewertungen und eine Prosaerzählung der Sitzung. Die DAUER ist lang: Aufzeichnungen bleiben je nach Tarif bis zu 365 Tage und in der Sicherung bis zu 364 Tage darüber hinaus, auch wenn seit August 2026 für alle Tabellen Löschfristen bestehen und laufen (Abschnitt 6). Allein die Kopfzahl hält die Bewertung unter der Schwelle, und die Kopfzahl ist genau die Größe, die MousePlayer nicht steuert: Sie ergibt sich daraus, wie viel Verkehr die Website des jeweiligen Kunden erhält. Ein einziger mittelgroßer E-Commerce-Kunde könnte das Produkt allein über die Linie tragen, ohne dass hier eine Entscheidung getroffen würde.
- Folge 1 — die Bewertung mit Datum festhalten. Art. 5 Abs. 2 macht die Rechenschaftspflicht zur Pflicht; eine negative Bewertung, die nie festgehalten wurde, ist von einer nie vorgenommenen nicht zu unterscheiden.
- Folge 2 — den Auslöser bestimmen, der sie wieder öffnet. Der sinnvolle Auslöser ist die Zahl der je Monat über alle Kunden hinweg beobachteten Besucher, dazu eine Überprüfung bei jedem neuen Kunden von nennenswerter Größe. Schwellenwert und Abstand: Die Bewertung nach Art. 37 wird wiederholt, sobald über alle Kunden hinweg mehr als 100000 Endnutzer je Monat beobachtet werden, mindestens jedoch jährlich. Verantwortlich ist Lukas Wójcik, Inhaber. (Entscheidung des Verantwortlichen, 17.08.2026) Umgesetzt am 19.08.2026: Die Zahl der in den letzten 30 Tagen beobachteten verschiedenen Endnutzer wird vom Wächterprozess einmal täglich gezählt und gegen diese Schwelle sowie gegen das Datum der zuletzt festgehaltenen Bewertung gehalten; wird eines von beidem überschritten, geht eine Warnung per E-Mail hinaus. Schwelle und Datum sind Einstellungen und werden aus derselben Zeile gelesen, die dieser Satz zitiert, damit Dokument und Messung nicht auseinanderlaufen. Ein Auslöser, den niemand misst, ist eine Notiz und keine Maßnahme – das war die Lücke, die dieser Absatz beschrieb und nicht mehr beschreibt.
- Folge 3 — nationales Recht prüfen. Art. 37 Abs. 4 erlaubt es dem Unionsrecht oder dem Recht der Mitgliedstaaten, eine Benennung in weiteren Fällen vorzuschreiben. auszufüllen: Bestätigung durch polnische Rechtsberatung, ob polnisches Recht über Art. 37 Abs. 1 hinaus einen Datenschutzbeauftragten verlangt
- Folge 4 — eine freiwillige Benennung bleibt offen. Wird ein Datenschutzbeauftragter freiwillig benannt, gelten die Art. 37 bis 39 vollständig, einschließlich der Veröffentlichung und Mitteilung der Kontaktdaten. Das ist eine Entscheidung, kein Selbstlauf.
- Folge 5 — davon getrennt, aber angrenzend: Eine Datenschutz-Folgenabschätzung nach Art. 35 ist bei jedem KUNDEN als Verantwortlichem sehr wahrscheinlich erforderlich, weil systematische Überwachung mit Bewertung und Scoring zusammentrifft. Als Auftragsverarbeiter muss MousePlayer nach Art. 28 Abs. 3 Buchstabe f unterstützen. Eine produktbezogene Folgenabschätzung besteht - es ist die unter „Datenschutz-Folgenabschätzung“ veröffentlichte. Ein gesondertes Exemplar wird Kunden nicht ausgehändigt (Entscheidung des Verantwortlichen, 17.08.2026). Die Unterstützung nach Art. 28 Abs. 3 Buchstabe f wird auf Anfrage geleistet und stützt sich auf die öffentlich zugänglichen Unterlagen: dieses Verzeichnis, die veröffentlichte Folgenabschätzung, die technischen und organisatorischen Maßnahmen und die Liste der Unterauftragsverarbeiter.
10. Bekannte Lücken
Alles Folgende ist belegt, nicht vermutet. Dieser Abschnitt besteht, weil ein Verzeichnis von Verarbeitungstätigkeiten ein Arbeitsmittel ist: Es geht darum, die offenen Punkte sehen zu können, nicht darum, ein sauberes Blatt vorzuweisen. Die Punkte sind danach geordnet, wie schlecht sie sich in einer Prüfung lesen würden, nicht danach, wie schwer sie zu beheben sind.
| Lücke | Was belegt ist | Warum es zählt |
| Volle IP-Adressen in Protokollen der eigenen Anwendung | Stand 16.10.2026 ist der Altbestand in visitor_sessions und ip_lifetime_stats gekürzt (am 10.08.2026 236 bzw. 291 ungekürzte Zeilen). Ungekürzt bleiben bewusst mouseplayer_logs, audit_logs, user_ip_history, login_sessions, share_views und support_requests (Teil B) sowie die Zugriffsprotokolle von nginx und Apache | Für Teil B ist die volle Adresse begründet (B.2 bis B.7) und durch Fristen begrenzt. Sie steht trotzdem hier, weil diese Tabellen in jede Sicherung gehen. |
| Altbestand mit Formulareingaben im Klartext | Am 10.08.2026 enthielten 173 Zeilen in mouse_events bei event_type='input' unmaskierte Werte aus dem Zeitraum 2026-07-21 bis 2026-07-27, darunter Personennamen. Die Zeilen wurden am 17.08.2026 gelöscht, vor Einführung der Archivdateien am 18.08.2026; Stand 16.10.2026 steht keine davon in mouse_events | Aktuelle Zeilen sind maskiert, die Kontrolle wirkt also. Im Archiv und in der heutigen Sicherung können die alten Werte nicht stehen; eine Sicherung aus der Zeit vor dem 17.08.2026 ist nicht bekannt, ihr Fehlen aber nicht im Einzelnen nachgewiesen. |
| Freigabe-Links umgehen die Anmeldung vollständig | /s/<40-Hex-Token> führt unmittelbar auf player.php?share=<token>; der Token ist die gesamte Schranke | Der Link lässt sich an jeden weiterreichen, weshalb die Empfängerkategorie für A.1, A.2, A.3 und A.9 tatsächlich offen ist. Begrenzt wird das durch die Höchstlebensdauer (voreingestellt 7 Tage, höchstens 90), die jederzeitige Rücknahme und das Abrufprotokoll (B.6). |
| Kein Protokoll darüber, wer eine Aufzeichnung angesehen hat | audit_logs kennt nur schreibende Aktionen; Aufrufe von player.php, ajax_get_events.php und player_theatre.php werden nicht protokolliert | Nach einem Vorfall lässt sich nicht feststellen, wer welche Sitzung angesehen hat. Das ist die eine Maßnahme, deren Fehlen einer Aufsichtsbehörde am schwersten zu erklären ist. |
| Der gesamte Server wird täglich ausgelagert | srv/backup-crypt.sh sichert täglich alle Datenbanken und den gesamten Webbaum einschließlich jeder .env, seit dem 06.10.2026 auch das Archiv der Aufzeichnungsereignisse; die Kopie wird vor der Übertragung auf dem eigenen Server verschlüsselt (rclone crypt) und seit dem 05.09.2026 in einem Bucket bei Google Cloud Storage in Warschau abgelegt, gedeckt von den Google-Cloud-Datenverarbeitungsbedingungen (Abschnitt 4) | Was täglich das Haus verlässt, ist nicht nur eine Kopie der Sitzungsaufzeichnungen, sondern der vollständige Server, mit den Produktivgeheimnissen mehrerer Systeme. Die Verschlüsselung nimmt Google den Inhalt, nicht den Umfang. Gehen beide Schlüsseldateien verloren, ist die Sicherung unwiederbringlich; sie liegen deshalb zusätzlich ausgedruckt im Safe (Abschnitt 8.1). |
| Ob die Sicherung ankommt, wird überwacht | Bis 11.08.2026 unbelegt. Seither schreibt der Lauf ein Protokoll und prüft am Ziel nach; seit dem 19.08.2026 hält ein Wächter den letzten gelungenen Lauf gegen eine Frist und meldet ein Ausbleiben in Urgent Logs und per E-Mail | Die Lücke dieser Zeile ist geschlossen. Sie bleibt stehen, damit nachvollziehbar ist, dass die Sicherung bis zum 11.08.2026 ohne Nachweis lief. |
| Alte Sicherungsskripte | Die alten Sicherungsskripte wurden am 16.10.2026 entfernt. Ausgeführt wurde keines von ihnen mehr; die tägliche Sicherung läuft seit dem 11.08.2026 über srv/backup-crypt.sh | Die Lücke dieser Zeile ist geschlossen. Sie bleibt stehen, damit nachvollziehbar ist, dass bis zum 11.08.2026 um 02:00 root hatte, wer das SSH-Konto pi erlangte. |
| Keine Verschlüsselung im Ruhezustand, kein TLS auf Datenbank- und Redis-Verbindungen | innodb_encrypt_* alle OFF, kein verschlüsselter Datenträger; ssl_cert/ssl_key/ssl_ca leer, MariaDB auch im lokalen Netz erreichbar; Redis zugangsbeschränkt, aber unverschlüsselt und mit Persistenz auf der Platte (AOF) | Die Aufzeichnungen — einschließlich des DOM-Payloads in der Redis-Warteschlange und der Archivdateien — sind für jeden mit Dateisystemzugriff lesbar; im lokalen Netz laufen Datenbankverbindungen im Klartext. Aus dem Internet ist keiner dieser Wege erreichbar. |
| Ein Teil der Einwilligungsnachweise sind Testdaten | Am 10.08.2026 trugen 671 von 706 Sitzungen consent_source='testdata' mit consent_ts IS NULL, gesetzt durch ai/devdata/001_altsitzungen_markieren.sql; Stand 16.10.2026 sind es noch 566 Sitzungen | Für diese Sitzungen kann das Einwilligungsprotokoll nicht als Nachweis dienen. Das ist ein Artefakt des Entwicklungssystems, doch dieselbe Abfrage im Produktivbetrieb bräuchte dieselbe Prüfung. |
| Der Widerruf löscht nichts | projects.consent_delete_on_withdraw ist Stand 16.10.2026 bei keinem Projekt gesetzt (ausgewertet im Zweig consent_withdrawn in srv/db_worker.php) | Der Widerruf hält die weitere Aufzeichnung an — was Art. 7 Abs. 3 verlangt —, aber ein Kunde, der annimmt, er lösche auch die frühere Aufzeichnung, irrt. Diese Unterscheidung muss in der kundenseitigen Dokumentation stehen. |
| Alles hier ist auf dem Entwicklungssystem gemessen | APP_ENV=dev; das Testprojekt mpconsenttest01 und die s_mptest_-Testdaten sind in den Zählungen enthalten | Die Struktur dieses Verzeichnisses überträgt sich auf den Produktivbetrieb, die Zahlen nicht. Der Produktivbetrieb muss gemessen werden, bevor dieses Verzeichnis nach außen verwendet wird. |
| Die Suche nach ausgehenden Aufrufen war nicht erschöpfend | cfg/, srv/, class/ und www/ wurden nach curl_init, curl_exec, file_get_contents mit http, fsockopen, stream_context_create und allen https-Literalen durchsucht; die vendor-Verzeichnisse nicht | In den vendor-Bäumen stehen die Endpunkte von Stripe, Google Cloud, PHPMailer und Symfony. Diese Dienste sind in Abschnitt 4 benannt, doch die Aussage "es gibt keinen weiteren ausgehenden Aufruf" ist durch die Suche begrenzt. |
| Kein Schalter je Projekt für die Verhaltensprofile | profile_aktiv ist eine globale Einstellung des Betreibers. mp_ki_module_katalog() in cfg/lib.php führt neun abwählbare KI-Abschnitte, und keiner davon sind die Profile — projects.ki_module deckt diesen Reiter also nicht ab; der Navigationseintrag in www/project.php steht unbedingt. Gemessen am 27.08.2026. | Ein Kunde, der die Besuche seiner Besucher nicht gruppiert haben will, kann das nicht abstellen. Die Aufzeichnung hat er in der Hand, die Ableitung daraus nicht. Jeder andere abgeleitete Abschnitt lässt sich je Projekt abwählen — dieser ist die Ausnahme. Die Aufbewahrungslücke, die hier bis zum 27.08.2026 stand, ist geschlossen: mp_profile und mp_sequenzmuster haben jetzt eigene Fristen, siehe 6.2. |
| Ein Löschverlangen erreicht die importierten GA4-Sitzungen nur bei eingeschalteter Analytics-Brücke | Seit dem 01.09.2026 nimmt mp_sitzungen_loeschen() bei einem Verlangen nach Art. 17 auch ga4_sessions und ga4_events mit, verbunden über ga4_sessions.user_pseudo_id = visitor_sessions.custom_user_id und gebunden an den Kanal. Diese Verbindung besteht aber nur, wenn der Kunde die GA4-Analytics-Brücke eingeschaltet hat — sie schreibt die client_id aus dem _ga-Cookie dorthin. Belegt er custom_user_id stattdessen über setUserId() mit einer eigenen Kennung, führt überhaupt kein Weg von einem Besucher zu seiner importierten Zeile. Der Fall steht als eigener Testfall im Prüfstand (test_ga4_import.php, Abschnitt J), damit er nicht in Vergessenheit gerät. | Für diese Kunden bleibt die importierte Zeile nach einem Löschverlangen stehen, bis die Frist aus A.14 sie abräumt. Sie ist pseudonym und für uns nicht zuordenbar — genau deshalb lässt sie sich auch nicht gezielt löschen. Ein Löschweg über die GA4-Property selbst ist Sache des Verantwortlichen, der sie führt. |
| Die Einwilligung importierter Zeilen lässt sich nicht nachweisen, nur vermuten | Importiert wird, was eine user_pseudo_id trägt; cookielose Treffer bei abgelehnter Einwilligung tragen keine und fallen heraus (A.14). Einen Nachweis wie consent_events gibt es für diese Zeilen nicht — GA4 liefert im Export kein Einwilligungsmerkmal, das hier gespeichert werden könnte. | Für die eigenen Aufzeichnungen kann MousePlayer je Sitzung belegen, worauf sie beruht; für eine importierte Sitzung nicht. Der Riegel ist mechanisch und wirkt, aber er belegt nur, dass ein Cookie gesetzt war — nicht, worauf sich der Besucher eingelassen hat. Verantwortlich dafür ist der Verantwortliche, der die Erhebung bei Google steuert. |
| Der eigene Besuchername ist ein ungeprüfter Freitext | A.13, seit dem 28.08.2026. mp_besucher_label_setzen() kürzt auf 64 Zeichen, entfernt Zeilenumbrüche und prüft, dass der Besucher zum Projekt gehört — den INHALT prüft nichts, und es gibt keine Vorgabe, welcher Art er sein soll. | Der Verantwortliche kann dort besondere Kategorien nach Art. 9 hineinschreiben („Herr X, Rollstuhl“), ohne dass ein Riegel greift oder eine Warnung erscheint. Für die Einhaltung haftet er, nicht der Auftragsverarbeiter — aber ein Auftragsverarbeiter, der ein Freitextfeld anbietet und dazu schweigt, hat die Gelegenheit geschaffen. Eine technische Prüfung ist nicht möglich: ein Name lässt sich von einer Gesundheitsangabe nicht maschinell unterscheiden. Was möglich wäre, ist ein Hinweis am Feld. |
| Beispiele der Bot-Nachkontrolle ohne Löschfrist | Ein pseudonymer Merkmalsvektor je entschiedener Sitzung (bot_review_labels, A.19) bleibt nach der Sitzung stehen, solange keine Frist gesetzt ist. Die Vorgabe von retention_bot_labels_years ist 0 (unbegrenzt); der Betreiber kann sie in Jahren setzen. | Sie sind kein Besucherinhalt, tragen aber die Sitzungskennung. Ob eine Frist zu setzen ist, entscheidet der Betreiber. |
| Der Freitext einer Umfrage ist nur grob gefiltert | A.21, seit dem 27.09.2026. mp_umfrage_text_filtern() ersetzt E-Mail-Adressen, IP-Adressen und Telefonnummern, im Browser und noch einmal im Worker. Namen, Anschriften, Kundennummern und Angaben zur Gesundheit erkennt es nicht. | Ein Besucher kann in die Nachfrage schreiben, was er will, auch besondere Kategorien nach Art. 9. Der Hinweis unter dem Feld bittet darum, es nicht zu tun; ein Riegel ist er nicht. Wie beim eigenen Besuchernamen (A.13) lässt sich der Inhalt maschinell nicht zuverlässig einordnen. |
11. Pflege dieses Verzeichnisses
Art. 30 Abs. 1 und Art. 30 Abs. 2 verlangen, das Verzeichnis schriftlich zu führen und der Aufsichtsbehörde auf Anfrage zur Verfügung zu stellen. Damit sind zwei Dinge nötig, die nicht im Dokument selbst stehen: jemand, der es verantwortet, und ein Abstand, in dem es gegen das System geprüft wird statt gegen seine eigene Vorfassung.
- Verantwortung und Überprüfungsabstand: Verantwortlich: Lukas Wójcik, Inhaber. Geprüft wird jährlich und bei jeder Änderung der Verarbeitung. Die datierten Fassungen liegen im Versionsverwaltungssystem unter
ai/cms/. (Entscheidung des Verantwortlichen, 17.08.2026)
- Ereignisse, die unabhängig vom Abstand eine Fortschreibung erzwingen: ein neuer Unterauftragsverarbeiter oder ein Wechsel des Ziels; eine neue Tabelle mit personenbezogenen Daten; eine Änderung der Löschkette
mp_sitzungen_loeschen() oder des täglichen Löschlaufs in srv/db_worker.php; die Aktivierung des BigQuery-Exports oder von Webhooks bei irgendeinem Kunden; eine Änderung der Maskierungsvorgaben; der erste Kunde, dessen Seite Daten besonderer Kategorien ausgibt.
- Vorgehen: Jede Zahl in diesem Verzeichnis stammt aus einer Messung gegen Code, Schema oder Datenbank an einem genannten Datum. Eine Überprüfung, die nur den Text erneut liest, hat nichts überprüft — die Zahlen müssen erneut gemessen werden, und die Platzhalter sind entweder auszufüllen oder ausdrücklich mit Begründung fortzuschreiben.
- Dieses Verzeichnis ersetzt weder die Liste der Unterauftragsverarbeiter noch das TOM-Dokument, den Auftragsverarbeitungsvertrag oder die Datenschutzerklärung. Wo jene Dokumente und dieses Verzeichnis voneinander abweichen, ist die Abweichung ein Befund, kein Formatierungsproblem.