182 lines
7.6 KiB
Markdown
182 lines
7.6 KiB
Markdown
# 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 (
|
||
<html>
|
||
<body>
|
||
<PageTracker />
|
||
{children}
|
||
</body>
|
||
</html>
|
||
);
|
||
}
|
||
```
|
||
|
||
### 3. Tel-Links mit `data-source-element` versehen
|
||
Der PageTracker hört automatisch auf Klicks von `<a href="tel:...">`. Damit die Quelle erfasst wird, muss das Attribut gesetzt sein:
|
||
```tsx
|
||
<a href="tel:+49123456789" data-source-element="header">Anrufen</a>
|
||
```
|
||
|
||
Empfohlene Element-Namen (Konvention: lowercase, kebab-case):
|
||
- `header`, `footer`, `hero`, `cta-banner`, `kontakt-form`, `sidebar`
|
||
|
||
### 4. Admin-Dashboard verlinken
|
||
```tsx
|
||
// In Admin-Navigation
|
||
<Link href="/admin/analytics">Analytics</Link>
|
||
```
|
||
|
||
### 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 <body> hinzu (vor {children}):
|
||
import { PageTracker } from "@/components/analytics/PageTracker";
|
||
// Im JSX:
|
||
<PageTracker />
|
||
|
||
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.
|
||
```
|