diff --git a/.claude/plans/referral-system.md b/.claude/plans/referral-system.md deleted file mode 100644 index 4b6fb9545..000000000 --- a/.claude/plans/referral-system.md +++ /dev/null @@ -1,1247 +0,0 @@ -# ManaCore Referral System - Design Document - -> **Status**: Finalisiert - Bereit zur Implementierung -> **Erstellt**: 2025-12-07 -> **Autor**: Claude Code - ---- - -## 1. Übersicht & Ziele - -### 1.1 Was wollen wir erreichen? - -Ein **app-übergreifendes Referral-System** für das ManaCore-Ökosystem, das: -- Organisches Wachstum durch User-Empfehlungen fördert -- User mit Credits bei jedem Stage-Übergang belohnt -- Transparentes Tracking aller Referral-Stages bietet -- Tier-basierte Belohnungen für Power-Referrer ermöglicht -- Cross-App-Engagement der geworbenen User trackt und belohnt -- Umfassende Fraud-Detection implementiert - -### 1.2 Finale Entscheidungen - -| Aspekt | Entscheidung | -|--------|--------------| -| Belohnungsart | Nur Credits, keine Geld-Auszahlung | -| Code-Generierung | Automatisch für jeden User + unbegrenzte Custom-Codes (mit Rate-Limit) | -| Code-Format | Nur Random, kurz (z.B. `X7K9P2`) | -| Code-Scope | Global einzigartig (über alle Apps) | -| Stage-Tracking | Alle Stages werden getrackt mit Bonus bei jedem Übergang | -| Retention | Wird getrackt (30 Tage aktiv) | -| E-Mail-Verifizierung | Bleibt deaktiviert | -| Tier-System | Ja, Lifetime-basiert, nicht rückwirkend | -| Referee-Bonus | Nicht tier-abhängig (alle gleich) | -| Cross-App | Codes flexibel nutzbar + Bonus für Cross-App-Nutzung | -| Fraud-Detection | Umfassend implementiert | - ---- - -## 2. Referral-Stages & Bonus-Struktur - -### 2.1 Stage-Definitionen mit Boni - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ REFERRAL LIFECYCLE │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ [1] REGISTERED Account erstellt │ -│ │ → Referrer: 5 Credits │ -│ │ → Referee: +25 Bonus (zusätzlich zu 150 Signup) │ -│ ▼ │ -│ [2] ACTIVATED Erste Credit-Nutzung (in irgendeiner App) │ -│ │ → Referrer: 10 Credits (× Tier-Multiplier) │ -│ ▼ │ -│ [3] QUALIFIED Erster Credit-Kauf getätigt │ -│ │ → Referrer: 25 Credits (× Tier-Multiplier) │ -│ ▼ │ -│ [4] RETAINED 30 Tage nach Registrierung noch aktiv │ -│ → Referrer: 15 Credits (× Tier-Multiplier) │ -│ │ -│ [+] CROSS_APP Referee nutzt weitere App (einmalig pro App) │ -│ → Referrer: 5 Credits pro App (× Tier-Multiplier) │ -│ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -### 2.2 Bonus-Tabelle - -#### Referrer-Boni (wer wirbt) - -| Event | Basis-Bonus | Bronze (1x) | Silver (1.5x) | Gold (2x) | Platinum (3x) | -|-------|-------------|-------------|---------------|-----------|---------------| -| Registered | 5 | 5 | 7 | 10 | 15 | -| Activated | 10 | 10 | 15 | 20 | 30 | -| Qualified | 25 | 25 | 37 | 50 | 75 | -| Retained (30d) | 15 | 15 | 22 | 30 | 45 | -| Cross-App (pro App) | 5 | 5 | 7 | 10 | 15 | - -**Max pro Referral:** 55 Basis + 13 Apps × 5 = **120 Credits** (Bronze) bis **360 Credits** (Platinum) - -#### Referee-Boni (wer geworben wird) - -| Event | Bonus | -|-------|-------| -| Registrierung mit Code | +25 Credits (= 175 total statt 150) | - ---- - -## 3. Tier-System - -### 3.1 Tier-Struktur (Lifetime-basiert) - -| Tier | Qualifizierte Referrals | Multiplier | Badge | -|------|------------------------|------------|-------| -| Bronze | 0-4 | 1.0x | 🥉 | -| Silver | 5-14 | 1.5x | 🥈 | -| Gold | 15-29 | 2.0x | 🥇 | -| Platinum | 30+ | 3.0x | 💎 | - -### 3.2 Wichtige Regeln - -- **Lifetime-basiert**: Einmal erreichte Qualified-Referrals zählen für immer -- **Nicht rückwirkend**: Bestehende Referrals bekommen keinen nachträglichen Bonus -- **Nur für Referrer**: Referee-Bonus ist für alle gleich (25 Credits) -- **Berechnung**: Nur QUALIFIED Referrals zählen für Tier-Aufstieg - ---- - -## 4. Code-System - -### 4.1 Code-Typen - -| Typ | Beschreibung | Format | Beispiel | -|-----|--------------|--------|----------| -| `auto` | Automatisch bei User-Erstellung | 6 Zeichen alphanumerisch | `X7K9P2` | -| `custom` | Vom User erstellt | 3-20 Zeichen, alphanumerisch + Bindestrich | `TILLCODES` | -| `campaign` | Admin-generiert | Beliebig | `LAUNCH2024` | - -### 4.2 Code-Regeln - -- **Global einzigartig**: Ein Code existiert nur einmal im gesamten System -- **Keine Limits**: User können unbegrenzt Custom-Codes erstellen -- **Rate-Limit**: Max 10 Code-Erstellungen pro Stunde pro User -- **Flexibel**: Jeder Code funktioniert für alle Apps (erstellt ManaCore-Account) -- **Tracking**: Ursprungs-App wird getrackt (woher kam der Link?) - -### 4.3 Code-Generierung - -```typescript -// Auto-Code Format: 6 alphanumerische Zeichen (ohne verwechselbare: 0/O, 1/I/L) -const CHARSET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; - -function generateCode(): string { - return Array.from({ length: 6 }, () => - CHARSET[Math.floor(Math.random() * CHARSET.length)] - ).join(''); -} -// Beispiele: X7K9P2, ABCD34, MNPQ78 -``` - ---- - -## 5. Cross-App-Tracking - -### 5.1 Konzept - -Wenn ein geworbener User eine neue App zum ersten Mal nutzt, erhält der Referrer einen Bonus: - -``` -User "Till" wirbt "Max" über Chat -├── Max registriert sich → Till: +5 Credits -├── Max nutzt Chat (Activation) → Till: +10 Credits -├── Max kauft Credits → Till: +25 Credits -├── Max nutzt Picture (neu!) → Till: +5 Credits (Cross-App) -├── Max nutzt Calendar (neu!) → Till: +5 Credits (Cross-App) -└── 30 Tage später → Till: +15 Credits (Retention) - -Total für Till: 65 Credits (Bronze) bis 195 Credits (Platinum) -``` - -### 5.2 App-Liste für Cross-App-Tracking - -```typescript -const TRACKABLE_APPS = [ - 'chat', // ManaChat - 'picture', // ManaPicture - 'presi', // Presi - 'mail', // ManaMail - 'manadeck', // ManaDeck - 'todo', // ManaTodo - 'calendar', // ManaCalendar - 'contacts', // ManaContacts - 'finance', // ManaFinance - 'clock', // ManaClock - 'zitare', // Zitare - 'storage', // ManaStorage - 'moodlit', // Moodlit -]; -// 13 Apps = max 65 Cross-App Credits (Bronze) bis 195 (Platinum) -``` - ---- - -## 6. Fraud-Detection System - -### 6.1 Übersicht - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ FRAUD DETECTION LAYERS │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ Layer 1: Prevention (vor Registrierung) │ -│ ├── Rate-Limiting auf Code-Validierung │ -│ ├── Self-Referral-Block │ -│ └── Captcha bei verdächtigen Patterns │ -│ │ -│ Layer 2: Detection (bei Registrierung) │ -│ ├── IP-Fingerprinting │ -│ ├── Device-Fingerprinting │ -│ ├── Email-Domain-Analyse │ -│ └── Timing-Analyse │ -│ │ -│ Layer 3: Verification (nach Registrierung) │ -│ ├── Minimum-Zeit bis Qualification (24h) │ -│ ├── Behavior-Analyse │ -│ └── Cross-Reference mit bekannten Fraud-Patterns │ -│ │ -│ Layer 4: Enforcement (bei Verdacht) │ -│ ├── Auto-Hold für Bonus-Auszahlung │ -│ ├── Manual Review Queue │ -│ └── Account-Suspension bei Bestätigung │ -│ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -### 6.2 Fraud-Signale & Scoring - -| Signal | Punkte | Beschreibung | -|--------|--------|--------------| -| Same IP | +30 | Gleiche IP wie Referrer | -| Same Device | +50 | Gleicher Device-Fingerprint | -| Disposable Email | +20 | Wegwerf-Email-Domain | -| Similar Email | +25 | Email ähnlich wie Referrer (z.B. till1@, till2@) | -| Rapid Registration | +15 | Registrierung < 5 Min nach Code-Abruf | -| Bulk Registrations | +40 | 5+ Registrierungen vom gleichen Referrer in 1h | -| VPN/Proxy | +20 | Bekannte VPN/Proxy-IP | -| New Account Referrer | +15 | Referrer-Account < 7 Tage alt | -| Instant Qualification | +35 | Kauf < 1h nach Registrierung | -| Minimal Activity | +25 | Keine echte App-Nutzung vor Kauf | - -**Fraud-Score Thresholds:** -- 0-29: ✅ Low Risk → Automatische Bonus-Auszahlung -- 30-59: ⚠️ Medium Risk → Verzögerte Auszahlung (48h Hold) -- 60-89: 🚨 High Risk → Auto-Hold + Manual Review -- 90+: 🛑 Critical → Bonus blockiert + Account-Flag - -### 6.3 Rate-Limits - -| Aktion | Limit | Zeitraum | -|--------|-------|----------| -| Code-Validierung | 20 | pro Minute pro IP | -| Code-Erstellung | 10 | pro Stunde pro User | -| Registrierungen pro Code | 50 | pro Tag | -| Registrierungen pro Referrer | 20 | pro Tag | -| Bonus-Claims | 100 | pro Tag pro Referrer | - -### 6.4 Timing-Regeln - -| Regel | Wert | Beschreibung | -|-------|------|--------------| -| Min. Zeit bis Activation | 5 Min | Nach Registrierung | -| Min. Zeit bis Qualification | 24h | Nach Registrierung | -| Retention-Check | 30 Tage | Nach Registrierung | -| Fraud-Review-Window | 7 Tage | Nach Qualification | - -### 6.5 Auto-Hold System - -```typescript -interface BonusHold { - id: string; - referralId: string; - userId: string; // Wer bekommt den Bonus - amount: number; - reason: 'fraud_score' | 'rate_limit' | 'manual_flag'; - fraudScore: number; - fraudSignals: string[]; // ['same_ip', 'rapid_registration'] - status: 'held' | 'released' | 'rejected'; - holdUntil: Date; // Auto-Release nach X Tagen wenn ok - reviewedBy?: string; // Admin-ID - reviewedAt?: Date; - createdAt: Date; -} -``` - -### 6.6 Device & IP Fingerprinting - -```typescript -interface FraudFingerprint { - id: string; - - // IP-Daten - ipAddress: string; - ipHash: string; // Für Datenschutz - ipType: 'residential' | 'datacenter' | 'vpn' | 'proxy' | 'tor'; - ipCountry: string; - ipCity?: string; - - // Device-Daten - deviceFingerprint: string; - userAgent: string; - screenResolution?: string; - timezone?: string; - language?: string; - - // Tracking - firstSeenAt: Date; - lastSeenAt: Date; - registrationCount: number; - flaggedCount: number; -} -``` - ---- - -## 7. Datenbank-Schema - -### 7.1 Neue Tabellen - -```sql --- Schema erstellen -CREATE SCHEMA IF NOT EXISTS referrals; - --- ============================================ --- CORE TABLES --- ============================================ - --- Referral-Codes (global einzigartig) -CREATE TABLE referrals.codes ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id TEXT NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, - code TEXT NOT NULL UNIQUE, -- Global einzigartig - type TEXT NOT NULL DEFAULT 'auto', -- 'auto', 'custom', 'campaign' - source_app_id TEXT, -- App wo Code erstellt wurde - is_active BOOLEAN DEFAULT true, - uses_count INTEGER DEFAULT 0, - max_uses INTEGER, -- NULL = unbegrenzt - expires_at TIMESTAMPTZ, -- NULL = nie - metadata JSONB DEFAULT '{}', - created_at TIMESTAMPTZ DEFAULT now(), - - CONSTRAINT code_format CHECK (code ~ '^[A-Z0-9-]{3,20}$') -); - -CREATE INDEX codes_lookup_idx ON referrals.codes(code) WHERE is_active = true; -CREATE INDEX codes_user_idx ON referrals.codes(user_id); - --- Referral-Beziehungen -CREATE TABLE referrals.relationships ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - referrer_id TEXT NOT NULL REFERENCES auth.users(id), - referee_id TEXT NOT NULL REFERENCES auth.users(id) UNIQUE, - code_id UUID NOT NULL REFERENCES referrals.codes(id), - source_app_id TEXT, -- App über die geworben wurde - - -- Stage Tracking - status TEXT NOT NULL DEFAULT 'registered', - registered_at TIMESTAMPTZ NOT NULL DEFAULT now(), - activated_at TIMESTAMPTZ, - qualified_at TIMESTAMPTZ, - retained_at TIMESTAMPTZ, - - -- Fraud - fraud_score INTEGER DEFAULT 0, - fraud_signals TEXT[] DEFAULT '{}', - is_flagged BOOLEAN DEFAULT false, - - created_at TIMESTAMPTZ DEFAULT now(), - updated_at TIMESTAMPTZ DEFAULT now(), - - CONSTRAINT no_self_referral CHECK (referrer_id != referee_id) -); - -CREATE INDEX relationships_referrer_idx ON referrals.relationships(referrer_id); -CREATE INDEX relationships_referee_idx ON referrals.relationships(referee_id); -CREATE INDEX relationships_status_idx ON referrals.relationships(status); -CREATE INDEX relationships_flagged_idx ON referrals.relationships(is_flagged) WHERE is_flagged = true; - --- Cross-App-Tracking -CREATE TABLE referrals.cross_app_activations ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - relationship_id UUID NOT NULL REFERENCES referrals.relationships(id), - app_id TEXT NOT NULL, - activated_at TIMESTAMPTZ DEFAULT now(), - bonus_paid BOOLEAN DEFAULT false, - - UNIQUE(relationship_id, app_id) -); - -CREATE INDEX cross_app_relationship_idx ON referrals.cross_app_activations(relationship_id); - --- User Tier Status -CREATE TABLE referrals.user_tiers ( - user_id TEXT PRIMARY KEY REFERENCES auth.users(id), - tier TEXT NOT NULL DEFAULT 'bronze', - qualified_count INTEGER DEFAULT 0, - total_earned INTEGER DEFAULT 0, -- Lifetime Credits durch Referrals - created_at TIMESTAMPTZ DEFAULT now(), - updated_at TIMESTAMPTZ DEFAULT now() -); - --- ============================================ --- BONUS & TRANSACTION TABLES --- ============================================ - --- Bonus-Events (Audit-Trail) -CREATE TABLE referrals.bonus_events ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - relationship_id UUID NOT NULL REFERENCES referrals.relationships(id), - user_id TEXT NOT NULL REFERENCES auth.users(id), - event_type TEXT NOT NULL, -- 'registered', 'activated', 'qualified', 'retained', 'cross_app' - app_id TEXT, -- Für cross_app events - credits_base INTEGER NOT NULL, -- Basis-Credits - tier_multiplier REAL NOT NULL DEFAULT 1.0, - credits_final INTEGER NOT NULL, -- Nach Multiplier - tier_at_time TEXT NOT NULL, - transaction_id UUID, -- Referenz zu credits.transactions - - -- Hold-Status - status TEXT DEFAULT 'pending', -- 'pending', 'paid', 'held', 'rejected' - hold_reason TEXT, - hold_until TIMESTAMPTZ, - released_at TIMESTAMPTZ, - - created_at TIMESTAMPTZ DEFAULT now() -); - -CREATE INDEX bonus_events_relationship_idx ON referrals.bonus_events(relationship_id); -CREATE INDEX bonus_events_user_idx ON referrals.bonus_events(user_id); -CREATE INDEX bonus_events_status_idx ON referrals.bonus_events(status); - --- ============================================ --- FRAUD DETECTION TABLES --- ============================================ - --- IP/Device Fingerprints -CREATE TABLE referrals.fingerprints ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - - -- IP - ip_hash TEXT NOT NULL, -- SHA256 der IP - ip_type TEXT DEFAULT 'unknown', -- 'residential', 'datacenter', 'vpn', 'proxy', 'tor' - ip_country TEXT, - ip_asn TEXT, - - -- Device - device_hash TEXT, -- Fingerprint-Hash - user_agent_hash TEXT, - - -- Stats - first_seen_at TIMESTAMPTZ DEFAULT now(), - last_seen_at TIMESTAMPTZ DEFAULT now(), - registration_count INTEGER DEFAULT 0, - flagged_count INTEGER DEFAULT 0, - - UNIQUE(ip_hash, device_hash) -); - -CREATE INDEX fingerprints_ip_idx ON referrals.fingerprints(ip_hash); -CREATE INDEX fingerprints_device_idx ON referrals.fingerprints(device_hash); - --- Fingerprint zu User Mapping -CREATE TABLE referrals.user_fingerprints ( - user_id TEXT NOT NULL REFERENCES auth.users(id), - fingerprint_id UUID NOT NULL REFERENCES referrals.fingerprints(id), - seen_at TIMESTAMPTZ DEFAULT now(), - context TEXT, -- 'registration', 'login', 'code_validation' - - PRIMARY KEY (user_id, fingerprint_id) -); - --- Fraud-Flags (für Muster-Erkennung) -CREATE TABLE referrals.fraud_patterns ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - pattern_type TEXT NOT NULL, -- 'email_domain', 'ip_range', 'device_pattern' - pattern_value TEXT NOT NULL, - severity TEXT DEFAULT 'medium', -- 'low', 'medium', 'high', 'critical' - score_impact INTEGER NOT NULL, - description TEXT, - is_active BOOLEAN DEFAULT true, - created_by TEXT, - created_at TIMESTAMPTZ DEFAULT now() -); - --- Rate-Limit Tracking -CREATE TABLE referrals.rate_limits ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - identifier TEXT NOT NULL, -- IP, User-ID, oder Code - identifier_type TEXT NOT NULL, -- 'ip', 'user', 'code' - action TEXT NOT NULL, -- 'code_validation', 'code_creation', 'registration' - count INTEGER DEFAULT 1, - window_start TIMESTAMPTZ DEFAULT now(), - window_end TIMESTAMPTZ NOT NULL, - - UNIQUE(identifier, identifier_type, action, window_start) -); - -CREATE INDEX rate_limits_lookup_idx ON referrals.rate_limits(identifier, identifier_type, action, window_end); - --- Admin Review Queue -CREATE TABLE referrals.review_queue ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - relationship_id UUID NOT NULL REFERENCES referrals.relationships(id), - fraud_score INTEGER NOT NULL, - fraud_signals TEXT[] NOT NULL, - priority TEXT DEFAULT 'medium', -- 'low', 'medium', 'high', 'critical' - status TEXT DEFAULT 'pending', -- 'pending', 'approved', 'rejected', 'escalated' - assigned_to TEXT, - notes TEXT, - reviewed_at TIMESTAMPTZ, - created_at TIMESTAMPTZ DEFAULT now() -); - -CREATE INDEX review_queue_status_idx ON referrals.review_queue(status, priority); - --- ============================================ --- ANALYTICS TABLES --- ============================================ - --- Tägliche Statistiken (für Dashboard) -CREATE TABLE referrals.daily_stats ( - date DATE NOT NULL, - app_id TEXT, -- NULL = global - - registrations INTEGER DEFAULT 0, - activations INTEGER DEFAULT 0, - qualifications INTEGER DEFAULT 0, - retentions INTEGER DEFAULT 0, - - credits_paid INTEGER DEFAULT 0, - credits_held INTEGER DEFAULT 0, - - fraud_blocked INTEGER DEFAULT 0, - - PRIMARY KEY (date, COALESCE(app_id, 'global')) -); - --- ============================================ --- VIEWS --- ============================================ - --- Referrer-Stats View -CREATE VIEW referrals.referrer_stats AS -SELECT - r.referrer_id, - ut.tier, - ut.qualified_count, - ut.total_earned, - COUNT(*) FILTER (WHERE r.status = 'registered') as registered_count, - COUNT(*) FILTER (WHERE r.activated_at IS NOT NULL) as activated_count, - COUNT(*) FILTER (WHERE r.qualified_at IS NOT NULL) as qualified_count_current, - COUNT(*) FILTER (WHERE r.retained_at IS NOT NULL) as retained_count, - COUNT(*) FILTER (WHERE r.is_flagged) as flagged_count -FROM referrals.relationships r -LEFT JOIN referrals.user_tiers ut ON r.referrer_id = ut.user_id -GROUP BY r.referrer_id, ut.tier, ut.qualified_count, ut.total_earned; -``` - -### 7.2 Erweiterung bestehender Tabellen - -```sql --- Transaction-Type erweitern (falls noch nicht vorhanden) -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_enum - WHERE enumlabel = 'referral' - AND enumtypid = 'credits.transaction_type'::regtype - ) THEN - ALTER TYPE credits.transaction_type ADD VALUE 'referral'; - END IF; -END -$$; - --- Referral-Referenz in Transactions -ALTER TABLE credits.transactions - ADD COLUMN IF NOT EXISTS referral_bonus_event_id UUID - REFERENCES referrals.bonus_events(id); -``` - ---- - -## 8. API-Endpoints - -### 8.1 Code-Management - -```typescript -// ============================================ -// PUBLIC ENDPOINTS -// ============================================ - -// Code validieren (für Registrierungs-Form) -GET /api/referrals/validate/:code -Response: { - valid: boolean, - referrerName?: string, // "Till S." (anonymisiert) - bonusCredits: number, // 25 - error?: string // 'invalid' | 'expired' | 'max_uses' -} - -// ============================================ -// AUTHENTICATED ENDPOINTS -// ============================================ - -// Eigene Codes abrufen -GET /api/referrals/codes -Response: { - codes: Array<{ - id: string, - code: string, - type: 'auto' | 'custom' | 'campaign', - isActive: boolean, - usesCount: number, - createdAt: string - }>, - autoCode: string // Primärer Auto-Code -} - -// Neuen Custom-Code erstellen -POST /api/referrals/codes -Body: { code: string } // 3-20 Zeichen -Response: { - code: { id, code, ... }, - error?: string // 'taken' | 'invalid_format' | 'rate_limited' -} - -// Code deaktivieren -DELETE /api/referrals/codes/:id -Response: { success: boolean } - -// ============================================ -// STATS ENDPOINTS -// ============================================ - -// Meine Referral-Stats -GET /api/referrals/stats -Response: { - tier: { - current: 'silver', - multiplier: 1.5, - qualifiedCount: 8, - nextTier: 'gold', - nextTierAt: 15, - progress: 0.53 // 8/15 - }, - totals: { - registered: 23, - activated: 18, - qualified: 8, - retained: 5, - creditsEarned: 450, - creditsPending: 35 // In Hold - }, - byApp: { - chat: { registered: 12, activated: 10, qualified: 4, credits: 200 }, - picture: { registered: 11, activated: 8, qualified: 4, credits: 250 } - }, - recentActivity: [ - { type: 'qualified', refereeName: 'Max M.', credits: 25, at: '...' }, - { type: 'cross_app', refereeName: 'Anna K.', app: 'picture', credits: 5, at: '...' } - ] -} - -// Meine geworbenen User -GET /api/referrals/referred-users -Query: ?status=all|registered|activated|qualified|retained&limit=20&offset=0 -Response: { - users: Array<{ - id: string, - name: string, // Anonymisiert: "Max M." - status: string, - registeredAt: string, - activatedAt?: string, - qualifiedAt?: string, - retainedAt?: string, - appsUsed: string[], // ['chat', 'picture'] - creditsEarned: number, - isFlagged: boolean - }>, - pagination: { total, limit, offset } -} - -// ============================================ -// INTERNAL ENDPOINTS (Service-to-Service) -// ============================================ - -// Referral bei Registrierung anwenden -POST /api/internal/referrals/apply -Headers: { 'X-Service-Key': '...' } -Body: { - refereeId: string, - code: string, - sourceAppId: string, - ipAddress: string, - deviceFingerprint?: string, - userAgent: string -} -Response: { - success: boolean, - referralId?: string, - bonusAwarded?: number, - fraudScore?: number, - error?: string -} - -// Stage-Update (von anderen Services) -POST /api/internal/referrals/stage-update -Headers: { 'X-Service-Key': '...' } -Body: { - userId: string, - stage: 'activated' | 'qualified', - appId: string, - metadata?: object -} -Response: { success: boolean, bonusPaid?: number } - -// Cross-App-Aktivierung -POST /api/internal/referrals/cross-app -Headers: { 'X-Service-Key': '...' } -Body: { - userId: string, - appId: string -} -Response: { success: boolean, bonusPaid?: number, isNewApp: boolean } -``` - -### 8.2 Admin-Endpoints - -```typescript -// ============================================ -// ADMIN ENDPOINTS -// ============================================ - -// Campaign-Code erstellen -POST /api/admin/referrals/campaign-codes -Body: { - code: string, - maxUses?: number, - expiresAt?: string, - metadata?: { campaign: string, source: string } -} - -// Review-Queue abrufen -GET /api/admin/referrals/review-queue -Query: ?status=pending&priority=high&limit=50 -Response: { - items: Array<{ - id: string, - relationship: { referrerId, refereeId, ... }, - fraudScore: number, - fraudSignals: string[], - priority: string, - bonusAmount: number, - createdAt: string - }> -} - -// Review abschließen -POST /api/admin/referrals/review/:id -Body: { - action: 'approve' | 'reject', - notes?: string -} - -// Fraud-Pattern hinzufügen -POST /api/admin/referrals/fraud-patterns -Body: { - patternType: 'email_domain' | 'ip_range' | 'device_pattern', - patternValue: string, - severity: 'low' | 'medium' | 'high' | 'critical', - scoreImpact: number, - description?: string -} - -// Dashboard-Stats -GET /api/admin/referrals/dashboard -Query: ?period=7d|30d|90d -Response: { - overview: { - totalReferrals: number, - conversionRate: number, // registered → qualified - creditsPaid: number, - creditsHeld: number, - fraudBlocked: number - }, - byDay: Array<{ date, registrations, qualifications, credits }>, - topReferrers: Array<{ userId, name, qualified, credits }>, - fraudStats: { - blockedToday: number, - pendingReview: number, - commonSignals: Array<{ signal, count }> - } -} -``` - ---- - -## 9. Service-Architektur - -### 9.1 Neue Module in mana-core-auth - -``` -services/mana-core-auth/src/ -├── referrals/ -│ ├── referrals.module.ts -│ ├── referrals.controller.ts -│ ├── services/ -│ │ ├── referral-code.service.ts # Code-Generierung & Verwaltung -│ │ ├── referral-tracking.service.ts # Stage-Tracking & Bonus -│ │ ├── referral-tier.service.ts # Tier-Berechnung -│ │ ├── referral-stats.service.ts # Statistiken -│ │ └── referral-cross-app.service.ts # Cross-App-Tracking -│ ├── fraud/ -│ │ ├── fraud-detection.service.ts # Fraud-Scoring -│ │ ├── fingerprint.service.ts # IP/Device Fingerprinting -│ │ ├── rate-limit.service.ts # Rate-Limiting -│ │ └── fraud-patterns.service.ts # Pattern-Matching -│ ├── dto/ -│ │ ├── create-code.dto.ts -│ │ ├── apply-referral.dto.ts -│ │ ├── stage-update.dto.ts -│ │ └── ... -│ └── entities/ -│ └── ... (Drizzle schemas) -``` - -### 9.2 Integration Points - -```typescript -// 1. Bei User-Registrierung (better-auth.service.ts) -async registerB2C(dto: RegisterB2CDto) { - const user = await this.createUser(dto); - await this.creditsService.initializeBalance(user.id); - - // NEU: Auto-Code erstellen - await this.referralCodeService.createAutoCode(user.id); - - // NEU: Referral anwenden wenn Code übergeben - if (dto.referralCode) { - await this.referralTrackingService.applyReferral({ - refereeId: user.id, - code: dto.referralCode, - sourceAppId: dto.appId, - fingerprint: dto.fingerprint - }); - } - - return { user, token }; -} - -// 2. Bei Credit-Nutzung (credits.service.ts) -async useCredits(userId: string, dto: UseCreditsDto) { - const result = await this.deductCredits(userId, dto); - - // NEU: Cross-App-Tracking - await this.referralCrossAppService.trackAppUsage(userId, dto.appId); - - // NEU: Activation-Check (erste Nutzung überhaupt) - await this.referralTrackingService.checkActivation(userId); - - return result; -} - -// 3. Bei Credit-Kauf (nach Stripe-Webhook) -async completePurchase(userId: string, purchaseId: string) { - await this.creditBalance(userId, amount); - - // NEU: Qualification-Check (erster Kauf) - await this.referralTrackingService.checkQualification(userId); -} - -// 4. Cron-Job für Retention (täglich) -@Cron('0 0 * * *') -async checkRetention() { - await this.referralTrackingService.processRetentionBatch(); -} -``` - ---- - -## 10. UI-Komponenten - -### 10.1 Registrierungs-Seite (erweitert) - -**Datei:** `apps/manacore/apps/web/src/routes/(auth)/register/+page.svelte` - -```svelte - - - -
- Eingeladen von {referralValidation.referrerName} - - Du erhältst {referralValidation.bonusCredits} Bonus-Credits! -
- {:else if referralValidation && !referralValidation.valid} -- Ungültiger Code -
- {/if} -- {#if referralValidation?.valid} - {150 + referralValidation.bonusCredits} Credits zum Start - {:else} - 150 Credits zum Start - {/if} -
-``` - -### 10.2 Dashboard Referral-Widget - -**Datei:** `apps/manacore/apps/web/src/lib/components/referrals/ReferralWidget.svelte` - -```svelte - - -Dein Code:
-
- {stats.autoCode}
-
-
- {stats.totals.registered}
-Registriert
-{stats.totals.activated}
-Aktiviert
-{stats.totals.qualified}
-Qualifiziert
-{stats.totals.creditsEarned}
-Credits
-- Bei {stats.tier.nextTier}: {stats.tier.multiplier * 1.5}x Bonus -
-- 💎 Maximales Tier erreicht! (3x Bonus) -
- {/if} - - - -