11 KiB
Website-Analyse (Funktion im Kundenportal) – Design
Stand: 2026-10-01 · Status: vom Nutzer im Chat freigegeben (Abschnitte 1–3), Spec zur Durchsicht
Teilprojekt 3 von 3 (1 Projektarten – live 30.09.; 2 Preview-Runner – live 01.10.).
Regel des Nutzers: bauen → live → Nutzer testet live.
Recherchen: /root/reports/analyse-funktion-2026-09-30/ (recht-tracking-deutschland.md,
technik-analyse-heatmap.md). Keine Rechtsberatung – AVV/Texte vor Livegang anwaltlich prüfen lassen.
Ziel
Kunden mit Wartungs-Abo schalten im Portal (Funktionen) eine Website-Analyse ein. Auf ihrer Website erscheint ein Cookie-Banner (Annehmen/Ablehnen). Ohne Einwilligung werden nur serverseitig Seitenaufrufe, Herkunft, Land und Gerätetyp gezählt; nach „Annehmen“ zusätzlich Besucher, Verweildauer, Scrolltiefe, Klick-Heatmap und Kontakt-Klicks. Alles läuft auf dem eigenen Server, ohne Google o. ä., und wird ohne Änderung am Kunden-Repo beim Veröffentlichen durch den Preview-Runner eingebunden.
Entscheidungen (vom Nutzer)
| # | Entscheidung |
|---|---|
| W1 | Nur mit Wartungs-Abo (productKey === 'wartung', Status in ACTIVE_STATUSES). Ohne Abo: Kachel „Im Wartungs-Abo enthalten“ mit Link zum Abo. Hosting-Abo (hosting) ausgeschlossen (bestätigt 01.10.). |
| W2 | Kunde schaltet selbst ein (Portal, AVV-Haken); WOMS kann ebenfalls schalten (Ausnahmen, protokolliert). |
| W3 | Umfang V1 wie unten (Abschnitt 2); nicht: Session-Aufzeichnung, Formularinhalte, Ladezeiten/JS-Fehler, Trichter/UTM. |
| W4 | Banner: schlichte Leiste unten, „Ablehnen“ und „Annehmen“ gleichwertig, Link „Datenschutz“, eine wählbare Akzentfarbe; Handy: kompakte Karte. Footer-Link „Cookie-Einstellungen“. Entscheidung gilt 6 Monate. Deutsch. |
| W5 | Datenschutz: automatische Zusatzseite /datenschutz-analyse.html + WOMS-Ticket „Datenschutzerklärung von um Hinweis auf Analyse ergänzen“. |
| W6 | Eigene Lösung (Sammeldienst + Skript), kein Umami/Matomo/Google. |
| W7 | Nur auf öffentlichen Websites (isPublic), nicht auf login-geschützten Previews. |
| W8 | Abo endet oder Analyse aus ⇒ Banner/Skript beim nächsten Veröffentlichen entfernt, Daten nach 60 Tagen gelöscht. |
| W9 | Aufbewahrung: Rohdaten 30 Tage, Tageswerte bis Abo-Ende + 60 Tage. |
1. Bausteine
- Sammeldienst
webklar-analytics– Code im Portal-Repo unteranalytics/(eigenespackage.json, keine Laufzeit-Abhängigkeiten), Containernode:24-alpine(eingebautesnode:sqlite), Code schreibgeschützt eingehängt wie der Runner, Daten/srv/webklar-analytics/(SQLite).deploy.shstartet ihn neu, wenn sichanalytics/geändert hat. Erreichbar über Traefik unterhttps://project.webklar.com/a/…(eigener Router mit höherer Priorität aufPathPrefix(/a/)). Länder über DB-IP Lite Country (CSV/MMDB, CC BY 4.0, Namensnennung im Portal), monatlich aktualisiert per Skript. - Einbinden über den Runner (Teilprojekt 2): Ist die Analyse für das Projekt aktiv und die Seite
öffentlich, setzt der Runner beim Veröffentlichen (static und build) vor
</head>jeder HTML-Datei ein:<script src="https://project.webklar.com/a/w.js" data-site="<siteKey>" data-color="<hex>" defer></script>und erzeugt/datenschutz-analyse.htmlaus einer Vorlage (Firmenname, Anschrift, E-Mail des Kunden aus Appwrite). Ist sie aus, unterbleibt beides. Das Portal übergibt dafür im Build-Auftrag ein Feldanalytics: { siteKey, color, privacy: { company, address, email } } | null(validiert im Runner: siteKey^[a-z0-9]{16,40}$, color^#[0-9a-f]{6}$, Texte HTML-maskiert, Länge begrenzt). Einschalten/Ausschalten löst einen Neubau aus (PortalrunDeploy). - Skript
w.js(≤ 6 KB minifiziert, ohne Abhängigkeiten, vom Sammeldienst ausgeliefert, Cache 1 h): Seitenaufruf ohne Einwilligung; Banner; nach „Annehmen“ Zusatzereignisse (Abschnitt 2); Footer-Link „Cookie-Einstellungen“ (fest unten rechts, klein, wenn kein Element[data-webklar-consent]auf der Seite existiert – sonst wird dieses Element zum Auslöser); Overlay-Modus für die Heatmap (Parameter__wk_heat=<token>, lädth.jsnach). - Portal: Funktionen-Kachel „Analyse“ (Abo-Prüfung, Projektwahl, Erklärung, Akzentfarbe mit Banner-Vorschau, AVV-Haken, Ein/Aus), Ansicht „Analyse“ (Abschnitt 3), Admin-API für WOMS.
- WOMS: Zeile „Website-Analyse an/aus“ auf der Projektkarte; Services zeigt die Funktion als aktiv.
- Rechtliches: AVV Website-Analyse, Leistungsbeschreibung „Website-Analyse“, neue Fassung der Abo-Bedingungen, Vorlage Zusatzseite, Absatz in WEBklar-Datenschutzerklärung (Auftragsverarbeitung).
2. Daten und Datenschutz
Ereignisse (alle per navigator.sendBeacon als text/plain an POST /a/e, Body JSON ≤ 4 KB):
| Typ | Wann | Felder |
|---|---|---|
pv Seitenaufruf |
immer | site, path (ohne Query/Hash, ≤ 300), ref (nur Host, nur wenn ≠ eigene Domain), vp (m < 768 ≤ t < 1024 ≤ d) |
bn Banner |
Anzeige / Klick | site, a: shown|accept|reject – keine weiteren Felder |
en Verweildauer |
nur nach Annehmen, beim Verlassen | site, path, vp, sec (0–3600), scroll (0–100) |
ck Klick |
nur nach Annehmen | site, path, vp, x, y (0–1, relativ zur Dokumentgröße), sel (CSS-Pfad ≤ 200) |
ct Kontakt-Klick |
nur nach Annehmen | site, path, kind: tel|mail|wa|out, host (nur bei out) |
Server: IP ⇒ Land (DB-IP), danach verworfen; User-Agent ⇒ Gerätetyp + Bot-Erkennung, danach verworfen.
Besucher-Kennung nur für en/ck/ct: HMAC-SHA256(tagesSalz, siteKey|ip|ua) gekürzt auf 16 Hex,
Salz zufällig, nur im RAM, wird um 00:00 Europe/Berlin neu erzeugt (nach Neustart neues Salz). Keine
Cookies, keine Set-Cookie-Header. Gespeichert auf dem Gerät nur die Banner-Wahl
(localStorage['wk-consent'] = {v:1, a:'accept'|'reject', t}), gültig 6 Monate.
GPC (navigator.globalPrivacyControl) oder DNT ⇒ wie „Ablehnen“, Banner nicht anzeigen.
Annahme-Prüfung: Unbekannter siteKey, Origin/Referer-Host nicht in den Domains der Website
(Subdomain *.project.webklar.com + liveDomain) ⇒ 204 ohne Speichern. Bots ⇒ verworfen. Mengenlimit
120 Ereignisse/Minute je (site, IP) im RAM. CORS nur für die eigenen Domains der Website.
Speicherung (SQLite): Tabellen events_raw (30 Tage), daily (site, day, dim, key, count),
clicks (30 Tage), sites (siteKey, projectId, domains, active, offSince). Nächtlicher Job 02:30:
Verdichten, Rohdaten > 30 Tage löschen, Websites mit offSince > 60 Tage komplett löschen.
Traefik: Zugriffsprotokoll für /a/ ohne Client-IP (Feld filtern oder Router ohne Access-Log) – im
Livegang prüfen.
Einwilligungsnachweis: technischer Nachweis (ohne Annehmen sendet das Skript nachweislich nichts Weiteres); so in AVV und Leistungsbeschreibung beschrieben; Prüfpunkt für den Anwalt.
3. Portal, WOMS, Abläufe
Funktionsdaten: vorhandenes Collection portalFeatures mit featureKey: 'analyse' je
(Kunde, Projekt): state (off|active|disabled), siteKey, neu accentColor, avvVersion,
avvAcceptedAt, avvAcceptedBy (customer|Mitarbeitername), activatedAt, offSince, privacyTicketId.
Fehlende Attribute per Schema-Skript (Muster scripts/preview-runner-setup.mjs, limit 200).
Einschalten (Kunde): POST /api/funktionen/analyse/activate { projectId, accentColor, avvVersion, consent:true } ⇒ Prüfungen (Eigentum, Wartungs-Abo aktiv, Projekt öffentlich mit Subdomain/Live-Domain,
AVV-Fassung aktuell) ⇒ Dokument active, Sammeldienst-Website registrieren (PUT /a/admin/sites/:siteKey
mit Token), Neubau anstoßen, Ticket „Datenschutzerklärung … ergänzen“ (Muster createFeatureTicket),
Mail an Kunden (neue Vorlage K-Nummer laut Bestand) „Deine Website-Analyse ist aktiv“.
Ausschalten: POST …/deactivate { projectId } ⇒ off, offSince, Neubau, Sammeldienst active=false.
Abo-Ende: täglicher Job: aktive Analyse ohne aktives Wartungs-Abo ⇒ wie Ausschalten (Mail an Kunden).
WOMS: POST /api/admin/analyse/:projectId { on, avvConfirmedVerbally } (requireAppwriteStaff);
beim Einschalten durch Mitarbeiter Pflicht-Bestätigung „Kunde hat AVV bestätigt“, protokolliert.
Auswertung: GET /api/funktionen/analyse/stats?projectId&range=7|30|90 (Portal holt beim Sammeldienst
GET /a/admin/stats/:siteKey, Token): Kennzahlen (Aufrufe, Besucher*, Kontakt-Klicks*, Zustimmungsquote),
Tagesverlauf, Top-Seiten, Herkunft, Länder, Geräte, Kontakt-Klicks nach Art, Banner-Zahlen
(*nur aus Einwilligungen – Hinweistext). Heatmap: POST …/heatmap-link { projectId, path, vp } ⇒ signierter
Link https://<domain><path>?__wk_heat=<token> (HMAC, 30 min); h.js lädt Punkte von
GET /a/heat?token=… und zeichnet sie (Canvas, eigene kleine Implementierung) über die Seite.
Ansicht handytauglich; Diagramme als leichtes SVG (keine Chart-Bibliothek nötig).
Rechtstexte (Entwürfe im Repo unter docs/rechtliches/, Upload in WOMS „Rechtliches“ durch den Nutzer):
AVV Website-Analyse (Art. 28 DSGVO; Gegenstand, Daten, Betroffene, TOMs, Unterauftragsverarbeiter
Hetzner, Löschung, Kontrollrechte), Leistungsbeschreibung (Umfang, Pflichten des Kunden: Banner nicht
umgehen, keine weiteren Tracker, Datenschutzerklärung pflegen), Abo-Bedingungen neue Fassung (Analyse als
Abo-Leistung), Vorlage /datenschutz-analyse.html (Art. 13: Zwecke, Rechtsgrundlagen § 25 Abs. 1 TDDDG /
Art. 6 Abs. 1 lit. a und f DSGVO, Empfänger, Speicherdauer, Widerruf, Rechte), Absatz WEBklar-
Datenschutzerklärung.
Fehlerfälle
Sammeldienst nicht erreichbar ⇒ Website läuft normal (Skript fängt Fehler, Beacon ohne Wirkung); Portal-Statistik zeigt „Auswertung gerade nicht erreichbar“. Länder-DB fehlt ⇒ Land „unbekannt“. Neubau nach Ein/Aus scheitert ⇒ Zustand bleibt gespeichert, Hinweis in der Kachel, nächster Neubau holt nach.
Tests
Sammeldienst (kein IP/UA gespeichert, Bots, Domain-Prüfung, Limit, Salz-Rotation, Verdichtung, Löschung),
Skript (jsdom/Playwright: ohne Annehmen nur pv+bn; GPC; Banner gleichwertig; Widerruf; Overlay),
Runner (Einsetzen/Entfernen, nur öffentlich, Maskierung, Zusatzseite), Portal (Abo-Pflicht, AVV-Pflicht,
Ticket, Abo-Ende-Job, Statistik-Proxy, Heatmap-Token), Playwright für Kachel, Auswertung, Banner (390 px).
Livegang (je Schritt mit OK des Nutzers)
L1 Sammeldienst-Container + Datenverzeichnis + DB-IP + Traefik-Route /a/ (ohne IP-Log) + Schema-Skript ·
L2 Portal/Runner pushen (Kachel noch „Kommt bald“ per Schalter ANALYSE_ENABLED=off) · L3 Probe auf einer
Wegwerf-Website (öffentlich) inkl. Banner, Heatmap, Löschung · L4 WOMS pushen, Rechtstexte durch den Nutzer
in „Rechtliches“, Schalter an · L5 Live-Test des Nutzers an einer echten Kunden-Website mit Wartungs-Abo.
Nicht Teil dieser Spec
Session-Aufzeichnung, Formularanalyse, Ladezeiten/JS-Fehler, UTM/Trichter, Einwilligung für fremde Inhalte (z. B. Google-Karte) über denselben Banner, Websites außerhalb des eigenen Hostings, Export.