# Modul: Analytics (Seitenaufrufe + Phone-Click-Tracking) > DSGVO-konformes Tracking ohne externe Dienste: Seitenaufrufe mit Verweildauer, Browser/OS/Gerät-Erkennung, anonymisierte IP (letztes IPv4-Oktett → 0). Zusätzlich automatisches Tracking aller `tel:`-Link-Klicks nach Quelle/Element. Admin-Dashboard mit KPI-Cards, Zeitreihen und Top-Seiten. --- ## Enthaltene Dateien | Ziel im neuen Projekt | Inhalt | |---|---| | `lib/analytics.ts` | Bot-Filter, IP-Anonymisierung, Device/Browser/OS-Parser | | `components/analytics/PageTracker.tsx` | Client-Komponente: Seitenaufruf + Verweildauer + Phone-Click-Tracking | | `app/api/analytics/track/route.ts` | POST: Seitenaufruf speichern (öffentlich, kein Auth) | | `app/api/analytics/track-phone-click/route.ts` | POST: Telefon-Click speichern (öffentlich) | | `app/api/admin/analytics/phone-calls/route.ts` | GET: Aggregierte Phone-Click-Daten (requireAdmin) | | `app/admin/analytics/page.tsx` | Admin-Dashboard mit Tabs: Seitenaufrufe + Phone-Calls | | `migrations/MIGRATIONS_PAGE_VIEWS.sql` | Tabelle `page_views` | | `migrations/MIGRATIONS_PHONE_CLICKS.sql` | Tabelle `phone_clicks` | --- ## Voraussetzungen Keine zusätzlichen npm-Pakete. Benötigt: - `lib/supabase.ts` (Service Client) - `lib/admin-auth.ts` (für `requireAdmin` im Admin-Endpunkt, aus Modul 02) --- ## Umgebungsvariablen Keine zusätzlichen. Nutzt bestehende Supabase-Variablen. --- ## Datenbank-Migrationen (Supabase) ``` migrations/MIGRATIONS_PAGE_VIEWS.sql → Tabelle page_views migrations/MIGRATIONS_PHONE_CLICKS.sql → Tabelle phone_clicks ``` Tabellen-Übersicht: ``` page_views: path, timestamp, ip_anon, device_type, browser, os, referrer, session_id, duration_ms, is_bot phone_clicks: phone_number, source_page, source_element, session_id, ip_anonymized, device_type, browser, os, timestamp ``` Supabase-Typen (`lib/supabase.ts`) ergänzen: ```ts page_views: { Row: { id: string; path: string; timestamp: string; ip_anon: string | null; device_type: string | null; browser: string | null; os: string | null; referrer: string | null; session_id: string; duration_ms: number | null; is_bot: boolean } } phone_clicks: { Row: { id: number; phone_number: string; source_page: string; source_element: string; session_id: string | null; ip_anonymized: string | null; device_type: string | null; browser: string | null; os: string | null; timestamp: string } } ``` --- ## Einbindung Schritt für Schritt ### 1. Dateien kopieren ### 2. PageTracker in Root-Layout einbinden (`app/layout.tsx`) ```tsx import { PageTracker } from "@/components/analytics/PageTracker"; export default function RootLayout({ children }) { return ( {children} ); } ``` ### 3. Tel-Links mit `data-source-element` versehen Der PageTracker hört automatisch auf Klicks von ``. Damit die Quelle erfasst wird, muss das Attribut gesetzt sein: ```tsx Anrufen ``` Empfohlene Element-Namen (Konvention: lowercase, kebab-case): - `header`, `footer`, `hero`, `cta-banner`, `kontakt-form`, `sidebar` ### 4. Admin-Dashboard verlinken ```tsx // In Admin-Navigation Analytics ``` ### 5. Admin-Routen aus Tracking ausschließen `PageTracker.tsx` filtert bereits `/admin/*` und `/api/*` – keine Anpassung nötig. --- ## Anpassungspunkte | Was | Wo | |---|---| | Ausgeschlossene Pfade | `components/analytics/PageTracker.tsx` → `EXCLUDED_PATHS` | | Datenaufbewahrung (13 Monate) | Supabase Cron: `DELETE FROM page_views WHERE timestamp < now() - interval '13 months'` | | Bot-Filter-Pattern | `lib/analytics.ts` → `BOT_PATTERNS` Array | | Dashboard-Zeiträume | `app/admin/analytics/page.tsx` → Filter-Buttons | | Geo-Lookup aktivieren | `app/api/analytics/track-phone-click/route.ts` → `GEO_LOOKUP_ENABLED` env var | --- ## Integrations-Prompt Kopiere diesen Prompt in eine neue KI-Konversation, nachdem du die `files/` in dein Projekt kopiert hast. Ersetze alle `[PLATZHALTER]`. ``` Ich integriere das Analytics-Modul (DSGVO-konforme Seitenaufrufe + Phone-Click-Tracking) in mein Next.js/Supabase-Projekt. PROJEKT-KONTEXT: - Admin-Auth-Modul (02) ist bereits integriert (requireAdmin verfügbar) - lib/supabase.ts mit Service Client vorhanden - Admin-Bereich unter /admin BEREITS KOPIERTE DATEIEN (aus modules/03-analytics/files/): - lib/analytics.ts - components/analytics/PageTracker.tsx - app/api/analytics/track/route.ts - app/api/analytics/track-phone-click/route.ts - app/api/admin/analytics/phone-calls/route.ts - app/admin/analytics/page.tsx AUFGABEN – führe sie der Reihe nach aus: 1. SUPABASE-MIGRATIONEN: Führe diese SQLs im Supabase SQL-Editor aus: -- Aus migrations/MIGRATIONS_PAGE_VIEWS.sql: CREATE TABLE IF NOT EXISTS page_views ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), path text NOT NULL, timestamp timestamptz NOT NULL DEFAULT now(), ip_anon text, device_type text CHECK (device_type IN ('desktop','tablet','mobile')), browser text, os text, referrer text, session_id text NOT NULL, duration_ms int, is_bot boolean NOT NULL DEFAULT false ); CREATE INDEX IF NOT EXISTS idx_pv_timestamp ON page_views (timestamp DESC); CREATE INDEX IF NOT EXISTS idx_pv_path ON page_views (path); CREATE INDEX IF NOT EXISTS idx_pv_session ON page_views (session_id); ALTER TABLE page_views ENABLE ROW LEVEL SECURITY; CREATE POLICY "Service-Role Vollzugriff" ON page_views USING (true) WITH CHECK (true); -- Aus migrations/MIGRATIONS_PHONE_CLICKS.sql: CREATE TABLE IF NOT EXISTS phone_clicks ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, phone_number TEXT NOT NULL, source_page TEXT NOT NULL, source_element TEXT NOT NULL, session_id TEXT, ip_anonymized TEXT, device_type TEXT, browser TEXT, os TEXT, timestamp TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_phone_clicks_timestamp ON phone_clicks(timestamp DESC); ALTER TABLE phone_clicks DISABLE ROW LEVEL SECURITY; 2. SUPABASE-TYPEN: Lies lib/supabase.ts und ergänze in Database.public.Tables: page_views: { Row: { id: string; path: string; timestamp: string; ip_anon: string | null; device_type: string | null; browser: string | null; os: string | null; referrer: string | null; session_id: string; duration_ms: number | null; is_bot: boolean } } phone_clicks: { Row: { id: number; phone_number: string; source_page: string; source_element: string; session_id: string | null; ip_anonymized: string | null; device_type: string | null; browser: string | null; os: string | null; timestamp: string } } 3. PAGE-TRACKER einbinden: Lies app/layout.tsx. Füge den Import und die Komponente im hinzu (vor {children}): import { PageTracker } from "@/components/analytics/PageTracker"; // Im JSX: 4. TEL-LINKS mit Tracking versehen: Suche im gesamten Projekt nach href="tel: Füge bei jedem gefundenen Link das Attribut data-source-element="[ELEMENT_NAME]" hinzu. Konvention für [ELEMENT_NAME]: header, footer, hero, cta-banner, kontakt-form (lowercase, kebab-case) 5. ADMIN-NAV ergänzen: Lies die Admin-Navigations-Datei (meist components/admin/AdminNav.tsx). Füge einen Link zu /admin/analytics hinzu. 6. TEST: a) Dev-Server starten, /kontakt oder eine andere Seite aufrufen b) Supabase → Table page_views → neuer Eintrag sollte erscheinen c) Auf eine Telefonnummer klicken → Supabase → Table phone_clicks → neuer Eintrag d) /admin/analytics aufrufen → KPI-Cards sollten Daten zeigen Lies jede Datei vor dem Bearbeiten. Melde wenn alle Schritte abgeschlossen sind. ```