From 9720cd95169cce33a493bcb215075eeb4b174d88 Mon Sep 17 00:00:00 2001 From: Till JS Date: Tue, 26 May 2026 14:21:04 +0200 Subject: [PATCH] =?UTF-8?q?chore(analytics):=20Umami-Kern=20entfernen=20?= =?UTF-8?q?=E2=80=94=20Injection,=20Client-Lib,=20Auth-Hook,=20Container,?= =?UTF-8?q?=20DB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Erster Schritt der Umami-Komplett-Entfernung (Entscheidung: kein Web-Analytics): - hooks.server.ts: injectUmamiAnalytics-Injection raus (stoppt Script-Load in der Unified-App) - packages/shared-utils/analytics-server.ts: GELÖSCHT (Script-Injection-Util) - packages/shared-utils/analytics.ts: zu No-op entkernt — window.umami/isUmamiAvailable raus, trackEvent no-op; alle 28 *Events-Aufrufer kompilieren weiter (senden nichts) - packages/shared-auth/authService.ts: inline-Umami-trackAuth-Hook + Aufrufe raus - infrastructure/docker-compose.gpu-box.yml: umami-Service (mana-mon-umami) raus - docker/init-db: CREATE DATABASE umami + GRANT raus - gelöscht: docs/ANALYTICS.md, scripts/mac-mini/setup-umami-db.sh, picture-landing .env.example VERBLEIBEND (separat, größer): ~60 weitere Dateien — 7 Landing-Layout.astro (eigene Script-Injection), website-blocks Analytics-Feature, Legal/Datenschutz, i18n×5, Admin-UI, ~20 Docs. Teils produkt-/rechts-sensibel → in Wellen. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/mana/apps/web/src/hooks.server.ts | 3 +- apps/picture/apps/landing/.env.example | 3 - docker/init-db/01-create-databases.sql | 2 - docs/ANALYTICS.md | 424 ------------------ infrastructure/docker-compose.gpu-box.yml | 18 - packages/shared-auth/src/core/authService.ts | 27 -- packages/shared-utils/src/analytics-server.ts | 43 -- packages/shared-utils/src/analytics.ts | 48 +- scripts/mac-mini/setup-umami-db.sh | 27 -- 9 files changed, 10 insertions(+), 585 deletions(-) delete mode 100644 apps/picture/apps/landing/.env.example delete mode 100644 docs/ANALYTICS.md delete mode 100644 packages/shared-utils/src/analytics-server.ts delete mode 100755 scripts/mac-mini/setup-umami-db.sh diff --git a/apps/mana/apps/web/src/hooks.server.ts b/apps/mana/apps/web/src/hooks.server.ts index 54d37b067..319abe1a7 100644 --- a/apps/mana/apps/web/src/hooks.server.ts +++ b/apps/mana/apps/web/src/hooks.server.ts @@ -1,5 +1,4 @@ import type { Handle } from '@sveltejs/kit'; -import { injectUmamiAnalytics } from '@mana/shared-utils/analytics-server'; import { setSecurityHeaders } from '@mana/shared-utils/security-headers'; /** @@ -226,7 +225,7 @@ window.__PUBLIC_MANA_ANALYTICS_URL__ = ${JSON.stringify(PUBLIC_MANA_ANALYTICS_UR window.__PUBLIC_AI_MISSION_GRANTS__ = ${JSON.stringify(PUBLIC_AI_MISSION_GRANTS)}; window.__PUBLIC_GLITCHTIP_DSN__ = ${JSON.stringify(PUBLIC_GLITCHTIP_DSN)}; `; - return injectUmamiAnalytics(html.replace('', `${envScript}`)); + return html.replace('', `${envScript}`); }, }); diff --git a/apps/picture/apps/landing/.env.example b/apps/picture/apps/landing/.env.example deleted file mode 100644 index 36877ecfb..000000000 --- a/apps/picture/apps/landing/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -# Umami Analytics -PUBLIC_UMAMI_URL=https://your-umami-instance.com -PUBLIC_UMAMI_WEBSITE_ID=your-website-id diff --git a/docker/init-db/01-create-databases.sql b/docker/init-db/01-create-databases.sql index 54b5f854f..b92887326 100644 --- a/docker/init-db/01-create-databases.sql +++ b/docker/init-db/01-create-databases.sql @@ -6,10 +6,8 @@ CREATE DATABASE mana_sync; -- Infrastructure databases (external tools) CREATE DATABASE glitchtip; -CREATE DATABASE umami; -- Grant privileges GRANT ALL PRIVILEGES ON DATABASE mana_platform TO mana; GRANT ALL PRIVILEGES ON DATABASE mana_sync TO mana; GRANT ALL PRIVILEGES ON DATABASE glitchtip TO mana; -GRANT ALL PRIVILEGES ON DATABASE umami TO mana; diff --git a/docs/ANALYTICS.md b/docs/ANALYTICS.md deleted file mode 100644 index 74ba345bd..000000000 --- a/docs/ANALYTICS.md +++ /dev/null @@ -1,424 +0,0 @@ -# Analytics & Event Tracking - -Mana verwendet Umami für Web Analytics. Alle Events werden zu `stats.mana.how` gesendet. - -## Umami Dashboard - -- **URL**: https://stats.mana.how -- **Public Stats**: Alle Websites haben Public Sharing aktiviert - -## Architektur - -Web-App Analytics werden über `hooks.server.ts` injiziert (nicht mehr hardcoded in `app.html`). - -``` -.env.development → UMAMI_WEBSITE_ID_CHAT=xxx - ↓ (scripts/generate-env.mjs) -apps/chat/apps/web/.env → PUBLIC_UMAMI_WEBSITE_ID=xxx - ↓ (process.env in hooks.server.ts) -injectUmamiAnalytics(html) → - - -``` - -### Astro Landing Pages - -```astro ---- -// Layout.astro - Script tag is already in ---- - - -``` - -### Development Mode - -Im Development-Modus ist Umami normalerweise nicht geladen (kein Script-Tag), daher werden Events stillschweigend ignoriert (`isUmamiAvailable()` gibt `false` zurück). Fehler beim Tracking werden als `console.warn` ausgegeben. - ---- - -## Event Naming Conventions - -1. **snake_case** für Event-Namen: `task_created`, nicht `taskCreated` -2. **Kurze, beschreibende Namen**: `signup_completed`, nicht `user_has_completed_signup_process` -3. **Konsistente Suffixe**: - - `_created`, `_updated`, `_deleted` für CRUD - - `_started`, `_completed`, `_canceled` für Prozesse - - `_clicked`, `_viewed` für UI-Interaktionen - -## Privacy - -- Keine persönlichen Daten in Events (keine E-Mails, Namen, etc.) -- Suchanfragen: Nur Länge wird getracked, nicht der Inhalt -- Error Messages: Auf 100 Zeichen gekürzt -- GDPR-konform: Umami ist privacy-focused und setzt keine Cookies - -## Umami Server - -- **Host**: Mac Mini (mana-server) -- **Container**: `mana-mon-umami` -- **Image**: `ghcr.io/umami-software/umami:postgresql-latest` -- **Datenbank**: PostgreSQL (`umami` DB, shared Postgres-Instanz) -- **Port**: 3000 (intern) → 8010 (extern), via Cloudflare Tunnel erreichbar unter stats.mana.how diff --git a/infrastructure/docker-compose.gpu-box.yml b/infrastructure/docker-compose.gpu-box.yml index f1e016e73..9a5a3d1de 100644 --- a/infrastructure/docker-compose.gpu-box.yml +++ b/infrastructure/docker-compose.gpu-box.yml @@ -80,24 +80,6 @@ services: retries: 3 start_period: 60s - umami: - image: ghcr.io/umami-software/umami:postgresql-v2.18.0 - container_name: mana-mon-umami - restart: unless-stopped - ports: - - '8010:3000' - environment: - DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@192.168.178.131:5432/umami - DATABASE_TYPE: postgresql - APP_SECRET: ${UMAMI_APP_SECRET} - DISABLE_TELEMETRY: '1' - healthcheck: - test: ['CMD-SHELL', 'wget -q -O- http://127.0.0.1:3000/api/heartbeat || exit 1'] - interval: 30s - timeout: 5s - retries: 3 - start_period: 30s - # ============================================ # Photon Geocoder (pre-existing user container, adopted into compose # 2026-05-07 to gain a healthcheck). Backs mana-geocoding's diff --git a/packages/shared-auth/src/core/authService.ts b/packages/shared-auth/src/core/authService.ts index 087afd241..05077a59e 100644 --- a/packages/shared-auth/src/core/authService.ts +++ b/packages/shared-auth/src/core/authService.ts @@ -23,20 +23,6 @@ import { getAppSettings as getAppSettingsFromToken, } from './jwtUtils'; -/** - * Inline analytics helper - tracks auth events via Umami if available. - * No-ops silently in environments without Umami (mobile, SSR, dev). - */ -function trackAuth(event: string, data?: Record): void { - if (typeof window !== 'undefined' && (window as any).umami?.track) { - try { - (window as any).umami.track(event, { ...data, module: 'auth' }); - } catch { - // Silently ignore tracking errors - } - } -} - /** * Default storage keys */ @@ -135,11 +121,9 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa // SSO cookie is nice-to-have, don't fail login if this fails } - trackAuth('login', { method: 'email' }); return { success: true }; } catch (error) { console.error('Error signing in:', error); - trackAuth('login_failed', { method: 'email' }); return { success: false, error: error instanceof Error ? error.message : 'Unknown error during sign in', @@ -175,11 +159,9 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa // If emailVerified is false, the user needs to verify their email before login const needsVerification = data?.user?.emailVerified === false; - trackAuth('signup', { method: 'email' }); return { success: true, needsVerification }; } catch (error) { console.error('Error signing up:', error); - trackAuth('signup_failed', { method: 'email' }); return { success: false, error: error instanceof Error ? error.message : 'Unknown error during sign up', @@ -203,7 +185,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa }).catch((err) => console.error('Error logging out on server:', err)); } - trackAuth('logout'); await service.clearAuthStorage(); } catch (error) { console.error('Error signing out:', error); @@ -228,7 +209,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa return service.handleAuthError(response.status, errorData); } - trackAuth('password_reset_requested'); return { success: true }; } catch (error) { console.error('Error sending password reset email:', error); @@ -484,7 +464,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa return { success: false, error: err.message || 'Passkey registration failed' }; } - trackAuth('passkey_registered'); return { success: true }; } catch (error) { // User cancelled or WebAuthn error @@ -572,14 +551,12 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa storage.setItem(storageKeys.USER_EMAIL, data.user?.email || ''), ]); - trackAuth('login', { method: 'passkey' }); return { success: true }; } catch (error) { if (error instanceof Error && error.name === 'NotAllowedError') { return { success: false, error: 'Passkey authentication was cancelled' }; } console.error('Passkey authentication error:', error); - trackAuth('login_failed', { method: 'passkey' }); return { success: false, error: error instanceof Error ? error.message : 'Passkey authentication failed', @@ -758,7 +735,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa } } - trackAuth('login', { method: '2fa' }); return { success: true }; } catch (error) { return { @@ -805,7 +781,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa } } - trackAuth('login', { method: 'backup_code' }); return { success: true }; } catch (error) { return { @@ -892,7 +867,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa return { success: false, error: err.message || 'Failed to send magic link' }; } - trackAuth('magic_link_sent'); return { success: true }; } catch (error) { return { @@ -1297,7 +1271,6 @@ export function createAuthService(config: AuthServiceConfig): AuthServiceInterfa ]); console.log('SSO: Successfully authenticated via session cookie'); - trackAuth('login', { method: 'sso' }); return { success: true }; } catch (error) { // SSO failed - this is expected if user hasn't logged in anywhere diff --git a/packages/shared-utils/src/analytics-server.ts b/packages/shared-utils/src/analytics-server.ts deleted file mode 100644 index 16a5927b0..000000000 --- a/packages/shared-utils/src/analytics-server.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Server-side Umami Analytics Utilities - * - * Used in SvelteKit hooks.server.ts to inject the Umami analytics script. - * Reads the website ID from the PUBLIC_UMAMI_WEBSITE_ID environment variable. - * - * @example - * ```typescript - * import { injectUmamiAnalytics } from '@mana/shared-utils/analytics-server'; - * - * export const handle: Handle = async ({ event, resolve }) => { - * return resolve(event, { - * transformPageChunk: ({ html }) => injectUmamiAnalytics(html), - * }); - * }; - * ``` - */ - -const UMAMI_SCRIPT_URL = 'https://stats.mana.how/script.js'; - -/** - * Get the Umami analytics script tag. - * Returns empty string if no website ID is configured. - */ -export function getUmamiScriptTag(websiteId?: string): string { - const id = websiteId || process.env.PUBLIC_UMAMI_WEBSITE_ID || ''; - if (!id) return ''; - return ``; -} - -/** - * Inject the Umami analytics script into HTML. - * Designed to be used in SvelteKit's transformPageChunk. - * - * @param html - The HTML string to inject the script into - * @param websiteId - Optional website ID override (defaults to PUBLIC_UMAMI_WEBSITE_ID env var) - * @returns The HTML with the Umami script injected before - */ -export function injectUmamiAnalytics(html: string, websiteId?: string): string { - const scriptTag = getUmamiScriptTag(websiteId); - if (!scriptTag) return html; - return html.replace('', `${scriptTag}\n`); -} diff --git a/packages/shared-utils/src/analytics.ts b/packages/shared-utils/src/analytics.ts index 0faaae4be..79d6c4374 100644 --- a/packages/shared-utils/src/analytics.ts +++ b/packages/shared-utils/src/analytics.ts @@ -1,37 +1,13 @@ /** - * Umami Analytics Utility + * Event-API — Web-Analytics DEAKTIVIERT (2026-05-26). * - * Provides type-safe event tracking for all Mana apps. - * Events are automatically sent to Umami at stats.mana.how - * - * @example - * ```typescript - * import { trackEvent, trackClick } from '@mana/shared-utils/analytics'; - * - * // Track a custom event - * trackEvent('signup_completed', { method: 'email' }); - * - * // Track a button click - * trackClick('cta_hero', 'Get Started'); - * ``` + * Verein-weit kein Besucher-Tracking mehr (keine Tracking-Pixel, auch + * nicht „nur Analytics" — siehe mana/docs/MISSION.md). Die `*Events`- + * Objekte und `track*`-Funktionen bleiben als No-ops bestehen, damit die + * bestehenden Aufruf-Stellen quer durch die Module weiter kompilieren — + * sie senden nichts mehr. */ -// Umami types -declare global { - interface Window { - umami?: { - track: (eventName: string, eventData?: Record) => void; - }; - } -} - -/** - * Check if Umami is available - */ -export function isUmamiAvailable(): boolean { - return typeof window !== 'undefined' && typeof window.umami?.track === 'function'; -} - /** * Track a custom event * @@ -45,15 +21,9 @@ export function trackEvent( eventName: string, data?: Record ): void { - if (!isUmamiAvailable()) { - return; - } - - try { - window.umami!.track(eventName, data); - } catch (error) { - console.warn('[Analytics] Failed to track event:', eventName, error); - } + // No-op: Web-Analytics entfernt (2026-05-26). Bewusst kein Tracking. + void eventName; + void data; } /** diff --git a/scripts/mac-mini/setup-umami-db.sh b/scripts/mac-mini/setup-umami-db.sh deleted file mode 100755 index 4e63a510d..000000000 --- a/scripts/mac-mini/setup-umami-db.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Setup Umami database on Mac Mini -# Run this script after starting PostgreSQL container - -set -e - -echo "Creating Umami database..." - -# Check if running inside docker network or from host -if docker ps | grep -q mana-postgres; then - docker exec -i mana-postgres psql -U postgres <