feat: integrate uload and picture, unify package naming

- Add uload project with apps/web structure
  - Reorganize from flat to monorepo structure
  - Remove PocketBase binary and local data
  - Update to pnpm and @uload/web namespace

- Add picture project to monorepo
  - Remove embedded git repository

- Unify all package names to @{project}/{app} schema:
  - @maerchenzauber/* (was @storyteller/*)
  - @manacore/* (was manacore-*, manacore)
  - @manadeck/* (was web, backend, manadeck)
  - @memoro/* (was memoro-web, landing, memoro)
  - @picture/* (already unified)
  - @uload/web

- Add convenient dev scripts for all apps:
  - pnpm dev:{project}:web
  - pnpm dev:{project}:landing
  - pnpm dev:{project}:mobile
  - pnpm dev:{project}:backend

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-11-25 04:00:36 +01:00
parent c6c4c5a552
commit c712a2504a
1031 changed files with 189301 additions and 290 deletions

View file

@ -0,0 +1,285 @@
# ULoad Feature Overview
**Date:** 2025-08-15-15:08
## Project Description
ULoad (ulo.ad) is a comprehensive link management and digital profile platform built with SvelteKit. The application combines URL shortening, link analytics, digital business cards, and customizable public profiles with a modern, themeable interface.
## Core Features
### 1. Link Management System
#### URL Shortening
- **Short Link Generation**: Create custom short URLs (ulo.ad/code)
- **Username-based URLs**: Personal branded links (ulo.ad/u/username/code)
- **Folder Organization**: Group links in themed folders with custom colors and icons
- **Tag System**: Organize links with customizable tags for better categorization
- **Link Features**:
- Password protection for sensitive links
- Expiration dates (automatic deactivation)
- Maximum click limits
- Link descriptions and titles
- Active/inactive status toggle
#### Analytics Dashboard
- **Comprehensive Metrics**:
- Total clicks tracking
- Browser distribution (Chrome, Firefox, Safari, etc.)
- Device type analytics (Desktop, Mobile, Tablet)
- Referrer source tracking
- Daily click patterns
- Recent click history with detailed information
- **QR Code Generation**:
- Multiple color options (black, white, gold)
- Multiple formats (PNG, SVG, JPG)
- Downloadable QR codes for each link
### 2. Digital Profile System
#### Public Profiles
- **Profile Pages**: Public profiles at /p/username
- **Profile Components**:
- Profile information card with bio and social links
- Link collections organized by folders
- QR code for profile sharing
- Click statistics display (optional)
- Social media integration (GitHub, Twitter/X, LinkedIn, Instagram)
#### Profile Cards System
- **Three Creation Modes**:
1. **Beginner Mode**: Visual drag-and-drop card builder
2. **Advanced Mode**: Template-based creation with modules
3. **Expert Mode**: Direct HTML/CSS editing
- **Card Modules**:
- Header Module (title, subtitle, avatar)
- Content Module (rich text content)
- Links Module (link collections)
- Media Module (images, videos)
- Stats Module (statistics display)
- Actions Module (CTA buttons)
- Footer Module (additional information)
- **Card Features**:
- Drag-and-drop reordering
- Module-based composition
- Custom themes and styling
- Aspect ratio controls
- Animation effects
- Card duplication
- Mode conversion between beginner/advanced/expert
### 3. Template Store
#### Community Templates
- **Template Marketplace**: Browse and use community-created card templates
- **Categories**: General, Profile, Dashboard, Widget templates
- **Template Features**:
- Live preview before use
- Download tracking
- 5-star rating system
- Tag-based search
- Sort by popularity, recency, or rating
- Template cloning to personal collection
#### Template Creation
- **Share Templates**: Create and publish templates for the community
- **Template Management**:
- Public/private visibility
- Template descriptions and tags
- Module configuration
- Preview images
### 4. Subscription & Pricing
#### Plan Tiers
1. **Free Plan**:
- 10 links per month
- Basic analytics
- QR code generation
- Link customization
2. **Pro Monthly (€4.99/month)**:
- Unlimited links
- Advanced analytics
- Custom QR codes
- Priority support
- No advertisements
- API access
3. **Pro Yearly (€39.99/year)**:
- All Pro features
- 20€ annual savings
- Same benefits as monthly
4. **Lifetime (€129.99 one-time)**:
- All Pro features forever
- Early access to new features
- Lifetime updates
#### Payment Integration
- **Stripe Integration**: Secure payment processing
- **Subscription Management**: Easy upgrade/downgrade
- **Checkout Flow**: Streamlined payment experience
### 5. User Management
#### Authentication System
- **Email/Password Authentication**: Standard registration and login
- **Email Verification**: Secure account activation
- **Password Reset**: Self-service password recovery
- **Session Management**: Persistent login with PocketBase
#### Settings & Preferences
- **Profile Settings**:
- Username customization
- Display name and bio
- Location information
- Social media links
- **Privacy Controls**:
- Public/private profile toggle
- Click statistics visibility
- Email notification preferences
- **Account Management**:
- Password changes
- Email updates
- Account deletion with confirmation
- **Default Preferences**:
- Default link expiry settings
- Notification preferences
### 6. Folder Management
#### Folder Features
- **Custom Folders**: Create folders for link organization
- **Folder Properties**:
- URL-safe names for navigation
- Display names for UI
- Custom colors (10 preset options)
- Icon support
- Public/private visibility
- Description fields
#### Folder Analytics
- **Metrics per Folder**:
- Total links count
- Aggregate click statistics
- Folder-based link grouping on profiles
### 7. Tag System
#### Tag Management
- **Custom Tags**: Create personalized tags for organization
- **Tag Features**:
- Custom icons
- Color coding
- Tag-based filtering
- Multi-tag support per link
- Tag search functionality
### 8. Theme System
#### Interface Theming
- **Dark/Light Mode**: System-wide theme switching
- **Custom Themes**: User-definable color schemes
- **Theme Components**:
- Primary/secondary colors
- Accent colors
- Surface colors
- Text color variations
- Border and hover states
#### Card Themes
- **Card-specific Themes**: Individual styling for cards
- **Theme Editor**: Visual theme customization tool
- **Theme Inheritance**: Global and card-level theme options
### 9. Internationalization
#### Language Support
- **Multi-language Interface**: Powered by Paraglide.js
- **Supported Languages**: German and English (expandable)
- **Language Switching**: User-selectable interface language
### 10. Mobile Experience
#### Responsive Design
- **Mobile-optimized Layouts**: Adaptive UI for all screen sizes
- **Touch-friendly Interface**: Optimized for mobile interaction
- **Mobile Sidebar**: Collapsible navigation for mobile devices
- **PWA-ready**: Progressive Web App capabilities
## Technical Features
### Architecture
- **Framework**: SvelteKit 2.22 with Svelte 5.0
- **Database**: PocketBase (backend)
- **Styling**: Tailwind CSS 4.0
- **Testing**: Vitest (unit) + Playwright (E2E)
- **Build Tool**: Vite
- **Deployment**: Node.js adapter
### Security Features
- **Password Protection**: Secure link access control
- **SSL Encryption**: HTTPS everywhere
- **Secure Authentication**: PocketBase auth system
- **CSRF Protection**: Built-in SvelteKit security
### Performance
- **Server-Side Rendering**: Fast initial page loads
- **Lazy Loading**: On-demand component loading
- **Optimized Assets**: Automatic image and code optimization
- **Caching Strategies**: Efficient data caching
### Developer Features
- **API Access**: Pro plan includes API access
- **TypeScript**: Full type safety
- **Component Library**: Reusable UI components
- **Testing Suite**: Comprehensive test coverage
- **Development Tools**: Hot reload, debugging support
## Unique Selling Points
1. **Three-Mode Card Builder**: Unique approach catering to all skill levels
2. **Integrated Link & Profile System**: Combines URL shortening with digital profiles
3. **Community Template Store**: Share and discover card designs
4. **Comprehensive Analytics**: Detailed insights without external tools
5. **Lifetime Plan Option**: One-time payment for permanent access
6. **Folder-based Organization**: Unique approach to link categorization
7. **Username-branded URLs**: Personal branding in short links
8. **Modular Card System**: Flexible, component-based card creation
## Future Expansion Possibilities
- Team/organization accounts
- Advanced API features
- Custom domain support
- Webhook integrations
- Advanced analytics (geographic data, conversion tracking)
- Social media auto-posting
- Bulk link operations
- Link scheduling
- A/B testing for links
- Browser extensions

View file

@ -0,0 +1,56 @@
# A/B Testing - Test URLs
## Test URLs für verschiedene Varianten
### Control (Baseline)
- http://localhost:5173/ (kein Hash)
- http://localhost:5173/?debug=true (mit Debug-Info)
### Variant A - Value Focused
- http://localhost:5173/#a1 (Generic Value)
- http://localhost:5173/#a2 (Specific Value)
- http://localhost:5173/#a3 (Transform Value)
### Variant B - Social Proof
- http://localhost:5173/#b1 (Numbers)
- http://localhost:5173/#b2 (Logos)
- http://localhost:5173/#b3 (Testimonial)
### Variant C - Feature Focused
- http://localhost:5173/#c1 (All-in-One)
- http://localhost:5173/#c2 (QR Focus)
- http://localhost:5173/#c3 (Integration)
## Debug Mode
Füge `?debug=true` zu jeder URL hinzu, um Debug-Informationen zu sehen:
- http://localhost:5173/?debug=true
- http://localhost:5173/#a1?debug=true
## Force Variant
Erzwinge eine spezifische Variante mit `?force=`:
- http://localhost:5173/?force=a1
- http://localhost:5173/?force=b2
- http://localhost:5173/?force=control
## Reset
Lösche die Zuweisung und erhalte eine neue:
- Öffne Debug-Modus: http://localhost:5173/?debug=true
- Klicke auf "Reset & Reload" Button
## Tracking Events
Folgende Events werden an Umami gesendet:
- `page_view_[variant]` - Beim Laden der Seite
- `cta_click_[variant]` - Beim Klick auf CTA Button
- `conversion_[variant]` - Beim Absenden des Formulars (wenn implementiert)

View file

@ -0,0 +1,712 @@
# A/B/C Testing System - Implementation Guide
## Übersicht
Dieses Dokument beschreibt die vollständige Implementierung eines URL-Hash-basierten A/B/C Testing Systems für uLoad. Das System nutzt URL-Hashes (#a, #b, #c) zur Variantenzuweisung und ermöglicht versionierte Iterationen für kontinuierliche Optimierung.
## 1. System-Architektur
### 1.1 URL-Schema
```
Basis-URL: https://ulo.ad
Control (Baseline):
└── https://ulo.ad (kein Hash)
Varianten:
├── Variant A: https://ulo.ad#a[version]
│ ├── https://ulo.ad#a1 (erste Version)
│ ├── https://ulo.ad#a2 (zweite Version)
│ └── https://ulo.ad#a3 (dritte Version)
├── Variant B: https://ulo.ad#b[version]
│ ├── https://ulo.ad#b1
│ ├── https://ulo.ad#b2
│ └── https://ulo.ad#b3
└── Variant C: https://ulo.ad#c[version]
├── https://ulo.ad#c1
├── https://ulo.ad#c2
└── https://ulo.ad#c3
```
### 1.2 Komponenten-Struktur
```
src/lib/ab-testing/
├── config/
│ ├── tests.json # Test-Konfigurationen
│ ├── variants.ts # Varianten-Definitionen
│ └── versions.ts # Versions-Mapping
├── components/
│ ├── control/ # Control-Varianten
│ │ └── HeroControl.svelte
│ ├── variant-a/ # A-Varianten
│ │ ├── HeroA1.svelte
│ │ ├── HeroA2.svelte
│ │ └── HeroA3.svelte
│ ├── variant-b/ # B-Varianten
│ │ ├── HeroB1.svelte
│ │ ├── HeroB2.svelte
│ │ └── HeroB3.svelte
│ └── variant-c/ # C-Varianten
│ ├── HeroC1.svelte
│ ├── HeroC2.svelte
│ └── HeroC3.svelte
├── service/
│ ├── ABTestingService.ts # Core Service
│ ├── TrackingService.ts # Umami Integration
│ └── AnalyticsService.ts # Auswertung
└── utils/
├── hash.ts # Hash-Utilities
├── random.ts # Zufallszuweisung
└── validation.ts # Validierung
```
## 2. Varianten-Definition
### 2.1 Control Variante (Baseline)
**URL:** `ulo.ad`
**Eigenschaften:**
- Aktuelle, bewährte Version
- Baseline für alle Vergleiche
- Mindestens 25-40% des Traffics
- Keine experimentellen Features
**Content:**
```yaml
Headline: 'Short Links That Work Harder'
Subheadline: 'Professional URL management with real-time analytics'
CTA: 'Start Free Trial'
Layout: Standard Hero mit Screenshot
Features: Grid Layout (2x3)
Social Proof: Logo-Leiste unten
```
### 2.2 Variant A - Value-Fokussiert
**Versionen:**
#### A1 - Generischer Value
**URL:** `ulo.ad#a1`
```yaml
Headline: 'Save Time on Every Link You Share'
Subheadline: 'Automate your URL workflow with smart tools'
CTA: 'Start Saving Time'
Focus: Zeit-Ersparnis
```
#### A2 - Spezifischer Value
**URL:** `ulo.ad#a2`
```yaml
Headline: 'Save 3 Hours Per Week on Link Management'
Subheadline: 'Join teams who reduced link tasks by 75%'
CTA: 'Calculate Your Savings'
Focus: Konkrete Zahlen
Extra: ROI-Rechner prominent
```
#### A3 - Personalisierter Value
**URL:** `ulo.ad#a3`
```yaml
Headline: 'Your Links, 10x More Powerful'
Subheadline: 'Transform every URL into a conversion machine'
CTA: 'Unlock Link Power'
Focus: Transformation
Extra: Before/After Vergleich
```
### 2.3 Variant B - Social Proof
**Versionen:**
#### B1 - Zahlen-basiert
**URL:** `ulo.ad#b1`
```yaml
Headline: 'Join 10,000+ Marketers Using uLoad'
Subheadline: 'The trusted URL shortener for growing brands'
CTA: 'Join the Community'
Focus: Nutzer-Anzahl
Extra: Live-Counter
```
#### B2 - Logo-basiert
**URL:** `ulo.ad#b2`
```yaml
Headline: 'Trusted by Google, Meta, and Microsoft'
Subheadline: 'Enterprise-grade URL management for all'
CTA: 'See Why They Chose Us'
Focus: Bekannte Marken
Extra: Logo-Carousel prominent
```
#### B3 - Testimonial-basiert
**URL:** `ulo.ad#b3`
```yaml
Headline: 'Rated #1 URL Shortener by Marketing Teams'
Subheadline: 'See what 10,000+ users say about us'
CTA: 'Read Success Stories'
Focus: Reviews & Ratings
Extra: Testimonial-Slider
```
### 2.4 Variant C - Feature-Fokussiert
**Versionen:**
#### C1 - All-in-One
**URL:** `ulo.ad#c1`
```yaml
Headline: 'URL Shortener + QR Codes + Analytics'
Subheadline: 'Everything you need in one platform'
CTA: 'Explore All Features'
Focus: Komplettlösung
Extra: Feature-Tabs
```
#### C2 - Killer-Feature
**URL:** `ulo.ad#c2`
```yaml
Headline: 'QR Codes That Actually Convert'
Subheadline: 'Dynamic QR codes with real-time analytics'
CTA: 'Create Your First QR Code'
Focus: QR-Code Feature
Extra: Live QR-Generator
```
#### C3 - Integration-Fokus
**URL:** `ulo.ad#c3`
```yaml
Headline: 'Works With Your Favorite Tools'
Subheadline: 'Zapier, Slack, WordPress & 100+ integrations'
CTA: 'Connect Your Tools'
Focus: Integrations
Extra: Integration-Grid
```
## 3. Traffic-Verteilung
### 3.1 Initial-Verteilung (Woche 1-2)
```javascript
const trafficDistribution = {
control: 40, // Baseline
a1: 20, // Value Test
b1: 20, // Social Test
c1: 20 // Feature Test
};
```
### 3.2 Optimierte Verteilung (Woche 3-4)
Nach ersten Daten, Traffic zu Gewinnern verschieben:
```javascript
const trafficDistribution = {
control: 30, // Reduziert
a2: 30, // Winner A (neue Version)
b1: 20, // B bleibt
c2: 20 // C iteriert
};
```
### 3.3 Champion/Challenger (Ab Woche 5)
```javascript
const trafficDistribution = {
champion: 70, // Bester Performer
challenger1: 10, // Neue Idee
challenger2: 10, // Neue Idee
challenger3: 10 // Neue Idee
};
```
## 4. Implementierungs-Schritte
### Phase 1: Basis-Setup (Tag 1-3)
#### Tag 1: Hash-System
```typescript
// 1. Hash-Detection implementieren
// 2. Zufallszuweisung bei fehlendem Hash
// 3. Hash-Persistierung (localStorage als Backup)
// 4. Redirect-Logic
```
#### Tag 2: Komponenten
```typescript
// 1. Control-Komponente finalisieren
// 2. A1, B1, C1 Komponenten erstellen
// 3. Dynamisches Component-Loading
// 4. Props-Passing System
```
#### Tag 3: Tracking
```typescript
// 1. Umami Custom Events Setup
// 2. Page View Tracking mit Hash
// 3. Conversion Event Tracking
// 4. Debug-Modus
```
### Phase 2: Content-Erstellung (Tag 4-7)
#### Tag 4: Variant A (Value)
- [ ] A1: Copy schreiben
- [ ] A1: Design anpassen
- [ ] A1: Value-Propositions definieren
- [ ] A1: Testing
#### Tag 5: Variant B (Social)
- [ ] B1: Social Proof sammeln
- [ ] B1: Logos vorbereiten
- [ ] B1: Testimonials auswählen
- [ ] B1: Counter implementieren
#### Tag 6: Variant C (Features)
- [ ] C1: Feature-Liste priorisieren
- [ ] C1: Icons/Grafiken erstellen
- [ ] C1: Interaktive Elemente
- [ ] C1: Demo-Integration
#### Tag 7: Testing & QA
- [ ] Alle Varianten durchspielen
- [ ] Mobile Testing
- [ ] Performance Check
- [ ] Tracking verifizieren
### Phase 3: Launch & Iteration (Woche 2+)
#### Woche 2: Soft Launch
```yaml
Montag:
- 10% Traffic auf Tests
- Monitoring Setup
- Fehler-Tracking
Mittwoch:
- 50% Traffic auf Tests
- Erste Daten-Analyse
- Quick Fixes
Freitag:
- 100% Traffic
- Wochenend-Monitoring
```
#### Woche 3: Erste Iteration
```yaml
Montag:
- Daten-Auswertung
- Winner/Loser identifizieren
- Neue Versionen planen
Mittwoch:
- A2, B2, C2 entwickeln
- Basierend auf Learnings
Freitag:
- Neue Versionen live
- Traffic umverteilen
```
## 5. Tracking & Analytics
### 5.1 Umami Setup
**Page Tracking:**
```
Umami sieht automatisch:
- ulo.ad (Control): 1000 views
- ulo.ad#a1: 200 views
- ulo.ad#a2: 250 views
- ulo.ad#b1: 200 views
- etc.
```
**Event Tracking:**
```javascript
// Conversion Events nach Variant
umami.track('signup_control');
umami.track('signup_a1');
umami.track('signup_a2');
umami.track('signup_b1');
// Micro-Conversions
umami.track('cta_click_a1');
umami.track('form_start_b2');
umami.track('video_play_c1');
```
### 5.2 Metriken & KPIs
**Primary Metrics:**
1. **Conversion Rate:** Besucher → Sign-up
2. **Engagement Rate:** Aktionen auf Seite
3. **Bounce Rate:** Sofortiges Verlassen
4. **Time on Page:** Verweildauer
**Secondary Metrics:**
1. **CTA Click Rate:** Button-Klicks
2. **Form Abandonment:** Angefangene Forms
3. **Scroll Depth:** Wie weit gescrollt
4. **Feature Interest:** Welche Features angeklickt
### 5.3 Erfolgs-Kriterien
**Statistische Signifikanz:**
- Minimum 500 Besucher pro Variante
- 95% Konfidenz-Level
- Minimum 10% Uplift für Gewinner
**Business Impact:**
- Conversion Rate > 3%
- Sign-ups +20% vs Control
- Engagement +15% vs Control
## 6. Iterations-Strategie
### 6.1 Wann iterieren?
**Neue Version erstellen wenn:**
- Variante schlechter als Control (-10%)
- Plateau erreicht (keine Verbesserung)
- Neue Hypothese basierend auf Daten
- Saisonale Anpassung nötig
**Variante behalten wenn:**
- Konstant besser als Control (+5-10%)
- Noch nicht genug Daten (<500 Besucher)
- Trend positiv aber nicht signifikant
### 6.2 Versions-Evolution
```
A1 (Generic) → A2 (Specific) → A3 (Hyper-specific)
"Save Time" → "Save 3 Hours" → "Save 3.5 Hours Weekly"
B1 (Numbers) → B2 (Logos) → B3 (Stories)
"10,000 users" → "Google uses us" → "How Google saves time"
C1 (All Features) → C2 (Best Feature) → C3 (Integration)
"Everything" → "Best QR Codes" → "Works with Zapier"
```
## 7. Code-Beispiele
### 7.1 Hash-Manager
```typescript
// src/lib/ab-testing/hash-manager.ts
export class HashManager {
private readonly validVariants = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'];
private readonly distribution = {
control: 40,
a1: 20,
b1: 20,
c1: 20
};
getVariant(): string {
// Check existing hash
const hash = window.location.hash.slice(1);
if (this.validVariants.includes(hash)) {
return hash;
}
// Check localStorage backup
const stored = localStorage.getItem('ab_variant');
if (stored && this.validVariants.includes(stored)) {
window.location.hash = stored;
return stored;
}
// Assign new variant
const variant = this.assignRandomVariant();
window.location.hash = variant || '';
localStorage.setItem('ab_variant', variant);
return variant;
}
private assignRandomVariant(): string {
const random = Math.random() * 100;
let cumulative = 0;
for (const [variant, weight] of Object.entries(this.distribution)) {
cumulative += weight;
if (random <= cumulative) {
return variant === 'control' ? '' : variant;
}
}
return '';
}
}
```
### 7.2 Component Loader
```svelte
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import { HashManager } from '$lib/ab-testing/hash-manager';
// Import all variants
import HeroControl from '$lib/ab-testing/components/control/HeroControl.svelte';
import HeroA1 from '$lib/ab-testing/components/variant-a/HeroA1.svelte';
import HeroA2 from '$lib/ab-testing/components/variant-a/HeroA2.svelte';
import HeroB1 from '$lib/ab-testing/components/variant-b/HeroB1.svelte';
// ... more imports
let variant = $state('');
let HeroComponent = $state(HeroControl);
const componentMap = {
'': HeroControl,
control: HeroControl,
a1: HeroA1,
a2: HeroA2,
b1: HeroB1
// ... more mappings
};
onMount(() => {
const hashManager = new HashManager();
variant = hashManager.getVariant();
HeroComponent = componentMap[variant] || HeroControl;
// Track view
if (typeof umami !== 'undefined') {
umami.track(`view_${variant || 'control'}`);
}
});
</script>
{#if HeroComponent}
<HeroComponent
on:conversion={() => {
umami?.track(`conversion_${variant || 'control'}`);
}}
/>
{/if}
```
## 8. Debugging & Testing
### 8.1 Debug Mode
**URL-Parameter für Testing:**
```
?debug=true # Zeigt aktuelle Variante
?force=a2 # Erzwingt spezifische Variante
?reset=true # Löscht Zuweisung
?show=all # Zeigt alle Varianten untereinander
```
### 8.2 Test-URLs für Team
```
Preview-Links:
- Control: https://ulo.ad/?preview=control
- Variant A1: https://ulo.ad/?preview=a1
- Variant A2: https://ulo.ad/?preview=a2
- Variant B1: https://ulo.ad/?preview=b1
- Compare: https://ulo.ad/?compare=control,a1,b1
```
## 9. Rollback-Strategie
### 9.1 Notfall-Abschaltung
```typescript
// Emergency switch in environment
PUBLIC_AB_TESTING_ENABLED = false;
// Code check
if (import.meta.env.PUBLIC_AB_TESTING_ENABLED === 'false') {
// Show only control
return HeroControl;
}
```
### 9.2 Graduelle Rückführung
```javascript
// Woche 1: Test läuft
distribution = { control: 40, a: 20, b: 20, c: 20 };
// Problem erkannt: Zurück zu Control
distribution = { control: 70, a: 10, b: 10, c: 10 };
// Finale Abschaltung
distribution = { control: 100 };
```
## 10. Dokumentation & Kommunikation
### 10.1 Team-Dokumentation
**Confluence/Notion Page:**
```markdown
# Aktuelle A/B Tests
## Homepage Hero Test
- Start: 01.02.2025
- Varianten: Control, A2, B1, C2
- Status: Aktiv
- Zwischenstand: A2 führt mit +15% Conversion
## Learnings
- Value-Propositions funktionieren besser als Features
- Konkrete Zahlen ("3 Hours") besser als vage ("Save Time")
- Social Proof wichtig aber nicht primär
```
### 10.2 Stakeholder-Reporting
**Wöchentlicher Report:**
```yaml
Test: Homepage Hero
Woche: 2
Besucher: 5,000
Conversions: 180
Ergebnisse:
Control: 3.2% CR (Baseline)
A2: 4.1% CR (+28% 🟢)
B1: 3.0% CR (-6% 🔴)
C2: 3.5% CR (+9% 🟡)
Empfehlung: A2 weiter optimieren
Nächste Schritte: A3 mit noch spezifischeren Zahlen
```
## 11. Zeitplan
### Woche 1: Implementation
- Mo-Mi: Technische Basis
- Do-Fr: Content-Erstellung
### Woche 2: Launch
- Mo: Soft Launch (10%)
- Mi: Ramp-up (50%)
- Fr: Full Launch (100%)
### Woche 3: Erste Iteration
- Mo: Daten-Analyse
- Mi: Neue Versionen
- Fr: Deploy V2
### Woche 4: Optimierung
- Mo: Winner-Analyse
- Mi: Champion festlegen
- Fr: Neue Challenger
### Monat 2+: Kontinuierlich
- Wöchentliche Reviews
- Monatliche große Updates
- Quartals-Reports
## 12. Budget & Ressourcen
### Entwicklung
- Initial-Setup: 3 Tage
- Pro Variante: 0.5 Tage
- Analyse/Woche: 2 Stunden
### Tools (bereits vorhanden)
- Umami: Kostenlos (Self-hosted)
- SvelteKit: Kostenlos
- Hosting: Bereits bezahlt
### Gesamt
- **Woche 1:** 40 Stunden
- **Fortlaufend:** 5 Stunden/Woche
## Anhang: Checklisten
### Pre-Launch Checklist
- [ ] Alle Varianten getestet
- [ ] Mobile responsive
- [ ] Tracking funktioniert
- [ ] Rollback-Plan ready
- [ ] Team informiert
### Weekly Review Checklist
- [ ] Daten aus Umami exportiert
- [ ] Conversion Rates berechnet
- [ ] Signifikanz geprüft
- [ ] Nächste Tests geplant
- [ ] Report verschickt
### Iteration Checklist
- [ ] Hypothesis dokumentiert
- [ ] Neue Version erstellt
- [ ] QA durchgeführt
- [ ] Traffic-Split angepasst
- [ ] Monitoring aktiviert
---
_Version: 1.0_
_Letzte Aktualisierung: Januar 2025_
_Verantwortlich: Development Team_
_Review-Zyklus: Wöchentlich_

View file

@ -0,0 +1,599 @@
# Downtime Prevention Plan für uLoad
## Problemanalyse
Das uLoad-Projekt war kürzlich komplett down, was zu kritischen Problemen geführt hat:
- Hauptanwendung nicht erreichbar
- Weiterleitungen funktionierten nicht
- Benutzererfahrung stark beeinträchtigt
- Potentieller Datenverlust/Inkonsistenz
## Aktuelle Architektur-Analyse
### Technology Stack
- **Frontend:** SvelteKit 2.22 mit Svelte 5.0
- **Backend:** PocketBase (https://pb.ulo.ad)
- **Hosting:** Hetzner VPS mit Coolify
- **Database:** PocketBase SQLite mit persistentem Volume
- **Deployment:** Docker mit Supervisor (Multi-Service Container)
### Kritische Single Points of Failure
1. **PocketBase Dependency**
- Gesamte Anwendung abhängig von PocketBase Verfügbarkeit
- Keine Fallback-Mechanismen implementiert
- Timeout-Konfiguration zu aggressiv (5 Sekunden)
2. **Single Server Setup**
- Ein Hetzner VPS für gesamte Infrastruktur
- Keine Redundanz oder Load Balancing
- Coolify als Single Point of Failure
3. **Container Architecture**
- SvelteKit und PocketBase in einem Container
- Supervisor als Process Manager
- Keine Health Checks zwischen Services
4. **Rate Limiting**
- In-Memory Store (verliert Daten bei Restart)
- Keine Redis-Backend für Persistenz
- Potentielle Blockierung legitimer Traffic
## Sofortmaßnahmen (Quick Wins)
### 1. Verbesserte Error Handling & Fallbacks
#### PocketBase Connection Resilience
```typescript
// src/lib/pocketbase-resilient.ts
class ResilientPocketBase {
private retryCount = 0;
private maxRetries = 3;
private backoffMs = 1000;
async withRetry<T>(operation: () => Promise<T>): Promise<T> {
for (let i = 0; i <= this.maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (i === this.maxRetries) throw error;
await this.delay(this.backoffMs * Math.pow(2, i));
}
}
throw new Error('Max retries exceeded');
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
```
#### Graceful Degradation
- Cache-basierte Fallbacks für kritische Daten
- Offline-Mode für Basis-Funktionalität
- Error Boundaries in allen Komponenten
### 2. Enhanced Monitoring
#### Health Check Verbesserung
```typescript
// src/routes/health/+server.ts erweitern
export const GET: RequestHandler = async () => {
const health = {
status: 'healthy',
timestamp: new Date().toISOString(),
environment: building ? 'build' : 'runtime',
services: {
sveltekit: 'running',
pocketbase: await checkPocketBaseDetailed(),
database: await checkDatabaseHealth(),
memory: process.memoryUsage(),
uptime: process.uptime()
},
checks: {
canCreateLink: await testLinkCreation(),
canAuthenticate: await testAuthentication(),
canServeStatic: await testStaticFiles()
}
};
const overallStatus = Object.values(health.services).every(s => s === 'running')
? 'healthy' : 'degraded';
return json(health, {
status: overallStatus === 'healthy' ? 200 : 503
});
};
```
#### Externes Monitoring Setup
- Uptime Robot/Pingdom für externe Überwachung
- Slack/Discord Webhooks für Alerts
- Grafana Dashboard für Metriken
### 3. Improved Rate Limiting
#### Redis-Backend für Rate Limiting
```typescript
// src/lib/server/redis-rate-limiter.ts
import Redis from 'ioredis';
class RedisRateLimiter {
private redis: Redis;
constructor() {
this.redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379');
}
async checkLimit(key: string, limit: number, windowMs: number): Promise<boolean> {
const multi = this.redis.multi();
multi.incr(key);
multi.expire(key, Math.ceil(windowMs / 1000));
const results = await multi.exec();
const count = results?.[0]?.[1] as number;
return count <= limit;
}
}
```
### 4. Database Backup Strategy
#### Automatisierte PocketBase Backups
```bash
#!/bin/bash
# scripts/backup-pocketbase.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/app/backups"
PB_DATA="/app/pb_data"
mkdir -p $BACKUP_DIR
# Create backup
tar -czf "$BACKUP_DIR/pb_backup_$DATE.tar.gz" -C $PB_DATA .
# Keep only last 7 days
find $BACKUP_DIR -name "pb_backup_*.tar.gz" -mtime +7 -delete
# Upload to S3/Object Storage (optional)
if [ -n "$S3_BUCKET" ]; then
aws s3 cp "$BACKUP_DIR/pb_backup_$DATE.tar.gz" "s3://$S3_BUCKET/backups/"
fi
```
## Mittelfristige Maßnahmen (1-4 Wochen)
### 1. Infrastructure Redundancy
#### Load Balancer Setup
```yaml
# docker-compose.prod-ha.yml
version: '3.8'
services:
nginx-lb:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app1
- app2
app1:
build: .
environment:
- INSTANCE_ID=app1
volumes:
- pb_data:/app/pb_data
app2:
build: .
environment:
- INSTANCE_ID=app2
volumes:
- pb_data:/app/pb_data
volumes:
pb_data:
```
#### Multi-Region Deployment
- Hauptserver: Hetzner Deutschland
- Backup Server: AWS/DigitalOcean anderer Region
- DNS Failover mit niedrigem TTL (60 Sekunden)
### 2. Separated Services Architecture
#### PocketBase als separater Service
```yaml
# docker-compose.services.yml
services:
pocketbase:
image: spectado/pocketbase:latest
volumes:
- ./pb_data:/pb/pb_data
ports:
- "8090:8090"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/api/health"]
interval: 30s
timeout: 10s
retries: 3
app:
build: .
environment:
- POCKETBASE_URL=http://pocketbase:8090
depends_on:
pocketbase:
condition: service_healthy
restart: unless-stopped
```
### 3. Caching Layer
#### Redis für Caching & Sessions
```typescript
// src/lib/cache/redis-cache.ts
export class CacheManager {
private redis: Redis;
async get<T>(key: string): Promise<T | null> {
const cached = await this.redis.get(key);
return cached ? JSON.parse(cached) : null;
}
async set(key: string, value: any, ttlSeconds: number = 3600): Promise<void> {
await this.redis.setex(key, ttlSeconds, JSON.stringify(value));
}
// Cache häufig abgerufene Daten
async getCachedLinks(userId: string): Promise<Link[]> {
const cacheKey = `user:${userId}:links`;
let links = await this.get<Link[]>(cacheKey);
if (!links) {
links = await pb.collection('links').getFullList({ filter: `user_id="${userId}"` });
await this.set(cacheKey, links, 300); // 5 Minuten Cache
}
return links;
}
}
```
## Langfristige Maßnahmen (1-3 Monate)
### 1. Database Migration Strategy
#### PostgreSQL als Primary Database
```typescript
// Alternative zu PocketBase für bessere Skalierbarkeit
// src/lib/database/postgresql.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const connectionString = process.env.DATABASE_URL!;
const client = postgres(connectionString);
export const db = drizzle(client);
// Migration zu PostgreSQL mit:
// - Bessere Performance bei hoher Last
// - Replication Support
// - Backup/Recovery Tools
// - Connection Pooling
```
#### Database Cluster Setup
- Master-Slave Replication
- Read Replicas für Analytics
- Automated Failover
### 2. CDN Integration
#### Cloudflare Setup
```typescript
// src/app.html erweitern
// DNS-Level Protection gegen DDoS
// Edge Caching für statische Assets
// SSL/TLS Termination
// Rate Limiting auf Edge-Level
```
### 3. Microservices Architecture
#### Service Separation
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │ │ API Gateway │ │ Auth Service │
│ (SvelteKit) │ │ (Kong/Nginx) │ │ (Custom) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘
┌───────────────────────┼───────────────────────┐
│ │ │
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Link Service │ │ Analytics Svc │ │ Redirect Svc │
│ (Create/CRUD) │ │ (Tracking) │ │ (Core Feature) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
## Deployment & Operations
### 1. CI/CD Pipeline Verbesserung
#### GitHub Actions Workflow
```yaml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Tests
run: |
npm ci
npm run test
npm run test:e2e
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Deploy to Primary
run: |
# Coolify Deployment
curl -X POST ${{ secrets.COOLIFY_WEBHOOK }}
- name: Health Check
run: |
# Warte auf erfolgreiche Deployment
for i in {1..30}; do
if curl -f https://ulo.ad/health; then
echo "Deployment successful"
exit 0
fi
sleep 10
done
exit 1
- name: Rollback on Failure
if: failure()
run: |
# Automatisches Rollback bei Fehler
curl -X POST ${{ secrets.COOLIFY_ROLLBACK_WEBHOOK }}
```
### 2. Monitoring & Alerting
#### Prometheus + Grafana Setup
```yaml
# monitoring/docker-compose.yml
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
ports:
- "3001:3000"
volumes:
- grafana-storage:/var/lib/grafana
alertmanager:
image: prom/alertmanager
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
```
#### Custom Metrics
```typescript
// src/lib/metrics/prometheus.ts
import { register, collectDefaultMetrics, Counter, Histogram } from 'prom-client';
collectDefaultMetrics();
export const httpRequestsTotal = new Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status_code']
});
export const httpRequestDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route']
});
export const linkRedirects = new Counter({
name: 'link_redirects_total',
help: 'Total number of link redirects',
labelNames: ['short_code', 'success']
});
```
### 3. Disaster Recovery Plan
#### Automated Recovery Scripts
```bash
#!/bin/bash
# scripts/disaster-recovery.sh
# 1. Check service status
check_services() {
if ! curl -f https://ulo.ad/health; then
echo "Primary service down, starting recovery..."
return 1
fi
}
# 2. Switch to backup server
activate_backup() {
# Update DNS to point to backup server
curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_RECORD_ID" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"content":"'$BACKUP_SERVER_IP'"}'
}
# 3. Restore from backup
restore_from_backup() {
# Download latest backup
aws s3 cp s3://$BACKUP_BUCKET/latest.tar.gz /tmp/restore.tar.gz
# Extract and restore
tar -xzf /tmp/restore.tar.gz -C /app/pb_data/
# Restart services
docker-compose restart
}
# Main recovery flow
if ! check_services; then
activate_backup
restore_from_backup
# Send alert
curl -X POST $SLACK_WEBHOOK -d '{"text":"Disaster recovery activated for ulo.ad"}'
fi
```
## Testing & Validation
### 1. Chaos Engineering
#### Fault Injection Tests
```typescript
// tests/chaos/network-failures.test.ts
describe('Network Failure Scenarios', () => {
test('should handle PocketBase timeout gracefully', async () => {
// Simulate PocketBase timeout
const mockPb = mockPocketBaseTimeout();
const response = await app.request('/api/links', {
method: 'POST',
body: JSON.stringify({ url: 'https://example.com' })
});
// Should return cached response or graceful error
expect(response.status).toBeLessThan(500);
});
test('should fallback to cached data when database is unavailable', async () => {
// Simulate database outage
mockDatabaseDown();
const response = await app.request('/my/links');
// Should serve from cache
expect(response.status).toBe(200);
expect(response.headers.get('x-served-from')).toBe('cache');
});
});
```
### 2. Load Testing
#### Performance Benchmarks
```bash
# scripts/load-test.sh
#!/bin/bash
# Test link creation under load
ab -n 1000 -c 10 -H "Authorization: Bearer $TOKEN" \
-p link-payload.json -T application/json \
https://ulo.ad/api/links
# Test redirect performance
ab -n 10000 -c 50 https://ulo.ad/test-link
# Test concurrent user scenarios
k6 run performance-tests/user-journey.js
```
## Implementation Roadmap
### Phase 1 (Sofort - 1 Woche)
- [x] Analyse der aktuellen Architektur
- [ ] Verbesserte Error Handling implementieren
- [ ] Health Check Endpoints erweitern
- [ ] Monitoring Setup (Uptime Robot)
- [ ] Backup-Scripts erstellen
### Phase 2 (2-4 Wochen)
- [ ] Redis für Rate Limiting & Caching
- [ ] Load Balancer Setup
- [ ] Service Separation (PocketBase)
- [ ] CI/CD Pipeline mit Health Checks
- [ ] Disaster Recovery Scripts
### Phase 3 (1-3 Monate)
- [ ] PostgreSQL Migration evaluieren
- [ ] CDN Integration (Cloudflare)
- [ ] Microservices Architecture
- [ ] Chaos Engineering Tests
- [ ] Multi-Region Deployment
## Kosten-Nutzen-Analyse
### Zusätzliche Infrastruktur-Kosten
- **Redis Server:** €5-10/Monat
- **Backup Server:** €5-15/Monat
- **Monitoring Tools:** €0-20/Monat (Uptime Robot Free, Grafana Cloud)
- **CDN:** €0-50/Monat (Cloudflare Free Tier)
**Gesamtkosten:** €10-95/Monat zusätzlich
### Nutzen
- **99.9% Uptime** (vs. aktuell ~95%)
- **Automatische Recovery** bei Ausfällen
- **Bessere Performance** durch Caching
- **Proaktive Überwachung** vor Problemen
- **Datenintegrität** durch Backups
## Metriken & KPIs
### Verfügbarkeit
- **Target:** 99.9% Uptime
- **MTTR (Mean Time To Recovery):** < 5 Minuten
- **MTBF (Mean Time Between Failures):** > 30 Tage
### Performance
- **Response Time:** < 200ms (95th percentile)
- **Redirect Time:** < 50ms
- **Error Rate:** < 0.1%
### Monitoring
- **Alert Response Time:** < 2 Minuten
- **Backup Success Rate:** 100%
- **Health Check Success:** > 99.5%
## Fazit
Das aktuelle Single-Point-of-Failure Setup birgt erhebliche Risiken für die Verfügbarkeit von uLoad. Mit den vorgeschlagenen Maßnahmen kann die Infrastruktur deutlich robuster und ausfallsicherer gestaltet werden.
**Empfohlene Prioritäten:**
1. **Sofort:** Verbessertes Error Handling und Monitoring
2. **Kurzfristig:** Service Separation und Backup-Strategie
3. **Mittelfristig:** Load Balancing und Caching
4. **Langfristig:** Microservices und Multi-Region
Der Plan bietet einen gestuften Ansatz, um die Ausfallsicherheit schrittweise zu erhöhen, ohne die laufende Entwicklung zu blockieren.

View file

@ -0,0 +1,498 @@
# Unified Card System - Konzept & Implementierungsplan
## 🎯 Vision
Ein universelles, modulares Card-System, das über Datenbank konfigurierbar ist, Themes unterstützt und einfach in andere Projekte portiert werden kann.
---
## 📦 1. Card-Komponenten-Architektur
### Basis-Card-Komponente
```svelte
<!-- $lib/components/cards/BaseCard.svelte -->
<script lang="ts">
interface CardConfig {
id: string;
variant: 'default' | 'compact' | 'hero' | 'minimal';
theme?: ThemeConfig;
modules: ModuleConfig[];
layout: LayoutConfig;
animations?: AnimationConfig;
responsive?: ResponsiveConfig;
}
</script>
```
### Module-System
Jede Card besteht aus konfigurierbaren Modulen:
```typescript
interface ModuleConfig {
type: 'header' | 'content' | 'footer' | 'media' | 'stats' | 'actions' | 'custom';
component: string; // Dynamisch geladene Komponente
props: Record<string, any>;
order: number;
visibility: 'always' | 'desktop' | 'mobile' | 'conditional';
grid?: { col: number; row: number; span: number };
}
```
### Beispiel-Module
- **HeaderModule**: Titel, Avatar, Badges
- **ContentModule**: Text, Listen, Tabellen
- **MediaModule**: Bilder, Videos, QR-Codes
- **StatsModule**: Zahlen, Charts, Progress
- **ActionsModule**: Buttons, Links, Dropdowns
- **CustomModule**: Benutzerdefinierte Inhalte
---
## 🗄️ 2. Datenbank-Schema (PocketBase)
### Collections
#### `themes`
```javascript
{
id: string,
name: string,
slug: string,
description: string,
author: string,
version: string,
is_public: boolean,
is_premium: boolean,
price: number,
colors: {
primary: string,
secondary: string,
accent: string,
background: string,
surface: string,
text: string,
border: string,
// Weitere Farben...
},
typography: {
fontFamily: string,
fontSize: object,
fontWeight: object,
lineHeight: object
},
spacing: {
xs: string,
sm: string,
md: string,
lg: string,
xl: string
},
borderRadius: object,
shadows: object,
animations: object,
created: datetime,
updated: datetime
}
```
#### `card_templates`
```javascript
{
id: string,
name: string,
slug: string,
description: string,
category: string, // 'profile', 'links', 'stats', 'media', etc.
theme_id: string, // Relation zu themes
is_public: boolean,
modules: [
{
type: string,
component: string,
props: object,
order: number,
visibility: string,
grid: object
}
],
layout: {
columns: number,
gap: string,
padding: string,
maxWidth: string
},
responsive: {
breakpoints: object,
mobileLayout: string
},
preview_image: string,
downloads: number,
rating: number,
created: datetime,
updated: datetime
}
```
#### `user_cards`
```javascript
{
id: string,
user_id: string, // Relation zu users
template_id: string, // Relation zu card_templates
page: string, // 'profile', 'dashboard', etc.
position: number,
custom_config: object, // Überschreibt Template-Config
is_active: boolean,
created: datetime,
updated: datetime
}
```
#### `theme_store`
```javascript
{
id: string,
theme_id: string, // Relation zu themes
featured: boolean,
category: string[], // ['minimal', 'dark', 'colorful', 'professional']
tags: string[],
screenshots: string[],
demo_url: string,
installations: number,
reviews: relation[], // zu theme_reviews
created: datetime,
updated: datetime
}
```
---
## 🎨 3. Theme-System
### Theme-Provider
```svelte
<!-- $lib/providers/ThemeProvider.svelte -->
<script lang="ts">
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
export let theme: ThemeConfig;
const themeStore = writable(theme);
setContext('theme', themeStore);
// CSS-Variablen dynamisch setzen
$: {
if (typeof document !== 'undefined') {
const root = document.documentElement;
Object.entries(theme.colors).forEach(([key, value]) => {
root.style.setProperty(`--theme-${key}`, value);
});
}
}
</script>
```
### Theme-Editor
```svelte
<!-- $lib/components/ThemeEditor.svelte -->
- Live-Preview - Color-Picker - Typography-Editor - Spacing-Controls - Animation-Settings - Export/Import
- Save to Database
```
---
## 🛍️ 4. Theme Store
### Features
1. **Browse & Filter**
- Kategorien (Minimal, Dark, Colorful, Professional)
- Tags (E-Commerce, Portfolio, Blog, Corporate)
- Sortierung (Beliebt, Neu, Bewertung, Preis)
2. **Preview & Demo**
- Live-Preview mit eigenen Daten
- Demo-Seiten
- Screenshots/Videos
- Code-Beispiele
3. **Monetarisierung**
- Free Themes
- Premium Themes (Einmalzahlung)
- Subscription Model
- Revenue Sharing für Theme-Autoren
4. **Community Features**
- Bewertungen & Reviews
- Kommentare
- Fork & Customize
- Share eigene Themes
---
## 🔧 5. Implementierung
### Phase 1: Basis-System (Woche 1-2)
```typescript
// 1. BaseCard Komponente
// 2. Module-Loader
// 3. Theme-Provider
// 4. Basis-Module (Header, Content, Actions)
```
### Phase 2: Datenbank-Integration (Woche 3-4)
```typescript
// 1. PocketBase Collections erstellen
// 2. API-Endpoints
// 3. CRUD-Operationen
// 4. Caching-Strategy
```
### Phase 3: Theme-Editor (Woche 5-6)
```typescript
// 1. Visual Editor
// 2. Code Editor
// 3. Preview-System
// 4. Export/Import
```
### Phase 4: Theme Store (Woche 7-8)
```typescript
// 1. Store-Frontend
// 2. Payment-Integration
// 3. Review-System
// 4. Author-Dashboard
```
---
## 🚀 6. Portabilität & Wiederverwendbarkeit
### NPM Package
```json
{
"name": "@uload/card-system",
"version": "1.0.0",
"exports": {
".": "./dist/index.js",
"./themes": "./dist/themes/index.js",
"./modules": "./dist/modules/index.js"
}
}
```
### Standalone-Version
```javascript
// Eigenständige JS/CSS Bundles
// Web Components Version
// Framework-agnostisch (React, Vue, Angular Adapter)
```
### Integration in andere Projekte
```svelte
<script>
import { CardSystem } from '@uload/card-system';
import { PocketBaseProvider } from '@uload/card-system/providers';
</script>
<CardSystem config={myConfig} theme={myTheme} modules={myModules} />
```
---
## 🎯 7. Use Cases
### 1. Profile Pages
- User-Profile mit Stats, Links, Bio
- Company-Profile mit Services, Team
- Product-Profile mit Features, Pricing
### 2. Dashboards
- Analytics-Cards
- Activity-Feeds
- Quick-Actions
- Status-Widgets
### 3. Content-Management
- Blog-Posts
- Media-Galleries
- Document-Cards
- Event-Cards
### 4. E-Commerce
- Product-Cards
- Category-Cards
- Cart-Items
- Order-Summary
---
## 📊 8. Technische Spezifikationen
### Performance
- Lazy Loading von Modulen
- Virtual Scrolling für Listen
- Image Optimization
- CSS-in-JS oder Tailwind
- Bundle-Splitting
### Accessibility
- ARIA-Labels
- Keyboard-Navigation
- Screen-Reader Support
- High-Contrast Themes
### Security
- XSS-Protection
- CSP-Headers
- Input-Sanitization
- Rate-Limiting
---
## 🔄 9. Migration Strategy
### Von aktuellem System
1. Identifiziere alle Card-Varianten
2. Extrahiere gemeinsame Patterns
3. Erstelle Module für jeden Use-Case
4. Schrittweise Migration
5. Backward-Compatibility
### Beispiel-Migration
```svelte
<!-- Alt -->
<div class="profile-card">
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
<!-- Neu -->
<BaseCard template="profile-basic">
<HeaderModule {user} />
<ContentModule text={user.bio} />
</BaseCard>
```
---
## 💡 10. Erweiterte Features
### KI-Integration
- Auto-Theme-Generation basierend auf Logo/Brand
- Content-Suggestions
- Layout-Optimierung
- A/B-Testing
### Analytics
- Card-Performance-Tracking
- User-Interaction-Heatmaps
- Conversion-Tracking
- Theme-Usage-Statistics
### Collaboration
- Team-Themes
- Shared-Templates
- Version-Control
- Comments & Annotations
---
## 📈 11. Business Model
### Freemium
- **Free**: 5 Themes, Basic-Module
- **Pro**: Unlimited Themes, All Module, Priority Support
- **Enterprise**: Custom Themes, White-Label, API-Access
### Marketplace
- 70/30 Revenue Split mit Theme-Autoren
- Featured Themes
- Sponsored Placements
- Bundle-Deals
---
## 🎯 12. Vorteile des Systems
1. **Flexibilität**: Jede Card individuell konfigurierbar
2. **Konsistenz**: Einheitliches Design-System
3. **Performance**: Optimierte, wiederverwendbare Komponenten
4. **Skalierbarkeit**: Einfach neue Module/Themes hinzufügen
5. **Portabilität**: In andere Projekte übertragbar
6. **Monetarisierung**: Theme-Store als Revenue-Stream
7. **Community**: User können eigene Themes teilen
8. **Wartbarkeit**: Zentrale Theme/Module-Verwaltung
---
## 🚦 13. Nächste Schritte
### Sofort (Diese Woche)
1. [ ] Proof of Concept BaseCard
2. [ ] 3-4 Basis-Module
3. [ ] Theme-Provider implementieren
### Kurzfristig (2-4 Wochen)
1. [ ] Datenbank-Schema erstellen
2. [ ] CRUD-API implementieren
3. [ ] Migration bestehender Cards
### Mittelfristig (1-2 Monate)
1. [ ] Theme-Editor
2. [ ] Theme-Store MVP
3. [ ] NPM-Package vorbereiten
### Langfristig (3-6 Monate)
1. [ ] Marketplace launchen
2. [ ] Enterprise-Features
3. [ ] KI-Integration
---
## 📝 Notizen
- Theme-System könnte auch für andere UI-Elemente verwendet werden
- Card-System als Basis für Page-Builder
- Integration mit bestehenden Design-Tools (Figma, Sketch)
- Mögliche Partnerschaft mit Theme-Autoren
- White-Label-Lösung für Agenturen
---
_Dieses Dokument wird kontinuierlich erweitert und aktualisiert._

View file

@ -0,0 +1,495 @@
# 📧 Komplette E-Mail-System Einrichtung für ulo.ad
## Übersicht
Diese Dokumentation beschreibt die vollständige Einrichtung des E-Mail-Systems für ulo.ad, inklusive Registrierung, E-Mail-Verifizierung, Passwort-Reset und zweisprachige Templates (DE/EN).
---
## 📋 Inhaltsverzeichnis
1. [Voraussetzungen](#voraussetzungen)
2. [SMTP-Konfiguration](#smtp-konfiguration)
3. [PocketBase Einstellungen](#pocketbase-einstellungen)
4. [E-Mail-Templates einrichten](#e-mail-templates-einrichten)
5. [Code-Anpassungen](#code-anpassungen)
6. [Verifizierungs-Flow](#verifizierungs-flow)
7. [Testing](#testing)
8. [Troubleshooting](#troubleshooting)
---
## 🔧 Voraussetzungen
### Benötigte Services:
- **PocketBase** (läuft auf Port 8090)
- **SMTP-Provider** (z.B. Brevo, SendGrid, Mailgun)
- **SvelteKit App** (läuft auf Port 5173)
### Benötigte Dateien:
- ✅ E-Mail-Templates (`docs/mail/email-templates-bilingual.md`)
- ✅ Verifizierungs-Route (`src/routes/verify-email/`)
- ✅ Angepasster Register-Flow (`src/routes/register/+page.server.ts`)
- ✅ Angepasste Login-Seite (`src/routes/login/+page.svelte`)
---
## 📮 SMTP-Konfiguration
### 1. SMTP-Provider einrichten (Beispiel: Brevo)
1. **Account erstellen** bei [Brevo](https://www.brevo.com/)
2. **SMTP-Key generieren**:
- Dashboard → SMTP & API → SMTP Settings
- "Generate new SMTP key" klicken
- Key sicher speichern (beginnt mit `xsmtpsib-`)
### 2. PocketBase SMTP konfigurieren
**In PocketBase Admin** (`http://localhost:8090/_/`):
1. Navigiere zu **Settings → Mail settings**
2. Aktiviere **"Use SMTP mail server"**
3. Trage folgende Daten ein:
```
SMTP server host: smtp-relay.brevo.com
Port: 587
Username: [deine-email@domain.com]
Password: [SMTP-KEY von Brevo]
Use TLS: ✓ (aktiviert)
```
4. **Sender address** eintragen:
```
Sender name: ulo.ad
Sender address: noreply@ulo.ad (oder deine Domain)
```
5. **"Send test email"** klicken zum Testen
6. **Save changes** klicken
### 3. Umgebungsvariablen (für Production)
Erstelle eine `.env.local` Datei:
```bash
# .env.local
PB_SMTP_HOST=smtp-relay.brevo.com
PB_SMTP_PORT=587
PB_SMTP_USER=deine-email@domain.com
PB_SMTP_PASSWORD=xsmtpsib-[DEIN-KEY]
PB_SMTP_TLS=true
```
⚠️ **WICHTIG**: `.env.local` zu `.gitignore` hinzufügen!
---
## ⚙️ PocketBase Einstellungen
### 1. Application URL setzen
**In PocketBase Admin** → **Settings → Application**:
```
Application name: ulo.ad
Application URL: http://localhost:5173 (Development)
https://ulo.ad (Production)
```
### 2. Users Collection konfigurieren
Die `users` Collection wurde erweitert um:
- **language** Field (Select): `de`, `en`, `fr`, `es`, `it`
- **verified** Field (Boolean): Automatisch von PocketBase verwaltet
### 3. Auth Settings prüfen
**Collections → users → Options**:
- ✅ Password auth enabled
- ✅ Email/Username login
- ✅ Verification token duration: 259200 (3 Tage)
- ✅ Auth token duration: 604800 (7 Tage)
---
## 📝 E-Mail-Templates einrichten
### 1. Templates in PocketBase einfügen
**In PocketBase Admin** → **Collections → users → Options**:
Für jedes Template aus `docs/mail/email-templates-bilingual.md`:
#### a) Verification Template
- **Subject**: `Bestätige deine E-Mail / Verify your email - ulo.ad 🔗`
- **Body**: HTML aus Datei kopieren
- **WICHTIG**: URL anpassen von `{APP_URL}/_/#/auth/confirm-verification/{TOKEN}`
zu `{APP_URL}/verify-email?token={TOKEN}`
#### b) Password Reset Template
- **Subject**: `Passwort zurücksetzen / Reset password - ulo.ad 🔐`
- **Body**: HTML aus Datei kopieren
- **URL**: `{APP_URL}/reset-password?token={TOKEN}`
#### c) Email Change Template
- **Subject**: `E-Mail-Adresse ändern / Change email address - ulo.ad 📧`
- **Body**: HTML aus Datei kopieren
#### d) Auth Alert Template (Login von neuem Standort)
- **Subject**: `Neue Anmeldung / New login - ulo.ad 🔔`
- **Body**: HTML aus Datei kopieren
#### e) OTP Template (falls aktiviert)
- **Subject**: `Einmal-Passwort / One-Time Password: {OTP} - ulo.ad 🔑`
- **Body**: HTML aus Datei kopieren
### 2. Template-Variablen
Diese Platzhalter werden automatisch ersetzt:
| Variable | Beschreibung | Beispiel |
| ------------- | -------------------------- | ---------------- |
| `{APP_NAME}` | App-Name | ulo.ad |
| `{APP_URL}` | Basis-URL | https://ulo.ad |
| `{TOKEN}` | Verifikations-Token | eyJhbGc... |
| `{EMAIL}` | User E-Mail | user@example.com |
| `{NEW_EMAIL}` | Neue E-Mail (bei Änderung) | new@example.com |
| `{OTP}` | One-Time Password | 12345678 |
---
## 💻 Code-Anpassungen
### 1. Register-Flow ohne Auto-Login
**Datei**: `src/routes/register/+page.server.ts`
```typescript
// Nach erfolgreicher Registrierung:
// 1. Verification Email senden
try {
await pb.collection('users').requestVerification(email);
console.log('Verification email sent to:', email);
} catch (emailErr) {
console.error('Failed to send verification email:', emailErr);
}
// 2. KEIN Auto-Login - Weiterleitung zur Login-Seite
redirect(303, '/login?registered=true&email=' + encodeURIComponent(email));
```
**Wichtige Änderungen**:
- ❌ Entfernt: Automatisches Login nach Registrierung
- ✅ Hinzugefügt: `requestVerification()` Aufruf
- ✅ Hinzugefügt: Weiterleitung mit E-Mail-Parameter
### 2. E-Mail-Verifizierungs-Route
**Neue Dateien erstellt**:
#### `src/routes/verify-email/+page.server.ts`:
```typescript
import { redirect } from '@sveltejs/kit';
import { pb } from '$lib/pocketbase';
export const load = async ({ url }) => {
const token = url.searchParams.get('token');
if (!token) {
redirect(303, '/login?error=missing-token');
}
try {
// Token verifizieren
await pb.collection('users').confirmVerification(token);
redirect(303, '/login?verified=true');
} catch (error) {
// Fehlerbehandlung
const errorMessage = error?.message || 'Verification failed';
if (errorMessage.includes('expired')) {
redirect(303, '/login?error=token-expired');
} else {
redirect(303, '/login?error=invalid-token');
}
}
};
```
#### `src/routes/verify-email/+page.svelte`:
- Zeigt Ladeanimation während Verifizierung
- Automatische Weiterleitung nach Verarbeitung
### 3. Login-Seite mit Status-Nachrichten
**Datei**: `src/routes/login/+page.svelte`
**Neue Features**:
- ✅ **Erfolgs-Nachricht** nach E-Mail-Verifizierung
- **Info-Box** nach Registrierung mit E-Mail-Adresse
- ⚠️ **Warnung** bei abgelaufenem Token
- ❌ **Fehler** bei ungültigem Token
```typescript
// URL-Parameter auslesen
const justRegistered = $page.url.searchParams.get('registered') === 'true';
const userEmail = $page.url.searchParams.get('email') || '';
const emailVerified = $page.url.searchParams.get('verified') === 'true';
const errorType = $page.url.searchParams.get('error');
```
---
## 🔄 Verifizierungs-Flow
### Kompletter Ablauf:
1. **User registriert sich** (`/register`)
- Formular ausfüllen
- Account wird erstellt (nicht verifiziert)
- `requestVerification()` sendet E-Mail
2. **Weiterleitung zur Login-Seite**
- URL: `/login?registered=true&email=user@example.com`
- Zeigt Info-Box: "Bestätigungs-E-Mail wurde gesendet"
3. **User erhält E-Mail**
- Zweisprachig (DE/EN)
- Enthält Verifizierungs-Link
4. **User klickt Verifizierungs-Link**
- URL: `https://ulo.ad/verify-email?token=TOKEN`
- Token wird validiert
- User wird als "verified" markiert
5. **Weiterleitung nach Verifizierung**
- Bei Erfolg: `/login?verified=true`
- Bei Fehler: `/login?error=token-expired`
6. **User kann sich einloggen**
- Account ist jetzt verifiziert
- Zugang zum Dashboard
---
## 🧪 Testing
### 1. SMTP-Test
In PocketBase Admin:
```
Settings → Mail settings → Send test email
```
### 2. Registrierungs-Test
```bash
# 1. Neue Test-E-Mail verwenden
# 2. Registrieren auf /register
# 3. E-Mail-Postfach prüfen (auch Spam-Ordner!)
# 4. Verifizierungs-Link klicken
# 5. Login versuchen
```
### 3. Token-Test
```bash
# Abgelaufenes Token testen:
/verify-email?token=ALTES_TOKEN
# Ungültiges Token testen:
/verify-email?token=FALSCHES_TOKEN
# Kein Token:
/verify-email
```
### 4. E-Mail erneut anfordern
Falls keine E-Mail ankommt:
```javascript
// In Browser-Konsole (eingeloggt als Admin):
await pb.collection('users').requestVerification('user@example.com');
```
---
## 🐛 Troubleshooting
### Problem: Keine E-Mails werden versendet
**Lösungen**:
1. SMTP-Einstellungen in PocketBase prüfen
2. Application URL prüfen (muss gesetzt sein!)
3. SMTP-Logs prüfen: PocketBase Admin → Logs
4. Firewall/Port 587 prüfen
5. SMTP-Key Gültigkeit prüfen
6. **Template-Komplexität prüfen**: Bei Problemen vereinfachte Templates ohne Emojis/Unicode verwenden (`email-templates-simplified.md`)
### Problem: "Invalid token" Fehler bei funktionierender Verifizierung
**⚠️ WICHTIG: PocketBase Verifizierungs-Quirk**
PocketBase hat ein spezielles Verhalten: Die E-Mail-Verifizierung funktioniert tatsächlich (User wird in DB als verifiziert markiert), ABER die API wirft trotzdem einen Fehler - auch beim ersten erfolgreichen Aufruf!
**Unsere Lösung in `src/routes/verify-email/+page.server.ts`:**
```typescript
try {
// Versuche zu verifizieren
await pb.collection('users').confirmVerification(token);
redirect(303, '/login?verified=true');
} catch (error) {
// PocketBase wirft IMMER einen Fehler, auch bei erfolgreicher Verifizierung!
if (errorMessage.includes('expired')) {
redirect(303, '/login?error=token-expired');
} else {
// Behandle als Erfolg, da Verifizierung trotz Fehler funktioniert
redirect(303, '/login?verified=true');
}
}
```
**Andere Token-Probleme**:
- Token abgelaufen (nach 3 Tagen)
- Falscher Token-Parameter in URL
**Neue Verifizierungs-E-Mail anfordern**:
```javascript
await pb.collection('users').requestVerification('email@example.com');
```
### Problem: User wird automatisch eingeloggt
**Prüfen**:
- `src/routes/register/+page.server.ts`
- KEIN `authWithPassword()` nach Registrierung
- Nur `redirect()` zur Login-Seite
### Problem: E-Mail landet im Spam
**Lösungen**:
1. SPF/DKIM/DMARC Records einrichten
2. Sender-Domain verifizieren
3. "noreply@" vermeiden, besser: "hello@ulo.ad"
4. HTML/Text Ratio optimieren
### Problem: Falsches Branding in E-Mails
**Lösung**:
- Alle Templates in PocketBase aktualisieren
- "uLoad" durch "ulo.ad" ersetzen
- Cache leeren
---
## 📁 Dateistruktur
```
/docs/mail/
├── COMPLETE-EMAIL-SETUP-GUIDE.md # Diese Datei
├── email-templates-bilingual.md # Alle E-Mail-Templates (mit Emojis)
├── email-templates-simplified.md # Vereinfachte Templates (ohne Emojis/Unicode)
├── SMTP-SETUP-SECURE.md # SMTP-Sicherheit
└── multilingual-email-plan.md # Mehrsprachigkeits-Konzept
/src/routes/
├── register/
│ └── +page.server.ts # Registrierung OHNE Auto-Login
├── login/
│ └── +page.svelte # Status-Nachrichten
├── verify-email/
│ ├── +page.server.ts # Token-Verarbeitung
│ └── +page.svelte # Lade-Animation
└── reset-password/
└── +page.server.ts # Passwort-Reset
```
---
## ✅ Checkliste für Production
- [ ] SMTP-Provider Account erstellt
- [ ] SMTP-Credentials sicher gespeichert
- [ ] PocketBase SMTP konfiguriert
- [ ] Application URL auf Production-Domain gesetzt
- [ ] Alle E-Mail-Templates eingefügt
- [ ] URLs in Templates angepasst (`/verify-email?token=`)
- [ ] Register-Flow ohne Auto-Login
- [ ] Verifizierungs-Route implementiert
- [ ] Login-Seite mit Status-Nachrichten
- [ ] SPF/DKIM/DMARC Records gesetzt
- [ ] Test-Registrierung durchgeführt
- [ ] E-Mail-Empfang getestet
- [ ] Verifizierung getestet
---
## 🚀 Quick Setup (Zusammenfassung)
```bash
# 1. SMTP in PocketBase konfigurieren
# 2. E-Mail-Templates einfügen (mit korrekten URLs!)
# 3. Application URL setzen
# 4. Test-Registrierung durchführen
# 5. E-Mail-Empfang prüfen
# 6. Verifizierungs-Link testen
```
---
## 📚 Wichtige Erkenntnisse
### 1. PocketBase Verifizierungs-Verhalten
- PocketBase verifiziert User erfolgreich, wirft aber trotzdem Fehler
- Lösung: Fehler als Erfolg behandeln (außer bei "expired")
### 2. Template-Kompatibilität
- Unicode-Zeichen (Emojis, Flags) können SMTP-Probleme verursachen
- Lösung: Vereinfachte Templates ohne Emojis verwenden
### 3. Registrierungs-Reihenfolge
- E-Mail-Versand MUSS vor Auth-Operationen erfolgen
- `pb.authStore.clear()` verhindert sonst E-Mail-Versand
## 📞 Support
Bei Problemen prüfe:
1. Diese Dokumentation
2. PocketBase Logs (`/api/logs`)
3. Browser Console
4. Network Tab (401/403 Errors?)
---
_Erstellt: 15. Januar 2025_
_Aktualisiert: 15. Januar 2025_
_Version: 1.1_
_Für: ulo.ad E-Mail-System_

View file

@ -0,0 +1,86 @@
# SICHERE SMTP Konfiguration
## ⚠️ NIEMALS Credentials teilen!
### 1. Erstelle einen neuen SMTP Key in Brevo:
1. Login bei Brevo
2. SMTP & API → SMTP Settings
3. Lösche den kompromittierten Key
4. "Generate new SMTP key"
5. Kopiere den neuen Key (startet mit `xsmtpsib-`)
### 2. Konfiguriere PocketBase SICHER:
**Option A: Direkt in PocketBase UI** (für lokale Entwicklung OK)
- Gehe zu PocketBase Admin → Settings → Mail settings
- Trage ein:
```
Host: smtp-relay.brevo.com
Port: 587
Username: till.schneider@memoro.ai
Password: [NEUER SMTP KEY - NICHT TEILEN!]
TLS: ✓ aktiviert
```
**Option B: Environment Variables** (für Production)
Erstelle eine `.env.local` Datei (NICHT committen!):
```bash
# .env.local (zu .gitignore hinzufügen!)
PB_SMTP_HOST=smtp-relay.brevo.com
PB_SMTP_PORT=587
PB_SMTP_USER=till.schneider@memoro.ai
PB_SMTP_PASSWORD=xsmtpsib-[DEIN-NEUER-KEY-HIER]
PB_SMTP_TLS=true
```
### 3. Füge .env.local zu .gitignore hinzu:
```gitignore
# Secrets
.env.local
.env.production
*.key
*.pem
```
### 4. Für Team-Mitglieder:
Nutze einen Password Manager oder sichere Kommunikation:
- 1Password
- Bitwarden
- Signal/verschlüsselte Nachricht
## WICHTIGE REGELN:
1. **NIEMALS** Passwörter/Keys in:
- GitHub Issues
- Commits
- Öffentlichen Chats
- Unverschlüsselten E-Mails
2. **IMMER** nutzen:
- Environment Variables
- .env.local Files (nicht committed)
- Secret Management Tools
3. **Bei Leak** (wie gerade):
- Sofort Key invalidieren
- Neuen Key erstellen
- Alle Systeme updaten
## Test-Kommando (OHNE echte Credentials):
```bash
# Teste ob SMTP funktioniert (mit env vars)
curl -X POST http://localhost:8090/api/test-email \
-H "Content-Type: application/json" \
-d '{"to": "test@example.com"}'
```
---
**ERINNERUNG**: Der alte Key ist jetzt kompromittiert und muss gelöscht werden!

View file

@ -0,0 +1,765 @@
# Zweisprachige E-Mail Templates für ulo.ad (DE/EN)
## Anleitung zum Einrichten
### Wo die Templates ändern:
1. Öffne PocketBase Admin: `http://localhost:8090/_/`
2. Gehe zu **Collections****users** (oder deine Auth-Collection)
3. Klicke auf **Options** (Zahnrad-Icon)
4. Scrolle zu den E-Mail-Templates Sektionen
5. Ersetze die Standard-Templates mit den unten stehenden Vorlagen
6. **Speichern** nicht vergessen!
### Sprachfeld zur User Collection hinzufügen:
1. Gehe zu **Collections** → **users**
2. Klicke auf **New field**
3. Füge folgendes Feld hinzu:
- **Name**: `language`
- **Type**: `Select`
- **Options**: `de`, `en`, `fr`, `es`, `it`
- **Default**: `de`
- **Required**: false
---
## 1. E-Mail-Verifizierung Template (Zweisprachig)
**Bereich:** Verification template
### Subject:
```
Bestätige deine E-Mail / Verify your email - ulo.ad 🔗
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 ulo.ad</h1>
<p style="color: #64748b; margin-top: 8px; font-size: 14px;">
Deine Links. Dein Style. Deine Kontrolle.<br />
Your links. Your style. Your control.
</p>
</div>
<!-- Main Content Card DEUTSCH -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<div style="display: flex; align-items: center; margin-bottom: 16px;">
<span style="font-size: 24px; margin-right: 10px;">🇩🇪</span>
<h2 style="color: #0f172a; font-size: 24px; margin: 0; font-weight: 600;">
Willkommen bei ulo.ad! 👋
</h2>
</div>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">
Vielen Dank für deine Registrierung! Du bist nur einen Klick davon entfernt, deine persönliche
Link-Sammlung zu erstellen und zu verwalten.
</p>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Bitte bestätige deine E-Mail-Adresse, um alle Features freizuschalten:
</p>
<!-- CTA Button Deutsch -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/verify-email?token={TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);
transition: all 0.3s ease;"
>
✨ E-Mail-Adresse bestätigen
</a>
</div>
<!-- Features Box Deutsch -->
<div
style="background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); border-radius: 12px; padding: 20px; margin: 24px 0; border: 1px solid #bae6fd;"
>
<p style="color: #0369a1; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
🚀 Was dich bei ulo.ad erwartet:
</p>
<ul style="color: #0c4a6e; font-size: 14px; margin: 0; padding-left: 20px; line-height: 1.8;">
<li>Kurze, merkbare Links mit eigenem Branding</li>
<li>Detaillierte Klick-Analysen in Echtzeit</li>
<li>QR-Codes mit anpassbarem Design</li>
<li>Ordner zur Organisation deiner Links</li>
<li>Passwortschutz für sensible Links</li>
<li>Ablaufdatum für zeitlich begrenzte Kampagnen</li>
</ul>
</div>
</div>
<!-- Main Content Card ENGLISH -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<div style="display: flex; align-items: center; margin-bottom: 16px;">
<span style="font-size: 24px; margin-right: 10px;">🇬🇧</span>
<h2 style="color: #0f172a; font-size: 24px; margin: 0; font-weight: 600;">
Welcome to ulo.ad! 👋
</h2>
</div>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">
Thank you for signing up! You're just one click away from creating and managing your personal
link collection.
</p>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Please verify your email address to unlock all features:
</p>
<!-- CTA Button English -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/verify-email?token={TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);
transition: all 0.3s ease;"
>
✨ Verify Email Address
</a>
</div>
<!-- Features Box English -->
<div
style="background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); border-radius: 12px; padding: 20px; margin: 24px 0; border: 1px solid #bae6fd;"
>
<p style="color: #0369a1; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
🚀 What awaits you at ulo.ad:
</p>
<ul style="color: #0c4a6e; font-size: 14px; margin: 0; padding-left: 20px; line-height: 1.8;">
<li>Short, memorable links with your own branding</li>
<li>Detailed click analytics in real-time</li>
<li>QR codes with customizable design</li>
<li>Folders to organize your links</li>
<li>Password protection for sensitive links</li>
<li>Expiration dates for time-limited campaigns</li>
</ul>
</div>
</div>
<!-- Alternative Link -->
<div
style="background: #ffffff; border-radius: 16px; padding: 24px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<p style="color: #94a3b8; font-size: 13px; line-height: 1.6; margin: 0;">
<strong>🇩🇪</strong> Falls der Button nicht funktioniert, kopiere diesen Link in deinen
Browser:<br />
<strong>🇬🇧</strong> If the button doesn't work, copy this link into your browser:
</p>
<div
style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-top: 8px; word-break: break-all;"
>
<a
href="{APP_URL}/verify-email?token={TOKEN}"
style="color: #0ea5e9; font-size: 12px; text-decoration: none;"
>
{APP_URL}/verify-email?token={TOKEN}
</a>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
<strong>🇩🇪</strong> Diese E-Mail wurde an <strong>{EMAIL}</strong> gesendet.<br />
<strong>🇬🇧</strong> This email was sent to <strong>{EMAIL}</strong>.
</p>
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
<strong>🇩🇪</strong> Falls du dich nicht bei ulo.ad registriert hast, kannst du diese E-Mail
sicher ignorieren.<br />
<strong>🇬🇧</strong> If you didn't sign up for ulo.ad, you can safely ignore this email.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 ulo.ad · Built with ❤️ ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## 2. Passwort-Reset Template (Zweisprachig)
**Bereich:** Password reset template
### Subject:
```
Passwort zurücksetzen / Reset password - ulo.ad 🔐
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 ulo.ad</h1>
</div>
<!-- Main Content Card DEUTSCH -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<div style="display: flex; align-items: center; margin-bottom: 16px;">
<span style="font-size: 24px; margin-right: 10px;">🇩🇪</span>
<h2 style="color: #0f172a; font-size: 24px; margin: 0; font-weight: 600;">
Passwort zurücksetzen 🔐
</h2>
</div>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Du hast eine Anfrage zum Zurücksetzen deines Passworts gestellt. Klicke auf den Button unten,
um ein neues Passwort zu wählen:
</p>
<!-- CTA Button Deutsch -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/reset-password?token={TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);"
>
🔄 Neues Passwort festlegen
</a>
</div>
<!-- Security Notice Deutsch -->
<div style="background: #f0f9ff; border-radius: 12px; padding: 16px; margin: 24px 0;">
<p style="color: #0369a1; font-size: 14px; margin: 0 0 8px 0; font-weight: 600;">
🔒 Sicherheitstipps für dein neues Passwort:
</p>
<ul style="color: #0c4a6e; font-size: 13px; margin: 0; padding-left: 20px; line-height: 1.6;">
<li>Mindestens 8 Zeichen lang</li>
<li>Kombination aus Buchstaben, Zahlen und Sonderzeichen</li>
<li>Verwende kein Passwort, das du bereits woanders nutzt</li>
</ul>
</div>
</div>
<!-- Main Content Card ENGLISH -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<div style="display: flex; align-items: center; margin-bottom: 16px;">
<span style="font-size: 24px; margin-right: 10px;">🇬🇧</span>
<h2 style="color: #0f172a; font-size: 24px; margin: 0; font-weight: 600;">
Reset Password 🔐
</h2>
</div>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
You have requested to reset your password. Click the button below to choose a new password:
</p>
<!-- CTA Button English -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/reset-password?token={TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);"
>
🔄 Set New Password
</a>
</div>
<!-- Security Notice English -->
<div style="background: #f0f9ff; border-radius: 12px; padding: 16px; margin: 24px 0;">
<p style="color: #0369a1; font-size: 14px; margin: 0 0 8px 0; font-weight: 600;">
🔒 Security tips for your new password:
</p>
<ul style="color: #0c4a6e; font-size: 13px; margin: 0; padding-left: 20px; line-height: 1.6;">
<li>At least 8 characters long</li>
<li>Combination of letters, numbers, and special characters</li>
<li>Don't use a password you already use elsewhere</li>
</ul>
</div>
</div>
<!-- Warning Box -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 0 20px 24px 20px;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0; line-height: 1.5;">
⚠️ <strong>🇩🇪 Wichtiger Hinweis:</strong> Dieser Link ist aus Sicherheitsgründen nur
<strong>1 Stunde</strong> gültig.<br />
⚠️ <strong>🇬🇧 Important Notice:</strong> This link is only valid for
<strong>1 hour</strong> for security reasons.
</p>
</div>
<!-- Alternative Link -->
<div
style="background: #ffffff; border-radius: 16px; padding: 24px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<p style="color: #94a3b8; font-size: 13px; line-height: 1.6; margin: 0;">
<strong>🇩🇪</strong> Falls der Button nicht funktioniert, kopiere diesen Link in deinen
Browser:<br />
<strong>🇬🇧</strong> If the button doesn't work, copy this link into your browser:
</p>
<div
style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-top: 8px; word-break: break-all;"
>
<a
href="{APP_URL}/reset-password?token={TOKEN}"
style="color: #0ea5e9; font-size: 12px; text-decoration: none;"
>
{APP_URL}/reset-password?token={TOKEN}
</a>
</div>
</div>
<!-- Ignore Notice -->
<div style="background: #f8fafc; border-radius: 8px; padding: 16px; margin: 0 20px;">
<p style="color: #64748b; font-size: 13px; margin: 0;">
<strong>🇩🇪 Du hast kein neues Passwort angefordert?</strong><br />
Dann kannst du diese E-Mail einfach ignorieren. Dein Passwort bleibt unverändert.<br /><br />
<strong>🇬🇧 You didn't request a new password?</strong><br />
Then you can simply ignore this email. Your password remains unchanged.
</p>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
<strong>🇩🇪</strong> Diese E-Mail wurde an <strong>{EMAIL}</strong> gesendet.<br />
<strong>🇬🇧</strong> This email was sent to <strong>{EMAIL}</strong>.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 ulo.ad · Sicher und privat / Safe and private ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## 3. E-Mail-Änderung Template (Zweisprachig)
**Bereich:** Email change template
### Subject:
```
E-Mail-Adresse ändern / Change email address - ulo.ad 📧
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 ulo.ad</h1>
</div>
<!-- Main Content Card DEUTSCH -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<div style="display: flex; align-items: center; margin-bottom: 16px;">
<span style="font-size: 24px; margin-right: 10px;">🇩🇪</span>
<h2 style="color: #0f172a; font-size: 24px; margin: 0; font-weight: 600;">
E-Mail-Adresse ändern 📧
</h2>
</div>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Du hast eine Änderung deiner E-Mail-Adresse beantragt. Bitte bestätige die neue
E-Mail-Adresse, um die Änderung abzuschließen:
</p>
<!-- Info Box Deutsch -->
<div
style="background: #f0f9ff; border-radius: 12px; padding: 16px; margin: 24px 0; border: 1px solid #bae6fd;"
>
<p style="color: #0369a1; font-size: 14px; margin: 0;">
<strong>Alte E-Mail:</strong> {EMAIL}<br />
<strong>Neue E-Mail:</strong> {NEW_EMAIL}
</p>
</div>
<!-- CTA Button Deutsch -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);"
>
✅ Neue E-Mail bestätigen
</a>
</div>
</div>
<!-- Main Content Card ENGLISH -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<div style="display: flex; align-items: center; margin-bottom: 16px;">
<span style="font-size: 24px; margin-right: 10px;">🇬🇧</span>
<h2 style="color: #0f172a; font-size: 24px; margin: 0; font-weight: 600;">
Change Email Address 📧
</h2>
</div>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
You have requested to change your email address. Please confirm the new email address to
complete the change:
</p>
<!-- Info Box English -->
<div
style="background: #f0f9ff; border-radius: 12px; padding: 16px; margin: 24px 0; border: 1px solid #bae6fd;"
>
<p style="color: #0369a1; font-size: 14px; margin: 0;">
<strong>Old Email:</strong> {EMAIL}<br />
<strong>New Email:</strong> {NEW_EMAIL}
</p>
</div>
<!-- CTA Button English -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);"
>
✅ Confirm New Email
</a>
</div>
</div>
<!-- Warning Box -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 0 20px 24px 20px;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0;">
⚠️ <strong>🇩🇪 Wichtig:</strong> Nach der Bestätigung musst du dich mit deiner neuen
E-Mail-Adresse anmelden.<br />
⚠️ <strong>🇬🇧 Important:</strong> After confirmation, you must log in with your new email
address.
</p>
</div>
<!-- Alternative Link -->
<div
style="background: #ffffff; border-radius: 16px; padding: 24px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<p style="color: #94a3b8; font-size: 13px; line-height: 1.6; margin: 0;">
<strong>🇩🇪</strong> Falls der Button nicht funktioniert, kopiere diesen Link in deinen
Browser:<br />
<strong>🇬🇧</strong> If the button doesn't work, copy this link into your browser:
</p>
<div
style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-top: 8px; word-break: break-all;"
>
<a
href="{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}"
style="color: #0ea5e9; font-size: 12px; text-decoration: none;"
>
{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}
</a>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
<strong>🇩🇪</strong> Falls du diese Änderung nicht beantragt hast, ignoriere diese E-Mail.<br />
<strong>🇬🇧</strong> If you didn't request this change, ignore this email.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 ulo.ad ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## 4. OTP (One-Time Password) Template (Zweisprachig)
**Bereich:** OTP template (falls aktiviert)
### Subject:
```
Einmal-Passwort / One-Time Password: {OTP} - ulo.ad 🔑
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 ulo.ad</h1>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600; text-align: center;"
>
🇩🇪 Dein Einmal-Passwort<br />
🇬🇧 Your One-Time Password
</h2>
<p
style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px; text-align: center;"
>
<strong>🇩🇪</strong> Verwende diesen Code, um dich bei ulo.ad anzumelden:<br />
<strong>🇬🇧</strong> Use this code to log in to ulo.ad:
</p>
<!-- OTP Code Box -->
<div
style="background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%); border-radius: 12px; padding: 24px; margin: 24px 0; text-align: center;"
>
<p
style="color: white; font-size: 32px; margin: 0; font-weight: 700; letter-spacing: 8px; font-family: 'Courier New', monospace;"
>
{OTP}
</p>
</div>
<!-- Timer Warning -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 24px 0; text-align: center;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0;">
⏱️ <strong>🇩🇪</strong> Dieser Code ist nur <strong>3 Minuten</strong> gültig<br />
⏱️ <strong>🇬🇧</strong> This code is only valid for <strong>3 minutes</strong>
</p>
</div>
<p style="color: #64748b; font-size: 14px; line-height: 1.6;">
<strong>🇩🇪</strong> Falls du diesen Code nicht angefordert hast, hat möglicherweise jemand
versucht, sich mit deiner E-Mail-Adresse anzumelden. Du kannst diese E-Mail in diesem Fall
ignorieren.<br /><br />
<strong>🇬🇧</strong> If you didn't request this code, someone may have tried to log in with
your email address. You can ignore this email in that case.
</p>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 ulo.ad · Sicher und privat / Safe and private ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
```
---
## 5. Login-Alert Template (Neue Anmeldung) (Zweisprachig)
**Bereich:** Auth alert template
### Subject:
```
Neue Anmeldung / New login - ulo.ad 🔔
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 ulo.ad</h1>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600;"
>
🇩🇪 Neue Anmeldung erkannt 🔔<br />
🇬🇧 New Login Detected 🔔
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
<strong>🇩🇪</strong> Wir haben eine Anmeldung bei deinem ulo.ad Account von einem neuen
Standort erkannt.<br />
<strong>🇬🇧</strong> We detected a login to your ulo.ad account from a new location.
</p>
<!-- Login Details -->
<div
style="background: #f8fafc; border-radius: 12px; padding: 20px; margin: 24px 0; border: 1px solid #e2e8f0;"
>
<p style="color: #0f172a; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
📍 Login Details / Anmelde-Details:
</p>
<ul style="color: #475569; font-size: 14px; margin: 0; padding-left: 20px; line-height: 1.8;">
<li><strong>Zeit / Time:</strong> {TIME}</li>
<li><strong>Browser:</strong> {BROWSER}</li>
<li><strong>Gerät / Device:</strong> {DEVICE}</li>
<li><strong>Standort / Location:</strong> {LOCATION}</li>
<li><strong>IP-Adresse / IP Address:</strong> {IP}</li>
</ul>
</div>
<!-- Action Box - Were you? -->
<div
style="background: #dcfce7; border: 1px solid #86efac; border-radius: 12px; padding: 16px; margin: 24px 0;"
>
<p style="color: #14532d; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
<strong>🇩🇪</strong> Warst du das? / <strong>🇬🇧</strong> Was this you?
</p>
<p style="color: #166534; font-size: 13px; margin: 0;">
<strong>🇩🇪</strong> Wenn ja, kannst du diese E-Mail ignorieren. Dein Account ist sicher.<br />
<strong>🇬🇧</strong> If yes, you can ignore this email. Your account is safe.
</p>
</div>
<!-- Warning Box - Not you? -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 24px 0;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
⚠️ <strong>🇩🇪</strong> Warst du das NICHT? / <strong>🇬🇧</strong> Was this NOT you?
</p>
<p style="color: #7f1d1d; font-size: 13px; margin: 0 0 16px 0;">
<strong>🇩🇪</strong> Ändere sofort dein Passwort, um deinen Account zu sichern:<br />
<strong>🇬🇧</strong> Change your password immediately to secure your account:
</p>
<div style="text-align: center;">
<a
href="{APP_URL}/forgot-password"
style="display: inline-block; background: #dc2626;
color: white; padding: 12px 24px; border-radius: 8px;
text-decoration: none; font-weight: 600; font-size: 14px;"
>
🔐 Passwort ändern / Change Password
</a>
</div>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
<strong>🇩🇪</strong> Diese Sicherheitsbenachrichtigung wurde an
<strong>{EMAIL}</strong> gesendet.<br />
<strong>🇬🇧</strong> This security notification was sent to <strong>{EMAIL}</strong>.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 ulo.ad · Deine Sicherheit ist uns wichtig / Your security is important to us ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## Verfügbare Variablen
Diese Platzhalter werden automatisch von PocketBase ersetzt:
| Variable | Beschreibung |
| ------------- | ---------------------------------- |
| `{APP_NAME}` | Name der App (ulo.ad) |
| `{APP_URL}` | Basis-URL deiner App |
| `{TOKEN}` | Verifikations-/Reset-Token |
| `{EMAIL}` | E-Mail-Adresse des Empfängers |
| `{NEW_EMAIL}` | Neue E-Mail-Adresse (bei Änderung) |
| `{OTP}` | Einmal-Passwort |
| `{TIME}` | Login-Zeit |
| `{BROWSER}` | Browser-Information |
| `{DEVICE}` | Gerät-Information |
| `{LOCATION}` | Standort |
| `{IP}` | IP-Adresse |
---
## Wichtige Hinweise
### URLs anpassen:
⚠️ **WICHTIG**: Die Standard-PocketBase-URLs müssen auf unsere Custom-Pages umgeleitet werden:
- **Password Reset**:
- Alt: `{APP_URL}/_/#/auth/confirm-password-reset/{TOKEN}`
- Neu: `{APP_URL}/reset-password?token={TOKEN}`
- **E-Mail Verifikation**:
- Alt: `{APP_URL}/_/#/auth/confirm-verification/{TOKEN}`
- Neu: `{APP_URL}/verify-email?token={TOKEN}`
### Test-Empfehlungen:
1. **Nach dem Einrichten**: Sende Test-Mails an dich selbst
2. **Verschiedene E-Mail-Clients**: Teste in Gmail, Outlook, Apple Mail
3. **Mobile Ansicht**: Prüfe die Darstellung auf Smartphones
4. **Spam-Check**: Stelle sicher, dass E-Mails nicht im Spam landen
### Design-Konsistenz:
- **Farben**: Verwende die ulo.ad-Farben (#0ea5e9 für Primary)
- **Schriften**: System-Fonts für beste Kompatibilität
- **Logo**: Emoji 🔗 als einfaches Branding-Element
- **Responsive**: Alle Templates sind mobile-optimiert
- **Zweisprachig**: Alle E-Mails enthalten deutsche und englische Texte
---
_Erstellt: 15. Januar 2025_
_Für: ulo.ad E-Mail-System (Zweisprachig)_
_Version: 2.0_

View file

@ -0,0 +1,470 @@
# Vereinfachte E-Mail Templates für ulo.ad (ohne Emojis/Flags)
## Wichtig: Diese Templates funktionieren garantiert!
Falls die komplexen Templates mit Emojis und Flags Probleme machen, verwende diese vereinfachten Versionen. Sie enthalten denselben Inhalt, aber ohne problematische Sonderzeichen.
---
## 1. E-Mail-Verifizierung Template (Vereinfacht)
**Bereich:** Verification template
### Subject:
```
Bestätige deine E-Mail / Verify your email - ulo.ad
```
### Body (HTML):
```html
<div
style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Header -->
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0;">ulo.ad</h1>
<p style="color: #64748b; margin-top: 8px; font-size: 14px;">
Deine Links. Dein Style. Deine Kontrolle.<br />
Your links. Your style. Your control.
</p>
</div>
<!-- Main Content -->
<div
style="background: #ffffff; border-radius: 12px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"
>
<!-- German Section -->
<div style="margin-bottom: 30px;">
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">
[DE] Willkommen bei ulo.ad!
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
Vielen Dank für deine Registrierung! Bitte bestätige deine E-Mail-Adresse, um alle Features
freizuschalten.
</p>
</div>
<!-- English Section -->
<div style="margin-bottom: 30px;">
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">[EN] Welcome to ulo.ad!</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
Thank you for signing up! Please verify your email address to unlock all features.
</p>
</div>
<!-- CTA Button -->
<div style="text-align: center; margin: 40px 0;">
<a
href="{APP_URL}/verify-email?token={TOKEN}"
style="display: inline-block; background: #0ea5e9; color: white;
padding: 16px 40px; border-radius: 8px; text-decoration: none;
font-weight: 600; font-size: 16px;"
>
E-Mail bestätigen / Verify Email
</a>
</div>
<!-- Alternative Link -->
<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e2e8f0;">
<p style="color: #94a3b8; font-size: 13px; margin-bottom: 8px;">
[DE] Falls der Button nicht funktioniert, kopiere diesen Link:<br />
[EN] If the button doesn't work, copy this link:
</p>
<p
style="background: #f8fafc; padding: 12px; border-radius: 6px; word-break: break-all; font-size: 12px; color: #0ea5e9;"
>
{APP_URL}/verify-email?token={TOKEN}
</p>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 30px;">
<p style="color: #94a3b8; font-size: 12px;">
Diese E-Mail wurde an {EMAIL} gesendet.<br />
This email was sent to {EMAIL}.
</p>
<p style="color: #cbd5e1; font-size: 11px; margin-top: 20px;">© 2025 ulo.ad</p>
</div>
</div>
```
---
## 2. Passwort-Reset Template (Vereinfacht)
**Bereich:** Password reset template
### Subject:
```
Passwort zurücksetzen / Reset password - ulo.ad
```
### Body (HTML):
```html
<div
style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Header -->
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0;">ulo.ad</h1>
</div>
<!-- Main Content -->
<div
style="background: #ffffff; border-radius: 12px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"
>
<!-- German Section -->
<div style="margin-bottom: 30px;">
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">
[DE] Passwort zurücksetzen
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
Du hast eine Anfrage zum Zurücksetzen deines Passworts gestellt. Klicke auf den Button
unten, um ein neues Passwort zu wählen.
</p>
</div>
<!-- English Section -->
<div style="margin-bottom: 30px;">
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">[EN] Reset Password</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
You have requested to reset your password. Click the button below to choose a new password.
</p>
</div>
<!-- CTA Button -->
<div style="text-align: center; margin: 40px 0;">
<a
href="{APP_URL}/reset-password?token={TOKEN}"
style="display: inline-block; background: #0ea5e9; color: white;
padding: 16px 40px; border-radius: 8px; text-decoration: none;
font-weight: 600; font-size: 16px;"
>
Neues Passwort festlegen / Set New Password
</a>
</div>
<!-- Warning -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; padding: 16px; margin: 20px 0;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0;">
<strong>[DE]</strong> Dieser Link ist nur 1 Stunde gültig.<br />
<strong>[EN]</strong> This link is only valid for 1 hour.
</p>
</div>
<!-- Alternative Link -->
<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e2e8f0;">
<p style="color: #94a3b8; font-size: 13px; margin-bottom: 8px;">
[DE] Falls der Button nicht funktioniert, kopiere diesen Link:<br />
[EN] If the button doesn't work, copy this link:
</p>
<p
style="background: #f8fafc; padding: 12px; border-radius: 6px; word-break: break-all; font-size: 12px; color: #0ea5e9;"
>
{APP_URL}/reset-password?token={TOKEN}
</p>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 30px;">
<p style="color: #94a3b8; font-size: 12px;">
[DE] Du hast kein neues Passwort angefordert? Ignoriere diese E-Mail.<br />
[EN] You didn't request a new password? Ignore this email.
</p>
<p style="color: #cbd5e1; font-size: 11px; margin-top: 20px;">© 2025 ulo.ad</p>
</div>
</div>
```
---
## 3. E-Mail-Änderung Template (Vereinfacht)
**Bereich:** Email change template
### Subject:
```
E-Mail-Adresse ändern / Change email address - ulo.ad
```
### Body (HTML):
```html
<div
style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Header -->
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0;">ulo.ad</h1>
</div>
<!-- Main Content -->
<div
style="background: #ffffff; border-radius: 12px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"
>
<!-- German Section -->
<div style="margin-bottom: 30px;">
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">
[DE] E-Mail-Adresse ändern
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
Du hast eine Änderung deiner E-Mail-Adresse beantragt. Bitte bestätige die neue
E-Mail-Adresse.
</p>
</div>
<!-- English Section -->
<div style="margin-bottom: 30px;">
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">
[EN] Change Email Address
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
You have requested to change your email address. Please confirm the new email address.
</p>
</div>
<!-- Info Box -->
<div style="background: #f0f9ff; border-radius: 8px; padding: 16px; margin: 20px 0;">
<p style="color: #0369a1; font-size: 14px; margin: 0;">
<strong>Old Email:</strong> {EMAIL}<br />
<strong>New Email:</strong> {NEW_EMAIL}
</p>
</div>
<!-- CTA Button -->
<div style="text-align: center; margin: 40px 0;">
<a
href="{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}"
style="display: inline-block; background: #0ea5e9; color: white;
padding: 16px 40px; border-radius: 8px; text-decoration: none;
font-weight: 600; font-size: 16px;"
>
Neue E-Mail bestätigen / Confirm New Email
</a>
</div>
<!-- Alternative Link -->
<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e2e8f0;">
<p style="color: #94a3b8; font-size: 13px; margin-bottom: 8px;">
[DE] Falls der Button nicht funktioniert, kopiere diesen Link:<br />
[EN] If the button doesn't work, copy this link:
</p>
<p
style="background: #f8fafc; padding: 12px; border-radius: 6px; word-break: break-all; font-size: 12px; color: #0ea5e9;"
>
{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}
</p>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 30px;">
<p style="color: #cbd5e1; font-size: 11px;">© 2025 ulo.ad</p>
</div>
</div>
```
---
## 4. OTP (One-Time Password) Template (Vereinfacht)
**Bereich:** OTP template
### Subject:
```
Einmal-Passwort / One-Time Password: {OTP} - ulo.ad
```
### Body (HTML):
```html
<div
style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Header -->
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0;">ulo.ad</h1>
</div>
<!-- Main Content -->
<div
style="background: #ffffff; border-radius: 12px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"
>
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0; text-align: center;">
[DE] Dein Einmal-Passwort<br />
[EN] Your One-Time Password
</h2>
<p style="color: #475569; font-size: 16px; text-align: center;">
[DE] Verwende diesen Code für die Anmeldung:<br />
[EN] Use this code to log in:
</p>
<!-- OTP Code -->
<div
style="background: #0ea5e9; border-radius: 8px; padding: 20px; margin: 30px 0; text-align: center;"
>
<p
style="color: white; font-size: 32px; margin: 0; font-weight: bold; letter-spacing: 4px; font-family: monospace;"
>
{OTP}
</p>
</div>
<!-- Warning -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; padding: 16px; text-align: center;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0;">
[DE] Dieser Code ist nur 3 Minuten gültig<br />
[EN] This code is only valid for 3 minutes
</p>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 30px;">
<p style="color: #cbd5e1; font-size: 11px;">© 2025 ulo.ad</p>
</div>
</div>
```
---
## 5. Login-Alert Template (Vereinfacht)
**Bereich:** Auth alert template
### Subject:
```
Neue Anmeldung / New login - ulo.ad
```
### Body (HTML):
```html
<div
style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Header -->
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0;">ulo.ad</h1>
</div>
<!-- Main Content -->
<div
style="background: #ffffff; border-radius: 12px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"
>
<h2 style="color: #0f172a; font-size: 24px; margin: 0 0 16px 0;">
[DE] Neue Anmeldung erkannt<br />
[EN] New Login Detected
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6;">
[DE] Wir haben eine Anmeldung von einem neuen Standort erkannt.<br />
[EN] We detected a login from a new location.
</p>
<!-- Login Details -->
<div style="background: #f8fafc; border-radius: 8px; padding: 20px; margin: 20px 0;">
<p style="color: #0f172a; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
Login Details:
</p>
<ul style="color: #475569; font-size: 14px; margin: 0; padding-left: 20px;">
<li>Time: {TIME}</li>
<li>Browser: {BROWSER}</li>
<li>Device: {DEVICE}</li>
<li>Location: {LOCATION}</li>
<li>IP: {IP}</li>
</ul>
</div>
<!-- Action Box -->
<div
style="background: #dcfce7; border: 1px solid #86efac; border-radius: 8px; padding: 16px; margin: 20px 0;"
>
<p style="color: #166534; font-size: 14px; margin: 0;">
<strong>[DE]</strong> Warst du das? Dann kannst du diese E-Mail ignorieren.<br />
<strong>[EN]</strong> Was this you? Then you can ignore this email.
</p>
</div>
<!-- Warning Box -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; padding: 16px; margin: 20px 0;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0 0 12px 0;">
<strong>[DE]</strong> Warst du das NICHT? Ändere sofort dein Passwort!<br />
<strong>[EN]</strong> Was this NOT you? Change your password immediately!
</p>
<div style="text-align: center; margin-top: 16px;">
<a
href="{APP_URL}/forgot-password"
style="display: inline-block; background: #dc2626; color: white;
padding: 12px 24px; border-radius: 6px; text-decoration: none;
font-weight: 600; font-size: 14px;"
>
Passwort ändern / Change Password
</a>
</div>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 30px;">
<p style="color: #94a3b8; font-size: 12px;">
Diese Sicherheitsbenachrichtigung wurde an {EMAIL} gesendet.<br />
This security notification was sent to {EMAIL}.
</p>
<p style="color: #cbd5e1; font-size: 11px; margin-top: 20px;">© 2025 ulo.ad</p>
</div>
</div>
```
---
## Wichtige Hinweise
### Warum vereinfachte Templates?
1. **Keine Emojis/Flags**: Manche SMTP-Server haben Probleme mit Unicode-Zeichen wie 🇩🇪, 🇬🇧, 🔗, etc.
2. **Einfacheres HTML**: Weniger verschachtelte Divs und Styles
3. **Kleinere Dateigröße**: Reduzierte HTML-Größe für bessere Zustellbarkeit
4. **Bessere Kompatibilität**: Funktioniert mit allen E-Mail-Clients
### Verwendung
1. **In PocketBase Admin** (`http://localhost:8090/_/`)
2. **Collections → users → Options**
3. **Jeweiliges Template-Feld** suchen
4. **HTML aus dieser Datei** kopieren und einfügen
5. **Speichern** und testen
### Test-Reihenfolge
1. **Zuerst**: Vereinfachtes Template verwenden
2. **Wenn es funktioniert**: Problem lag an den Emojis/komplexem HTML
3. **Optional**: Schrittweise Emojis wieder hinzufügen und testen
### URLs beachten
- **Verification**: `{APP_URL}/verify-email?token={TOKEN}`
- **Password Reset**: `{APP_URL}/reset-password?token={TOKEN}`
- **Email Change**: Standard PocketBase URL (nicht ändern)
---
_Erstellt: 15. Januar 2025_
_Für: ulo.ad E-Mail-System (Fallback-Templates)_
_Version: 1.0 Simplified_

View file

@ -0,0 +1,584 @@
# E-Mail Templates für uLoad
## Anleitung zum Einrichten
### Wo die Templates ändern:
1. Öffne PocketBase Admin: `http://localhost:8090/_/`
2. Gehe zu **Collections****users** (oder deine Auth-Collection)
3. Klicke auf **Options** (Zahnrad-Icon)
4. Scrolle zu den E-Mail-Templates Sektionen
5. Ersetze die Standard-Templates mit den unten stehenden Vorlagen
6. **Speichern** nicht vergessen!
---
## 1. E-Mail-Verifizierung Template
**Bereich:** Verification template
### Subject:
```
Bestätige deine E-Mail-Adresse für uLoad 🔗
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 uLoad</h1>
<p style="color: #64748b; margin-top: 8px; font-size: 14px;">
Deine Links. Dein Style. Deine Kontrolle.
</p>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600;"
>
Willkommen bei uLoad! 👋
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">
Vielen Dank für deine Registrierung! Du bist nur einen Klick davon entfernt, deine persönliche
Link-Sammlung zu erstellen und zu verwalten.
</p>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Bitte bestätige deine E-Mail-Adresse, um alle Features freizuschalten:
</p>
<!-- CTA Button -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/_/#/auth/confirm-verification/{TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);
transition: all 0.3s ease;"
>
✨ E-Mail-Adresse bestätigen
</a>
</div>
<!-- Features Box -->
<div
style="background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); border-radius: 12px; padding: 20px; margin: 24px 0; border: 1px solid #bae6fd;"
>
<p style="color: #0369a1; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
🚀 Was dich bei uLoad erwartet:
</p>
<ul style="color: #0c4a6e; font-size: 14px; margin: 0; padding-left: 20px; line-height: 1.8;">
<li>Kurze, merkbare Links mit eigenem Branding</li>
<li>Detaillierte Klick-Analysen in Echtzeit</li>
<li>QR-Codes mit anpassbarem Design</li>
<li>Ordner zur Organisation deiner Links</li>
<li>Passwortschutz für sensible Links</li>
<li>Ablaufdatum für zeitlich begrenzte Kampagnen</li>
</ul>
</div>
<!-- Alternative Link -->
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #94a3b8; font-size: 13px; line-height: 1.6; margin: 0;">
Falls der Button nicht funktioniert, kopiere diesen Link in deinen Browser:
</p>
<div
style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-top: 8px; word-break: break-all;"
>
<a
href="{APP_URL}/_/#/auth/confirm-verification/{TOKEN}"
style="color: #0ea5e9; font-size: 12px; text-decoration: none;"
>
{APP_URL}/_/#/auth/confirm-verification/{TOKEN}
</a>
</div>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
Diese E-Mail wurde an <strong>{EMAIL}</strong> gesendet.
</p>
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
Falls du dich nicht bei uLoad registriert hast, kannst du diese E-Mail sicher ignorieren.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 uLoad · Built with ❤️ ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## 2. Passwort-Reset Template
**Bereich:** Password reset template
### Subject:
```
Passwort zurücksetzen für uLoad 🔐
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 uLoad</h1>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600;"
>
Passwort zurücksetzen 🔐
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Du hast eine Anfrage zum Zurücksetzen deines Passworts gestellt. Klicke auf den Button unten,
um ein neues Passwort zu wählen:
</p>
<!-- CTA Button -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/reset-password?token={TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);"
>
🔄 Neues Passwort festlegen
</a>
</div>
<!-- Warning Box -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 24px 0;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0; line-height: 1.5;">
⚠️ <strong>Wichtiger Hinweis:</strong><br />
Dieser Link ist aus Sicherheitsgründen nur <strong>1 Stunde</strong> gültig. Danach musst du
eine neue Anfrage stellen.
</p>
</div>
<!-- Security Notice -->
<div style="background: #f0f9ff; border-radius: 12px; padding: 16px; margin: 24px 0;">
<p style="color: #0369a1; font-size: 14px; margin: 0 0 8px 0; font-weight: 600;">
🔒 Sicherheitstipps für dein neues Passwort:
</p>
<ul style="color: #0c4a6e; font-size: 13px; margin: 0; padding-left: 20px; line-height: 1.6;">
<li>Mindestens 8 Zeichen lang</li>
<li>Kombination aus Buchstaben, Zahlen und Sonderzeichen</li>
<li>Verwende kein Passwort, das du bereits woanders nutzt</li>
</ul>
</div>
<!-- Alternative Link -->
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #94a3b8; font-size: 13px; line-height: 1.6; margin: 0;">
Falls der Button nicht funktioniert, kopiere diesen Link in deinen Browser:
</p>
<div
style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-top: 8px; word-break: break-all;"
>
<a
href="{APP_URL}/reset-password?token={TOKEN}"
style="color: #0ea5e9; font-size: 12px; text-decoration: none;"
>
{APP_URL}/reset-password?token={TOKEN}
</a>
</div>
</div>
<!-- Ignore Notice -->
<div style="margin-top: 24px; padding: 16px; background: #f8fafc; border-radius: 8px;">
<p style="color: #64748b; font-size: 13px; margin: 0;">
<strong>Du hast kein neues Passwort angefordert?</strong><br />
Dann kannst du diese E-Mail einfach ignorieren. Dein Passwort bleibt unverändert und niemand
kann ohne Zugriff auf deine E-Mails dein Passwort ändern.
</p>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
Diese E-Mail wurde an <strong>{EMAIL}</strong> gesendet.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 uLoad · Sicher und privat ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
<p style="color: #cbd5e1; font-size: 10px; margin-top: 8px;">
Aus Sicherheitsgründen speichern wir deine IP-Adresse bei Passwort-Änderungen.
</p>
</div>
</div>
</div>
```
---
## 3. E-Mail-Änderung Template
**Bereich:** Email change template
### Subject:
```
Bestätige deine neue E-Mail-Adresse für uLoad 📧
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 uLoad</h1>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600;"
>
E-Mail-Adresse ändern 📧
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Du hast eine Änderung deiner E-Mail-Adresse beantragt. Bitte bestätige die neue
E-Mail-Adresse, um die Änderung abzuschließen:
</p>
<!-- Info Box -->
<div
style="background: #f0f9ff; border-radius: 12px; padding: 16px; margin: 24px 0; border: 1px solid #bae6fd;"
>
<p style="color: #0369a1; font-size: 14px; margin: 0;">
<strong>Alte E-Mail:</strong> {EMAIL}<br />
<strong>Neue E-Mail:</strong> {NEW_EMAIL}
</p>
</div>
<!-- CTA Button -->
<div style="text-align: center; margin: 32px 0;">
<a
href="{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}"
style="display: inline-block; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white; padding: 16px 40px; border-radius: 10px;
text-decoration: none; font-weight: 600; font-size: 16px;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.25);"
>
✅ Neue E-Mail bestätigen
</a>
</div>
<!-- Warning Box -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 24px 0;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0;">
⚠️ <strong>Wichtig:</strong> Nach der Bestätigung musst du dich mit deiner neuen
E-Mail-Adresse anmelden.
</p>
</div>
<!-- Alternative Link -->
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #94a3b8; font-size: 13px; line-height: 1.6; margin: 0;">
Falls der Button nicht funktioniert, kopiere diesen Link in deinen Browser:
</p>
<div
style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-top: 8px; word-break: break-all;"
>
<a
href="{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}"
style="color: #0ea5e9; font-size: 12px; text-decoration: none;"
>
{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}
</a>
</div>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
Falls du diese Änderung nicht beantragt hast, ignoriere diese E-Mail und melde dich bei uns,
falls du Sicherheitsbedenken hast.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 uLoad ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## 4. OTP (One-Time Password) Template
**Bereich:** OTP template (falls aktiviert)
### Subject:
```
Dein uLoad Einmal-Passwort: {OTP} 🔑
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 uLoad</h1>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600;"
>
Dein Einmal-Passwort 🔑
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Verwende diesen Code, um dich bei uLoad anzumelden:
</p>
<!-- OTP Code Box -->
<div
style="background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%); border-radius: 12px; padding: 24px; margin: 24px 0; text-align: center;"
>
<p
style="color: white; font-size: 32px; margin: 0; font-weight: 700; letter-spacing: 8px; font-family: 'Courier New', monospace;"
>
{OTP}
</p>
</div>
<!-- Timer Warning -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 24px 0; text-align: center;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0;">
⏱️ Dieser Code ist nur <strong>3 Minuten</strong> gültig
</p>
</div>
<p style="color: #64748b; font-size: 14px; line-height: 1.6;">
Falls du diesen Code nicht angefordert hast, hat möglicherweise jemand versucht, sich mit
deiner E-Mail-Adresse anzumelden. Du kannst diese E-Mail in diesem Fall ignorieren.
</p>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 uLoad · Sicher und privat ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
```
---
## 5. Login-Alert Template (Neue Anmeldung)
**Bereich:** Auth alert template
### Subject:
```
Neue Anmeldung bei deinem uLoad Account 🔔
```
### Body (HTML):
```html
<div
style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f8fafc;"
>
<!-- Logo/Header -->
<div style="text-align: center; margin-bottom: 30px; padding: 20px;">
<h1 style="color: #0ea5e9; font-size: 36px; margin: 0; font-weight: 700;">🔗 uLoad</h1>
</div>
<!-- Main Content Card -->
<div
style="background: #ffffff; border-radius: 16px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);"
>
<h2
style="color: #0f172a; font-size: 24px; margin-top: 0; margin-bottom: 16px; font-weight: 600;"
>
Neue Anmeldung erkannt 🔔
</h2>
<p style="color: #475569; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">
Wir haben eine Anmeldung bei deinem uLoad Account von einem neuen Standort erkannt.
</p>
<!-- Login Details -->
<div
style="background: #f8fafc; border-radius: 12px; padding: 20px; margin: 24px 0; border: 1px solid #e2e8f0;"
>
<p style="color: #0f172a; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
📍 Anmelde-Details:
</p>
<ul style="color: #475569; font-size: 14px; margin: 0; padding-left: 20px; line-height: 1.8;">
<li><strong>Zeit:</strong> {TIME}</li>
<li><strong>Browser:</strong> {BROWSER}</li>
<li><strong>Gerät:</strong> {DEVICE}</li>
<li><strong>Standort:</strong> {LOCATION}</li>
<li><strong>IP-Adresse:</strong> {IP}</li>
</ul>
</div>
<!-- Action Box - Warst du das? -->
<div
style="background: #dcfce7; border: 1px solid #86efac; border-radius: 12px; padding: 16px; margin: 24px 0;"
>
<p style="color: #14532d; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
✅ Warst du das?
</p>
<p style="color: #166534; font-size: 13px; margin: 0;">
Wenn ja, kannst du diese E-Mail ignorieren. Dein Account ist sicher.
</p>
</div>
<!-- Warning Box - Warst du das nicht? -->
<div
style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px; margin: 24px 0;"
>
<p style="color: #991b1b; font-size: 14px; margin: 0 0 12px 0; font-weight: 600;">
⚠️ Warst du das NICHT?
</p>
<p style="color: #7f1d1d; font-size: 13px; margin: 0 0 16px 0;">
Ändere sofort dein Passwort, um deinen Account zu sichern:
</p>
<div style="text-align: center;">
<a
href="{APP_URL}/forgot-password"
style="display: inline-block; background: #dc2626;
color: white; padding: 12px 24px; border-radius: 8px;
text-decoration: none; font-weight: 600; font-size: 14px;"
>
🔐 Passwort jetzt ändern
</a>
</div>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 32px; padding: 20px;">
<p style="color: #94a3b8; font-size: 12px; margin: 8px 0;">
Diese Sicherheitsbenachrichtigung wurde an <strong>{EMAIL}</strong> gesendet.
</p>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e2e8f0;">
<p style="color: #cbd5e1; font-size: 11px; margin: 0;">
© 2025 uLoad · Deine Sicherheit ist uns wichtig ·
<a href="https://ulo.ad" style="color: #0ea5e9; text-decoration: none;">ulo.ad</a>
</p>
</div>
</div>
</div>
```
---
## Verfügbare Variablen
Diese Platzhalter werden automatisch von PocketBase ersetzt:
| Variable | Beschreibung |
| ------------- | ---------------------------------- |
| `{APP_NAME}` | Name der App (uload) |
| `{APP_URL}` | Basis-URL deiner App |
| `{TOKEN}` | Verifikations-/Reset-Token |
| `{EMAIL}` | E-Mail-Adresse des Empfängers |
| `{NEW_EMAIL}` | Neue E-Mail-Adresse (bei Änderung) |
| `{OTP}` | Einmal-Passwort |
| `{TIME}` | Login-Zeit |
| `{BROWSER}` | Browser-Information |
| `{DEVICE}` | Gerät-Information |
| `{LOCATION}` | Standort |
| `{IP}` | IP-Adresse |
---
## Wichtige Hinweise
### URLs anpassen:
⚠️ **WICHTIG**: Die Standard-PocketBase-URLs müssen auf unsere Custom-Pages umgeleitet werden:
- **Password Reset**:
- Alt: `{APP_URL}/_/#/auth/confirm-password-reset/{TOKEN}`
- Neu: `{APP_URL}/reset-password?token={TOKEN}`
- **E-Mail Verifikation**:
- Standard: `{APP_URL}/_/#/auth/confirm-verification/{TOKEN}`
- Kann so bleiben oder zu einer Custom-Page geändert werden
### Test-Empfehlungen:
1. **Nach dem Einrichten**: Sende Test-Mails an dich selbst
2. **Verschiedene E-Mail-Clients**: Teste in Gmail, Outlook, Apple Mail
3. **Mobile Ansicht**: Prüfe die Darstellung auf Smartphones
4. **Spam-Check**: Stelle sicher, dass E-Mails nicht im Spam landen
### Design-Konsistenz:
- **Farben**: Verwende die uLoad-Farben (#0ea5e9 für Primary)
- **Schriften**: System-Fonts für beste Kompatibilität
- **Logo**: Emoji 🔗 als einfaches Branding-Element
- **Responsive**: Alle Templates sind mobile-optimiert
---
_Erstellt: 15. Januar 2025_
_Für: uLoad E-Mail-System_
_Version: 1.0_

View file

@ -0,0 +1,529 @@
# Plan: Mehrsprachige E-Mail-Templates für uLoad
## Executive Summary
Implementierung eines Systems für deutsche und englische E-Mail-Templates mit automatischer Spracherkennung basierend auf Nutzerpräferenzen.
---
## 🎯 Ziele
1. **Primär**: Deutsche und englische E-Mail-Templates
2. **Automatische Sprachauswahl** basierend auf Nutzerpräferenz
3. **Fallback**: Englisch als Standard
4. **Erweiterbar**: Einfach neue Sprachen hinzufügen
---
## 📊 Ansätze (von einfach zu komplex)
### Ansatz 1: PocketBase Collection-Erweiterung (⭐ Empfohlen)
**Konzept**: Nutzer-Sprachpräferenz in der users Collection speichern
#### Implementation:
1. **Users Collection erweitern**:
```javascript
// Neues Feld in users collection
{
name: "language",
type: "select",
values: ["de", "en"],
default: "de"
}
```
2. **Custom E-Mail-Service erstellen**:
```typescript
// src/lib/server/email-service.ts
import { pb } from '$lib/pocketbase';
export async function sendLocalizedEmail(
userId: string,
type: 'verification' | 'reset' | 'change',
data: any
) {
// Nutzer-Sprache abrufen
const user = await pb.collection('users').getOne(userId);
const lang = user.language || 'de';
// Template basierend auf Sprache wählen
const template = getTemplate(type, lang);
// E-Mail senden
await sendEmail({
to: user.email,
subject: template.subject,
html: template.body(data)
});
}
```
**Vorteile**:
- ✅ Einfache Implementation
- ✅ Nutzer kann Sprache in Settings ändern
- ✅ Funktioniert mit PocketBase
**Nachteile**:
- ❌ Erfordert Custom Email Handler
- ❌ PocketBase Standard-Mails umgehen
---
### Ansatz 2: Browser-Sprache + IP-Geolocation
**Konzept**: Automatische Spracherkennung ohne Nutzer-Input
#### Implementation:
```typescript
// src/routes/register/+page.server.ts
export const actions = {
register: async ({ request, getClientAddress }) => {
const clientIp = getClientAddress();
const acceptLanguage = request.headers.get('accept-language');
// Sprache ermitteln
const language = detectLanguage(acceptLanguage, clientIp);
// Bei User-Erstellung speichern
await pb.collection('users').create({
email,
password,
language // 'de' oder 'en'
});
}
};
function detectLanguage(acceptLanguage: string, ip: string): string {
// 1. Browser-Sprache prüfen
if (acceptLanguage?.startsWith('de')) return 'de';
if (acceptLanguage?.startsWith('en')) return 'en';
// 2. IP-Geolocation (optional)
// const country = await getCountryFromIP(ip);
// if (['DE', 'AT', 'CH'].includes(country)) return 'de';
// 3. Fallback
return 'en';
}
```
**Vorteile**:
- ✅ Automatisch ohne Nutzer-Aktion
- ✅ Nutzerfreundlich
**Nachteile**:
- ❌ Nicht immer akkurat
- ❌ Zusätzliche Geolocation-API nötig
---
### Ansatz 3: Custom PocketBase Extension (Advanced)
**Konzept**: PocketBase mit Go erweitern für native Unterstützung
#### Struktur:
```go
// pb_hooks/email_localization.go
package main
import (
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
app.OnRecordBeforeCreateRequest("users").Add(func(e *core.RecordCreateEvent) error {
// Sprache aus Request Headers
lang := e.HttpContext.Request().Header.Get("Accept-Language")
e.Record.Set("language", parseLanguage(lang))
return nil
})
app.OnMailerBeforeRecordVerificationSend().Add(func(e *core.MailerRecordEvent) error {
user := e.Record
lang := user.GetString("language")
// Template basierend auf Sprache
if lang == "de" {
e.Message.Subject = "Bestätige deine E-Mail"
e.Message.HTML = germanTemplate(e.Record, e.Token)
} else {
e.Message.Subject = "Verify your email"
e.Message.HTML = englishTemplate(e.Record, e.Token)
}
return nil
})
app.Start()
}
```
**Vorteile**:
- ✅ Native PocketBase Integration
- ✅ Alle Standard-Features bleiben
- ✅ Beste Performance
**Nachteile**:
- ❌ Komplexe Implementation
- ❌ Go-Kenntnisse erforderlich
- ❌ Custom PocketBase Build
---
## 🚀 Empfohlene Lösung: Hybrid-Ansatz
### Phase 1: Quick Win (1-2 Tage)
1. **User Collection erweitern**:
```sql
ALTER TABLE users ADD COLUMN language TEXT DEFAULT 'de';
```
2. **Settings-Page Update**:
```svelte
<!-- src/routes/(app)/settings/+page.svelte -->
<select name="language" bind:value={user.language}>
<option value="de">🇩🇪 Deutsch</option>
<option value="en">🇬🇧 English</option>
</select>
```
3. **Template-Struktur**:
```
docs/mail/templates/
├── de/
│ ├── verification.html
│ ├── reset.html
│ └── change.html
└── en/
├── verification.html
├── reset.html
└── change.html
```
### Phase 2: Custom Email Handler (3-5 Tage)
```typescript
// src/lib/server/email/index.ts
import { readFileSync } from 'fs';
import { compile } from 'handlebars';
export class EmailService {
private templates: Map<string, Function> = new Map();
constructor() {
this.loadTemplates();
}
private loadTemplates() {
const languages = ['de', 'en'];
const types = ['verification', 'reset', 'change'];
for (const lang of languages) {
for (const type of types) {
const path = `./templates/${lang}/${type}.html`;
const template = readFileSync(path, 'utf-8');
const compiled = compile(template);
this.templates.set(`${lang}-${type}`, compiled);
}
}
}
async send(userId: string, type: string, data: any) {
const user = await pb.collection('users').getOne(userId);
const lang = user.language || 'de';
const template = this.templates.get(`${lang}-${type}`);
if (!template) throw new Error('Template not found');
const html = template({
...data,
user,
appUrl: PUBLIC_APP_URL,
currentYear: new Date().getFullYear()
});
await this.sendViaBrevo({
to: user.email,
subject: this.getSubject(lang, type),
html
});
}
private getSubject(lang: string, type: string): string {
const subjects = {
'de-verification': 'Bestätige deine E-Mail für uLoad 🔗',
'en-verification': 'Verify your email for uLoad 🔗',
'de-reset': 'Passwort zurücksetzen für uLoad 🔐',
'en-reset': 'Reset your password for uLoad 🔐'
// ...
};
return subjects[`${lang}-${type}`];
}
}
```
### Phase 3: API Routes (1 Tag)
```typescript
// src/routes/api/auth/verify/+server.ts
import { EmailService } from '$lib/server/email';
export async function POST({ request }) {
const { userId, token } = await request.json();
const emailService = new EmailService();
await emailService.send(userId, 'verification', { token });
return json({ success: true });
}
```
---
## 🌍 Sprach-Detection Strategien
### 1. Bei Registrierung:
```typescript
// Prioritäten:
1. URL-Parameter: ?lang=de
2. Browser Accept-Language Header
3. IP-Geolocation
4. Default: de (für DACH-Region)
```
### 2. Implementation:
```typescript
export function detectUserLanguage(request: Request): 'de' | 'en' {
// 1. Check URL param
const url = new URL(request.url);
const urlLang = url.searchParams.get('lang');
if (urlLang === 'de' || urlLang === 'en') return urlLang;
// 2. Check browser language
const acceptLang = request.headers.get('accept-language') || '';
const browserLang = acceptLang.split(',')[0].split('-')[0].toLowerCase();
if (browserLang === 'de') return 'de';
if (browserLang === 'en') return 'en';
// 3. Check cookie (if user changed language before)
const cookies = parseCookies(request.headers.get('cookie'));
if (cookies.lang === 'de' || cookies.lang === 'en') return cookies.lang;
// 4. Default
return 'de'; // DACH-focused app
}
```
---
## 📁 Datei-Struktur
```
src/
├── lib/
│ ├── server/
│ │ ├── email/
│ │ │ ├── index.ts # EmailService class
│ │ │ ├── templates.ts # Template loader
│ │ │ └── brevo.ts # Brevo API wrapper
│ │ └── i18n/
│ │ ├── detector.ts # Language detection
│ │ └── translations.ts # Email translations
│ └── stores/
│ └── language.ts # Client-side language store
├── routes/
│ ├── api/
│ │ ├── user/language/+server.ts # Update language preference
│ │ └── email/send/+server.ts # Custom email sender
│ └── (app)/
│ └── settings/
│ └── +page.svelte # Language selector
└── hooks.server.ts # Language detection on request
```
---
## 🔄 Migration Plan
### Woche 1:
- [ ] Users Collection um `language` Feld erweitern
- [ ] Settings-Page mit Sprachauswahl
- [ ] Deutsche & englische Templates erstellen
### Woche 2:
- [ ] EmailService Klasse implementieren
- [ ] API Routes für Custom Emails
- [ ] Auto-Detection bei Registrierung
### Woche 3:
- [ ] Testing mit verschiedenen Sprachen
- [ ] Fallback-Mechanismen
- [ ] Documentation
---
## 💡 Quick Start (Minimal Version)
Für einen schnellen Start ohne große Änderungen:
### 1. Zwei PocketBase Instanzen:
```bash
# Deutsche Version
PB_LANG=de ./pocketbase serve --http=127.0.0.1:8090
# Englische Version
PB_LANG=en ./pocketbase serve --http=127.0.0.1:8091
```
### 2. Nginx Proxy:
```nginx
server {
listen 80;
server_name api.ulo.ad;
# Route basierend auf Accept-Language
if ($http_accept_language ~* "^de") {
proxy_pass http://127.0.0.1:8090;
}
proxy_pass http://127.0.0.1:8091; # Default EN
}
```
**Vorteil**: Keine Code-Änderungen nötig
**Nachteil**: Doppelte Wartung
---
## 🎨 Template Management
### Option 1: Handlebars Templates
```handlebars
<!-- templates/de/verification.hbs -->
<h1>Willkommen {{user.name}}!</h1>
<p>Bitte bestätige deine E-Mail:</p>
<a href='{{appUrl}}/verify?token={{token}}'>Bestätigen</a>
```
### Option 2: React Email (Modern)
```tsx
// emails/Verification.tsx
export function VerificationEmail({ user, token, lang }) {
const t = translations[lang];
return (
<Html>
<Head />
<Body>
<Container>
<Heading>
{t.welcome} {user.name}!
</Heading>
<Text>{t.pleaseVerify}</Text>
<Button href={`${APP_URL}/verify?token=${token}`}>{t.verifyButton}</Button>
</Container>
</Body>
</Html>
);
}
```
### Option 3: JSON-basierte Templates
```json
{
"de": {
"verification": {
"subject": "Bestätige deine E-Mail",
"heading": "Willkommen {name}!",
"body": "Bitte bestätige deine E-Mail-Adresse.",
"button": "E-Mail bestätigen"
}
},
"en": {
"verification": {
"subject": "Verify your email",
"heading": "Welcome {name}!",
"body": "Please verify your email address.",
"button": "Verify Email"
}
}
}
```
---
## 🚦 Entscheidungsmatrix
| Kriterium | Ansatz 1 | Ansatz 2 | Ansatz 3 |
| -------------- | ---------- | -------- | ---------- |
| Aufwand | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Flexibilität | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Wartbarkeit | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| Performance | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Zukunftssicher | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
**Empfehlung**: Starte mit Ansatz 1, plane für Ansatz 3
---
## ✅ Nächste Schritte
1. **Sofort (Tag 1)**:
- [ ] Language Feld zu users Collection hinzufügen
- [ ] Settings-Page um Sprachauswahl erweitern
2. **Kurzfristig (Woche 1)**:
- [ ] Templates in DE/EN erstellen
- [ ] Template-Loader implementieren
3. **Mittelfristig (Woche 2-3)**:
- [ ] EmailService mit Sprach-Support
- [ ] Auto-Detection bei Registration
4. **Langfristig (Monat 2)**:
- [ ] Weitere Sprachen (FR, ES, IT)
- [ ] A/B Testing für Templates
- [ ] Analytics pro Sprache
---
## 📚 Ressourcen
- [PocketBase Hooks Documentation](https://pocketbase.io/docs/hooks)
- [Accept-Language Parser](https://www.npmjs.com/package/accept-language-parser)
- [React Email i18n](https://react.email/docs/integrations/i18n)
- [Handlebars i18n Helper](https://github.com/handlebars-lang/handlebars.js/issues/1646)
---
_Erstellt: 15. Januar 2025_
_Status: Bereit zur Diskussion_
_Priorität: Mittel_
_Geschätzter Aufwand: 5-10 Tage für vollständige Implementation_

View file

@ -0,0 +1,213 @@
# PocketBase Development Setup - Implementierungsplan
## 🎯 Ziel
Vollständige Trennung von Development und Production Datenbanken, ähnlich wie bei Redis.
## 📋 Aktuelle Situation
### Probleme:
- ❌ Beide Umgebungen nutzen Production DB (`https://pb.ulo.ad`)
- ❌ Gefahr von Testdaten in Production
- ❌ Keine lokale Entwicklungsumgebung
- ❌ Hardcoded Production URLs im Code
- ❌ Inkonsistente Environment-Variable-Nutzung
### Vorhandene Ressourcen:
- ✅ PocketBase Binary bereits in `backend/` vorhanden
- ✅ `npm run backend` Script existiert
- ✅ Lokale DB-Dateien in `backend/pb_data/`
- ✅ Schema-Migrations in `backend/pb_migrations/`
## 🛠 Implementierungsplan
### Phase 1: Lokale PocketBase einrichten (15 Min)
1. **PocketBase starten**
```bash
cd backend
./pocketbase serve
```
- Läuft auf http://localhost:8090
- Admin UI: http://localhost:8090/_/
2. **Admin Account erstellen**
- Beim ersten Start wird Admin-Account angelegt
- Credentials sicher speichern
3. **Schema von Production kopieren**
```bash
# Export von Production (manuell über Admin UI)
# Import in lokale Instanz
```
### Phase 2: Environment Variables korrigieren (10 Min)
1. **.env.development anpassen**
```env
# PocketBase Configuration (Local Development)
PUBLIC_POCKETBASE_URL=http://localhost:8090
POCKETBASE_URL=http://localhost:8090
# PocketBase Admin (for local development)
POCKETBASE_ADMIN_EMAIL=admin@localhost
POCKETBASE_ADMIN_PASSWORD=localdevpassword123
```
2. **.env.production erstellen**
```env
# PocketBase Configuration (Production)
PUBLIC_POCKETBASE_URL=https://pb.ulo.ad
POCKETBASE_URL=https://pb.ulo.ad
```
### Phase 3: Code-Anpassungen (20 Min)
1. **src/lib/pocketbase.ts**
```typescript
import { dev } from '$app/environment';
// Automatic environment detection
const POCKETBASE_URL = import.meta.env.PUBLIC_POCKETBASE_URL ||
(dev ? 'http://localhost:8090' : 'https://pb.ulo.ad');
```
2. **Hardcoded URLs entfernen**
- `src/routes/p/[username]/+page.server.ts:16`
- `src/lib/scripts/update-links-collection.js:6`
- `src/routes/api/verify/+server.ts:15`
3. **CSP Headers anpassen**
- `src/hooks.server.ts` - Dynamische CSP basierend auf Environment
### Phase 4: Daten-Migration (30 Min)
1. **Test-Daten erstellen**
```bash
# Script für Sample-Daten
npm run seed:dev
```
2. **Production Snapshot (optional)**
- Export wichtiger Test-Links
- Anonymisierte User-Daten
- Keine echten Produktionsdaten!
3. **Migrations synchronisieren**
```bash
# Alle Migrations lokal ausführen
cd backend
./pocketbase migrate up
```
### Phase 5: Development Workflow (10 Min)
1. **Start-Scripts optimieren**
```json
{
"scripts": {
"dev": "npm run dev:frontend",
"dev:frontend": "vite dev",
"dev:backend": "cd backend && ./pocketbase serve",
"dev:all": "concurrently \"npm:dev:backend\" \"npm:dev:frontend\"",
"dev:setup": "npm run dev:backend:setup && npm run dev:seed"
}
}
```
2. **Docker Alternative (optional)**
```yaml
# docker-compose.dev.yml
services:
pocketbase:
image: ghcr.io/pocketbase/pocketbase:latest
ports:
- "8090:8090"
volumes:
- ./backend/pb_data:/pb_data
```
### Phase 6: Testing & Validation (15 Min)
1. **Connection Tests**
- Verify localhost:8090 responds
- Check Admin UI access
- Test API endpoints
2. **Feature Tests**
- Create link
- Register user
- Authentication flow
- Stripe webhooks (mit lokaler URL)
3. **Data Isolation**
- Verify no production data access
- Check environment variables
- Test fallback mechanisms
## 🚀 Quick Start (Nach Implementierung)
```bash
# 1. Backend starten
npm run dev:backend
# 2. In neuem Terminal: Frontend starten
npm run dev:frontend
# Oder alles zusammen:
npm run dev:all
```
## ⚠️ Wichtige Überlegungen
### Daten-Synchronisation
- **NICHT** Production-Daten lokal spiegeln
- Nur Schema/Structure synchronisieren
- Test-Daten separat verwalten
### Secrets Management
- Lokale Admin-Credentials nur für Dev
- Keine Production-Secrets in .env.development
- Stripe Test-Keys für lokale Entwicklung
### Backup Strategy
- Lokale DB regelmäßig committen? (ohne sensible Daten)
- Schema-Änderungen als Migrations tracken
- Production Backups separat
## 📊 Vergleich: Vorher vs Nachher
| Aspekt | Vorher | Nachher |
|--------|---------|---------|
| Dev Database | Production (pb.ulo.ad) | Lokal (localhost:8090) |
| Test-Daten | In Production! | Isoliert lokal |
| Performance | Netzwerk-Latenz | Instant (lokal) |
| Sicherheit | Risiko für Prod-Daten | Vollständig getrennt |
| Offline-Arbeit | Nicht möglich | Voll funktionsfähig |
## 🔄 Migration Checkliste
- [ ] Lokale PocketBase starten
- [ ] Admin Account erstellen
- [ ] Schema importieren
- [ ] Environment Variables anpassen
- [ ] Code von hardcoded URLs befreien
- [ ] Test-Daten erstellen
- [ ] Alle Features lokal testen
- [ ] Team-Dokumentation aktualisieren
- [ ] CI/CD Pipeline anpassen
## 🎉 Vorteile nach Implementierung
1. **Sicherer** - Keine Produktionsdaten-Gefährdung
2. **Schneller** - Lokale DB ohne Netzwerk-Latenz
3. **Flexibler** - Experimente ohne Konsequenzen
4. **Offline-fähig** - Arbeiten ohne Internet
5. **Team-freundlich** - Jeder hat eigene DB
## 📚 Nächste Schritte
1. Entscheidung treffen: Sofort umsetzen oder planen?
2. Team informieren über Änderungen
3. Migration durchführen
4. Dokumentation für Team erstellen
5. CI/CD anpassen für neue Struktur

View file

@ -0,0 +1,122 @@
# PocketBase Collections - Manuelle Einrichtung
Da der Schema-Import nicht funktioniert (veraltetes Format), musst du die Collections manuell erstellen.
## 🎯 Admin Login
1. Gehe zu: http://localhost:8090/_/
2. Login mit:
- Email: `till.schneider@memoro.ai`
- Password: `p0ck3t-RAJ`
## 📦 Collections erstellen
### 1. Links Collection
**Collections → New collection → Base collection**
**Name:** `links`
**Fields hinzufügen (+ New field):**
| Field Name | Type | Required | Options |
|------------|------|----------|---------|
| `short_code` | text | ✅ | Unique: ✅, Min: 3, Max: 50 |
| `original_url` | url | ✅ | - |
| `title` | text | ❌ | Max: 200 |
| `description` | text | ❌ | Max: 500 |
| `user_id` | relation | ❌ | Collection: users, Max select: 1, Cascade delete: ✅ |
| `is_active` | bool | ❌ | - |
| `password` | text | ❌ | - |
| `max_clicks` | number | ❌ | Min: 0 |
| `expires_at` | date | ❌ | - |
| `click_count` | number | ❌ | - |
| `tags` | json | ❌ | - |
**API Rules:**
- List/View rule: `` (leer = public)
- Create rule: `@request.auth.id != ""`
- Update rule: `@request.auth.id = user_id`
- Delete rule: `@request.auth.id = user_id`
### 2. Clicks Collection
**Collections → New collection → Base collection**
**Name:** `clicks`
**Fields:**
| Field Name | Type | Required | Options |
|------------|------|----------|---------|
| `link_id` | relation | ✅ | Collection: links, Max select: 1, Cascade delete: ✅ |
| `ip_hash` | text | ❌ | - |
| `user_agent` | text | ❌ | - |
| `referer` | text | ❌ | - |
| `browser` | text | ❌ | - |
| `device_type` | text | ❌ | - |
| `os` | text | ❌ | - |
| `country` | text | ❌ | - |
| `city` | text | ❌ | - |
| `clicked_at` | date | ❌ | - |
**API Rules:**
- List/View rule: `` (leer = public)
- Create rule: `` (leer = public)
- Update rule: `null` (keine Updates erlaubt)
- Delete rule: `@request.auth.id = link_id.user_id`
### 3. Accounts Collection (Optional)
**Collections → New collection → Base collection**
**Name:** `accounts`
**Fields:**
| Field Name | Type | Required | Options |
|------------|------|----------|---------|
| `name` | text | ✅ | - |
| `owner` | relation | ✅ | Collection: users, Max select: 1 |
| `members` | relation | ❌ | Collection: users, Multiple: ✅ |
| `isActive` | bool | ❌ | - |
| `planType` | select | ❌ | Values: free, team, enterprise |
| `settings` | json | ❌ | - |
## ✅ Nach dem Erstellen
1. **Speichern** nicht vergessen (Save button oben rechts)
2. **Test-Daten laden:**
```bash
node scripts/seed-local-db.js
```
3. **App testen:**
```bash
npm run dev
```
## 🎉 Fertig!
Deine lokale PocketBase ist jetzt bereit mit:
- Admin Account ✅
- Collections ✅
- Test-Daten (nach Seed-Script)
## 📝 Test-URLs
Nach dem Seed-Script:
- http://localhost:5173/test1 - Normaler Link
- http://localhost:5173/test2 - Link mit Click-Limit
- http://localhost:5173/protected - Passwort: `secret123`
## 🔍 Troubleshooting
**"Collection not found" Fehler?**
- Stelle sicher, dass alle Collections erstellt und gespeichert wurden
- Name muss exakt sein (case-sensitive)
**"Invalid relation" Fehler?**
- Erst Links Collection erstellen, dann Clicks
- Users Collection existiert bereits (Standard Auth)

View file

@ -0,0 +1,233 @@
# PocketBase Local Development Setup
## ✅ Was wurde implementiert
### 1. Environment Separation
- **Development**: `http://localhost:8090` (lokal)
- **Production**: `https://pb.ulo.ad` (Coolify)
- Automatische Umgebungserkennung basierend auf `dev` Flag
### 2. Code-Änderungen
- ✅ `.env.development` - Lokale PocketBase URL
- ✅ `.env.production` - Production PocketBase URL
- ✅ `src/lib/pocketbase.ts` - Dynamische URL-Auswahl
- ✅ `src/routes/p/[username]/+page.server.ts` - Environment-basierte URL
- ✅ `src/lib/scripts/update-links-collection.js` - Flexible URL
- ✅ `src/routes/api/verify/+server.ts` - Dynamische Redirect URL
- ✅ `src/hooks.server.ts` - CSP Headers für beide Umgebungen
### 3. Sicherheit
- Keine hardcoded Production URLs mehr
- Vollständige Trennung von Dev/Prod Daten
- Lokale Entwicklung ohne Internetverbindung möglich
## 🚀 Quick Start
### 1. PocketBase starten
```bash
# Terminal 1: Backend
cd backend
./pocketbase serve
# Läuft auf http://localhost:8090
# Admin UI: http://localhost:8090/_/
```
### 2. Admin Account erstellen
1. Öffne http://localhost:8090/_/
2. Erstelle Admin Account (nur beim ersten Mal)
3. Merke dir die Credentials
### 3. Schema importieren
**Option A: Manuell über UI**
1. Login als Admin
2. Settings → Import/Export
3. Load from JSON → `backend/pb_schema.json`
4. Review → Confirm
**Option B: Automatisch (wenn Collections existieren)**
```bash
# Schema ist bereits in backend/pb_migrations/
cd backend
./pocketbase migrate up
```
### 4. Test-Daten erstellen
```bash
# Seed Script ausführen
node scripts/seed-local-db.js
```
Erstellt:
- 2 Test-User (test@localhost, demo@localhost)
- 4 Test-Links (normal, protected, expired, limited)
- Sample Click-Daten
### 5. App starten
```bash
# Terminal 2: Frontend
npm run dev
# Oder alles zusammen:
npm run dev:all
```
## 📝 Test-Credentials
### Users
```
Email: test@localhost
Password: test123456
Email: demo@localhost
Password: demo123456
```
### Links
- `http://localhost:5173/test1` - Normaler Link
- `http://localhost:5173/test2` - Mit Click-Limit (100)
- `http://localhost:5173/protected` - Password: `secret123`
- `http://localhost:5173/expired` - Abgelaufener Link
### Admin
```
URL: http://localhost:8090/_/
Email: [deine Admin Email]
Password: [dein Admin Password]
```
## 🔍 Verification
### 1. Environment Check
```bash
# In Browser Console sollte stehen:
🔧 PocketBase URL: http://localhost:8090
🔧 Environment: development
🔧 Dev mode: true
```
### 2. API Health
```bash
curl http://localhost:5173/health
# sollte zeigen: "pocketbase": "running"
```
### 3. Feature Tests
- [ ] User Registration
- [ ] Login/Logout
- [ ] Link erstellen
- [ ] Link redirect
- [ ] Password-geschützte Links
- [ ] Click-Tracking
## 🛠 Troubleshooting
### PocketBase startet nicht
```bash
# Port bereits belegt?
lsof -i :8090
# Process beenden
kill -9 [PID]
# Neu starten
cd backend && ./pocketbase serve
```
### "Collection not found" Fehler
1. Schema importieren (siehe oben)
2. Oder Collections manuell erstellen:
- users (auth)
- links
- clicks
- accounts
### Environment Variables nicht geladen
```bash
# .env.development muss existieren
cat .env.development
# Sollte enthalten:
PUBLIC_POCKETBASE_URL=http://localhost:8090
```
### CORS Fehler
PocketBase erlaubt standardmäßig alle Origins in Development.
Falls Probleme: Admin UI → Settings → API Rules
## 📊 Development vs Production
| Aspekt | Development | Production |
|--------|------------|------------|
| PocketBase URL | http://localhost:8090 | https://pb.ulo.ad |
| Datenbank | Lokal (SQLite) | Cloud (Coolify) |
| Auth | Test-Accounts | Echte User |
| Stripe | Test-Keys | Live-Keys |
| Redis | localhost:6379 | Coolify Redis |
| SSL | Nein (HTTP) | Ja (HTTPS) |
| CSP | Relaxed | Strict |
## 🔄 Daten-Synchronisation
### Schema Updates von Production holen
```bash
# 1. Export aus Production (Admin UI)
# 2. Speichern als backend/pb_schema.json
# 3. Lokal importieren
```
### Migrations erstellen
```bash
cd backend
./pocketbase migrate create "add_new_field"
# Edit migration file
./pocketbase migrate up
```
## 🎯 Best Practices
1. **Niemals Production-Daten lokal speichern**
2. **Separate Test-Accounts verwenden**
3. **Schema-Änderungen als Migrations tracken**
4. **Regelmäßig lokale DB zurücksetzen**
```bash
# Lokale DB reset
rm backend/pb_data/*.db
cd backend && ./pocketbase serve
# Schema neu importieren
```
## 🚢 Deployment
Beim Deployment nach Production:
1. Environment wird automatisch erkannt
2. Production URLs werden verwendet
3. Keine Code-Änderungen nötig!
```bash
# Build für Production
npm run build
# Preview Production Build lokal
npm run preview
# Nutzt automatisch Production-Config!
```
## 📚 Weitere Ressourcen
- [PocketBase Docs](https://pocketbase.io/docs/)
- [Admin UI Guide](https://pocketbase.io/docs/admin-ui/)
- [API Rules](https://pocketbase.io/docs/api-rules-and-filters/)
- [Migrations](https://pocketbase.io/docs/migrations/)

View file

@ -0,0 +1,124 @@
# Pocketbase Setup
## Installation
### 1. Pocketbase SDK installieren
```bash
npm install pocketbase
```
### 2. Pocketbase Backend herunterladen
```bash
cd backend
./download-pocketbase.sh
```
Das Script lädt automatisch die richtige Version für deine Plattform herunter (macOS ARM64/AMD64).
### 3. MCP Server für Claude Code einrichten
```bash
# MCP Server Repository klonen
mkdir -p mcp-servers && cd mcp-servers
git clone https://github.com/mrwyndham/pocketbase-mcp.git
# Dependencies installieren und bauen
cd pocketbase-mcp
npm install
npm run build
```
Der MCP Server ermöglicht Claude Code direkte Interaktion mit Pocketbase (Collections erstellen, Records verwalten, etc.).
## Server starten
### Einzeln starten
```bash
# Backend
npm run backend
# Frontend
npm run dev
```
### Beide gleichzeitig starten
```bash
npm run dev:all
```
## Admin-Account erstellen
### Über Terminal (empfohlen)
```bash
/app/pocketbase superuser create till.schneider@memoro.ai p0ck3t-RA1N
```
### Über Web-Interface
1. Pocketbase starten: `npm run backend`
2. Browser öffnen: http://127.0.0.1:8090/_/
3. Admin-Account über das Setup-Formular erstellen
## Zugriff
- **Pocketbase Admin Panel**: http://127.0.0.1:8090/_/
- **API Endpoint**: http://127.0.0.1:8090/api/
- **Frontend (SvelteKit)**: http://localhost:5173
## Projekt-Struktur
```
uload/
├── backend/ # Pocketbase Backend
│ ├── pocketbase # Pocketbase Binary
│ ├── pb_data/ # Datenbank & Uploads
│ └── pb_migrations/ # Datenbank-Migrationen
├── mcp-servers/ # MCP Server für Claude Code
│ └── pocketbase-mcp/ # Pocketbase MCP Integration
│ └── build/ # Gebauter MCP Server
├── src/
│ └── lib/
│ └── pocketbase.ts # Pocketbase Client-Konfiguration
├── docs/ # Dokumentation
└── .mcp.json # MCP Konfiguration (in .gitignore)
```
## MCP Server Konfiguration
Die `.mcp.json` Datei wird automatisch erstellt und enthält:
- Pfad zum MCP Server
- Pocketbase URL (http://127.0.0.1:8090)
- Admin-Zugangsdaten
**Wichtig**: Die `.mcp.json` ist in `.gitignore` aufgeführt, da sie sensible Daten enthält.
### Claude Code neu starten
Nach der MCP-Einrichtung muss Claude Code neu gestartet werden:
```bash
cd /Users/tillschneider/Documents/__00__Code/uload
claude
```
Überprüfe die MCP-Integration mit:
```
/mcp
```
## Pocketbase Client verwenden
```typescript
import { pb } from '$lib/pocketbase';
// Beispiel: Records abrufen
const records = await pb.collection('links').getFullList();
```

View file

@ -0,0 +1,55 @@
# Profile Background Color Feature
## Übersicht
Nutzer können jetzt die Hintergrundfarbe ihrer Profilseite anpassen.
## So funktioniert's
### 1. Einstellung ändern
1. Gehe zu **Settings** (`/settings`)
2. Scrolle zum Abschnitt **Profile Appearance**
3. Wähle eine Farbe aus:
- **Color Picker**: Klicke auf das Farbfeld für eine individuelle Farbe
- **Presets**: Wähle aus vordefinierten Farben (Light Gray, Light Blue, Light Green, etc.)
### 2. Vorschau
Die gewählte Farbe wird sofort auf deiner Profilseite (`/p/[username]`) angezeigt.
## Verfügbare Preset-Farben
- Light Gray (Standard): `#f9fafb`
- Light Blue: `#dbeafe`
- Light Green: `#dcfce7`
- Light Yellow: `#fef3c7`
- Light Pink: `#fce7f3`
- Light Purple: `#e9d5ff`
- Dark Gray: `#1f2937`
- Dark Blue: `#0f172a`
- Black: `#000000`
## Technische Details
### Datenbank
- Neues Feld: `profileBackground` (String) in der `users` Collection
- Standard: `#f9fafb` (Light Gray)
### Implementation
- Settings-Seite: Color Picker + Preset-Auswahl
- Profile-Seite: Dynamisches CSS mit inline `style` Attribut
- Für dunkle Farben wird ein leichter Gradient angewendet
### Dateien geändert
- `/src/routes/(app)/settings/+page.server.ts` - Server-Action für Speicherung
- `/src/routes/(app)/settings/+page.svelte` - UI für Farbauswahl
- `/src/routes/p/[username]/+page.server.ts` - Lade Hintergrundfarbe
- `/src/routes/p/[username]/+page.svelte` - Zeige Hintergrundfarbe
- `/src/lib/pocketbase.ts` - User Type aktualisiert
## Beispiel
```html
<div
class="min-h-screen transition-colors duration-300"
style="background: #dbeafe"
>
<!-- Profile content -->
</div>
```

View file

@ -0,0 +1,287 @@
# Projects & Shared Usernames Feature
**Implementiert am:** 16. Januar 2025
**Version:** 1.0.0
**Status:** ✅ Vollständig implementiert
## Übersicht
Das Projects-System ermöglicht es Teams und Organisationen, gemeinsame Link-Sammlungen unter einem einheitlichen Username zu verwalten. Mehrere Nutzer können Links unter demselben Projekt-Username erstellen und verwalten, wodurch eine konsistente Markenpräsenz gewährleistet wird.
## Use Case
**Beispiel: Firma Memoro**
- Erstellt Projekt mit Username `@memoro`
- Mehrere Teammitglieder können Links erstellen
- Alle Links sind unter `ulo.ad/u/memoro/...` erreichbar
- Zentrale Verwaltung und einheitliches Branding
## Technische Implementierung
### Datenbank-Schema
#### 1. **projects Collection**
```javascript
{
id: string (auto),
name: string, // z.B. "Memoro GmbH"
username: string, // z.B. "memoro" (unique)
description: string?, // Projektbeschreibung
logo: file?, // Projekt-Logo
owner_id: relation, // Verweis auf users
settings: json, // Projekt-Einstellungen
is_active: boolean, // Projekt aktiv/inaktiv
created: date,
updated: date
}
```
**Berechtigungen:**
- `listRule/viewRule`: Authentifizierte User (Owner oder Mitglieder)
- `createRule`: Jeder authentifizierte User
- `updateRule`: Nur Owner
- `deleteRule`: Nur Owner
#### 2. **project_members Collection**
```javascript
{
id: string (auto),
project_id: relation, // Verweis auf projects
user_id: relation, // Verweis auf users
role: select, // "admin" | "editor" | "viewer"
can_create_links: boolean,
can_edit_links: boolean,
can_delete_links: boolean,
joined_at: date,
created: date,
updated: date
}
```
**Rollen-Berechtigungen:**
- **Admin**: Volle Verwaltung (Links + Mitglieder)
- **Editor**: Links erstellen und bearbeiten
- **Viewer**: Nur Ansicht
#### 3. **links Collection (erweitert)**
```javascript
{
// Bestehende Felder...
project_id: relation?, // NEU: Verweis auf projects
created_by: relation?, // NEU: Wer hat den Link erstellt
user_id: relation? // Jetzt optional (entweder user_id ODER project_id)
}
```
**Regel-Updates:**
- Links können entweder einem User ODER einem Projekt gehören
- `created_by` trackt immer den Ersteller (wichtig bei Projekt-Links)
### API-Endpunkte & Routes
#### Projekt-Verwaltung
- `GET /projects` - Liste aller Projekte des Users
- `GET /projects/[id]` - Projekt-Details mit Mitgliedern und Links
- `POST /projects` - Neues Projekt erstellen
- `GET /projects/[id]/settings` - Projekt-Einstellungen (geplant)
#### Link-Routing
- `/u/[username]/[code]` - Funktioniert für User UND Projekt-Usernames
- Prüft zuerst `users.username`
- Falls nicht gefunden, prüft `projects.username`
- Leitet zur Original-URL weiter
#### Actions
- `create` - Projekt erstellen mit Username-Validierung
- `addMember` - Mitglied per E-Mail hinzufügen
- `removeMember` - Mitglied entfernen
- `updateMember` - Rolle/Berechtigungen ändern
## UI-Komponenten
### 1. Projects Übersicht (`/projects`)
- Grid-Ansicht aller Projekte
- Unterscheidung: "Your Projects" vs "Member Projects"
- Quick-Create Form mit Username-Validierung
- Visual: Karten mit Name, @username, Beschreibung
### 2. Projekt-Detail (`/projects/[id]`)
- **Header**: Name, Username, URL-Copy-Button
- **Stats**: Links-Anzahl, Mitglieder, Total Clicks
- **Members Panel**:
- Owner mit Badge
- Mitglieder-Liste mit Rollen
- Add/Remove Funktionen für Owner
- **Links Panel**:
- Alle Projekt-Links
- Creator-Attribution
- Click-Statistiken
### 3. Link-Erstellung (erweitert)
- Projekt-Auswahl beim Erstellen
- URL-Parameter: `?project=PROJECT_ID`
- Automatische URL-Generierung mit Projekt-Username
## Sicherheit & Berechtigungen
### Zugriffskontrolle
```sql
-- Projekt-Links anzeigen
@request.auth.id = created_by
|| project_id.owner_id = @request.auth.id
|| @collection.project_members.user_id ?= @request.auth.id
-- Links bearbeiten
created_by = @request.auth.id
|| (project_id && @collection.project_members.user_id = @request.auth.id
&& @collection.project_members.can_edit_links = true)
```
### Username-Validierung
- Nutzt bestehende `validateUsername()` Funktion
- Prüft Eindeutigkeit über beide Collections (users + projects)
- Reservierte Usernames werden blockiert
## Migration & Backward Compatibility
### Bestehende Links
- Alle bestehenden Links bleiben unverändert (user_id gesetzt, project_id = null)
- Keine Breaking Changes für existierende URLs
### Neue Links
- Entweder `user_id` ODER `project_id` gesetzt
- `created_by` wird immer gesetzt für Audit-Trail
## Performance-Überlegungen
### Optimierungen
1. **Username-Lookup**: Sequentiell (users → projects) für minimale Latenz
2. **Caching**: Project-Metadaten können gecacht werden (nicht implementiert)
3. **Indexes**: Username-Felder sollten indiziert sein (PocketBase Default)
### Skalierung
- Unbegrenzte Projekte pro User
- Unbegrenzte Mitglieder pro Projekt
- Links-Limit nur durch Account-Plan begrenzt
## Zukünftige Erweiterungen
### Phase 2 (geplant)
- [ ] Projekt-Settings Page
- [ ] Logo-Upload und Anzeige
- [ ] Projekt-spezifische Themes
- [ ] Öffentliche Projekt-Profile
- [ ] Projekt-Analytics Dashboard
### Phase 3 (Ideen)
- [ ] Projekt-Templates
- [ ] Bulk-Import für Links
- [ ] API-Keys pro Projekt
- [ ] Webhook-Integration
- [ ] Audit-Log für alle Projekt-Aktionen
## Testing-Anleitung
### Manuelles Testing
1. **Projekt erstellen**
```
- Gehe zu /projects
- "New Project" → Name: "Test Firma", Username: "testfirma"
- Prüfe: Projekt erscheint in "Your Projects"
```
2. **Mitglieder verwalten**
```
- Projekt öffnen
- "Add Member" → E-Mail eingeben, Rolle wählen
- Prüfe: Mitglied erscheint in Liste
- Als Mitglied einloggen → Projekt in "Member Projects"
```
3. **Links erstellen**
```
- In Projekt: "New Link" klicken
- URL eingeben, speichern
- Prüfe: Link unter /u/testfirma/[code] erreichbar
```
### Automatisierte Tests (TODO)
```javascript
// Beispiel-Test
describe('Projects', () => {
it('should create project with unique username', async () => {
// Test implementation
});
it('should prevent duplicate project usernames', async () => {
// Test implementation
});
it('should route project links correctly', async () => {
// Test implementation
});
});
```
## Bekannte Limitierungen
1. **Username-Konflikte**: User und Projekt können nicht denselben Username haben
2. **Keine Username-Änderung**: Einmal gesetzt, kann der Username nicht geändert werden
3. **Keine Projekt-Übertragung**: Owner kann nicht gewechselt werden (nur via DB)
4. **Keine Massen-Operationen**: Links müssen einzeln verschoben werden
## Support & Dokumentation
### Für Entwickler
- Code: `/src/routes/(app)/projects/`
- Collections: `projects`, `project_members`
- Utils: Erweiterte `username.ts` Validierung
### Für Nutzer
- Feature-Announcement: [TODO]
- Help-Center Artikel: [TODO]
- Video-Tutorial: [TODO]
## Changelog
### v1.0.0 (16.01.2025)
- ✅ Initial Release
- ✅ Projects & project_members Collections
- ✅ UI für Projekt-Verwaltung
- ✅ Link-Zuordnung zu Projekten
- ✅ URL-Routing für Projekt-Usernames
- ✅ Rollenbasierte Berechtigungen
---
**Entwickelt von:** Claude mit Tillschneider
**Review-Status:** In Produktion
**Letztes Update:** 16.01.2025

View file

@ -0,0 +1,491 @@
Redis Cache für uLoad - Was bringt es
wirklich?
Das Hauptproblem aktuell
Jedes Mal wenn jemand einen deiner
Short-Links klickt, muss deine App:
1. PocketBase fragen "welche URL gehört zu
diesem Short-Code?"
2. Warten bis PocketBase in der SQLite
Datei sucht
3. Antwort zurückgeben und weiterleiten
Das dauert 50-100ms pro Klick. Bei vielen
Klicks wird PocketBase zum Flaschenhals.
Was Redis ändern würde
Redis ist wie ein ultra-schneller
Zwischenspeicher. Statt jedes Mal
PocketBase zu fragen, schaust du erst in
Redis nach. Das ist 20-50x schneller!
Die 3 größten Verbesserungen
1. Link-Redirects (90% deines Traffics)
Problem: Jeder Klick = PocketBase Query =
langsam
Lösung: Beliebte Links werden in Redis
gespeichert
Beispiel:
- Dein Link "ulo.ad/meeting" wird 100x am
Tag geklickt
- Ohne Redis: 100x PocketBase Query (100x
80ms = 8 Sekunden Serverzeit)
- Mit Redis: 1x PocketBase + 99x Redis (1x
80ms + 99x 2ms = 0.28 Sekunden)
Ergebnis: 30x schneller, 95% weniger
PocketBase Last
2. Dashboard Performance
Problem: Dein Dashboard lädt alle deine
Links aus PocketBase
Lösung: Links werden für 5 Minuten gecacht
Beispiel:
- Du hast 50 Links, checkst Dashboard 20x
am Tag
- Ohne Redis: 20x komplette Liste laden =
langsam
- Mit Redis: 1x laden, 19x aus Cache =
blitzschnell
3. Analytics & Statistiken
Problem: Click-Zahlen berechnen ist langsam
(viele Datenbankabfragen)
Lösung: Statistiken werden live berechnet
und gecacht
Beispiel:
- "Zeige Clicks der letzten 7 Tage" braucht
normalerweise komplizierte Queries
- Mit Redis: Zahlen werden kontinuierlich
aktualisiert, sofort verfügbar
Rate Limiting Verbesserung
Aktuell: Dein Rate Limiter vergisst alles
bei Server-Restart
Mit Redis: Rate Limits bleiben bestehen,
auch über Restarts hinweg
Das bedeutet: Angreifer können nicht mehr
durch Server-Restart deine Limits umgehen.
Konkrete Zahlen für dich
Traffic-Verteilung schätzen:
- 90% Redirects (Leute klicken deine Links)
- 8% Dashboard/API (Du managst deine Links)
- 2% Sonstiges (Login, Settings, etc.)
Performance ohne Redis:
- Redirect: 80ms durchschnittlich
- Dashboard laden: 300ms
- Bei 1000 Klicks/Tag: PocketBase ist
gestresst
Performance mit Redis:
- Redirect: 5ms (95% aus Cache)
- Dashboard laden: 20ms (meist aus Cache)
- Bei 10.000 Klicks/Tag: PocketBase
entspannt
Wann merkst du den Unterschied?
Sofort spürbar:
- Dashboard lädt viel schneller (besonders
mit vielen Links)
- Redirects sind blitzschnell
- Analytics laden sofort statt zu "denken"
Bei mehr Traffic:
- Server bleibt entspannt auch bei
Viral-Links
- Keine Timeouts mehr bei hoher Last
- PocketBase überlastet nicht
Skalierung:
- Ohne Redis: ~500 Redirects/Minute machbar
- Mit Redis: ~5000+ Redirects/Minute
machbar
Kosten vs. Nutzen
Option 1: Kostenlos starten
- Upstash Redis (10k Commands/Tag gratis)
- Perfekt zum Testen
- Upgrade wenn nötig
Option 2: Minimale Kosten
- €5-15/Monat für ordentlichen Redis
- Dafür 10x bessere Performance
Was du sparst:
- Weniger Server-Stress = längere
Hardware-Lebensdauer
- Bessere User Experience = mehr zufriedene
Nutzer
- Skalierung möglich ohne neuen Server
Die Realität für uLoad
Jetzt: Bei 100 Klicks gleichzeitig würde
dein Server wahrscheinlich strugglen
Mit Redis: Bei 1000 Klicks gleichzeitig
läuft alles smooth
Jetzt: Dashboard mit 100 Links braucht eine
Sekunde zum Laden
Mit Redis: Dashboard lädt in 0.1 Sekunden
Jetzt: Click-Statistiken berechnen dauert
ewig
Mit Redis: Statistiken sind immer aktuell
und sofort da
Meine ehrliche Einschätzung
Für uLoad ist Redis ein No-Brainer:
- Minimaler Aufwand (2-3 Tage Setup)
- Maximaler Nutzen (10x Performance)
- Kosten fast null (kann gratis starten)
Der größte Gewinn ist bei Redirects - das
ist dein Kernfeature und wird damit
ultra-schnell. Plus du bist ready für
Viral-Links die plötzlich 1000x geklickt
werden.
Bottom Line: Redis macht aus deinem "hobby
project" eine professionelle, skalierbare
Anwendung für praktisch null Zusatzkosten.
Das ist vermutlich das beste ROI was du
kriegen kannst! 🎯
> super danke. wir können ja reddis auch
einfach auf unserem hetzter vps mit coolify
hochfahren oder? was brucht es an
reccourcen? was mus man beachten? sollte es
lieber auf einem adnere server liegen?
sollte es im gleichen project in coolify
liegen?
⏺ Redis auf Hetzner VPS mit Coolify -
Perfekte Idee!
Ja, absolut machbar und sinnvoll!
Dein aktueller Hetzner VPS kann Redis
problemlos mit hosten. Coolify macht das
super einfach.
Resource-Bedarf von Redis
RAM (das Wichtigste):
- Redis lädt alles in den RAM - das macht
es so schnell
- Für uLoad geschätzt: 50-200MB RAM
- Link Cache: ~1MB pro 10.000 Links
- Session Cache: ~10MB für 1000 aktive
User
- Analytics: ~20-50MB je nach History
- Rate Limiting: ~5-10MB
CPU:
- Minimal! Redis ist extrem CPU-effizient
- Für uLoad: <1% CPU Auslastung
- Nur bei komplexen Operationen mehr
Disk:
- Persistence: 100-500MB für Dumps
- Logs: 10-50MB
- Total: <1GB
Dein CX21 VPS Kapazität:
- RAM: 8GB total, aktuell ~2GB verwendet →
6GB frei!
- CPU: 2 vCPUs, aktuell <20% Mehr als
genug
- Disk: 40GB, Redis braucht <1GB Kein
Problem
Fazit: Dein Server kann Redis locker
verkraften! 🎯
Coolify Setup - zwei Optionen
Option 1: Gleiches Projekt (Empfohlen für
Start)
# Einfach Redis Service zu deinem
bestehenden docker-compose hinzufügen
services:
app:
# Deine bestehende App
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
--maxmemory 512mb --maxmemory-policy
allkeys-lru
volumes:
- redis-data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3
volumes:
redis-data:
Option 2: Separates Projekt in Coolify
- Vorteil: Unabhängiges Deployment von
deiner App
- Nachteil: Etwas komplizierter zu
verwalten
Ich empfehle Option 1 - Redis ist so
stabil, das macht keinen Unterschied.
Coolify Konfiguration
Redis Environment Variables:
# In Coolify für Redis Service setzen:
REDIS_PASSWORD=dein-sicheres-passwort-hier
REDIS_MAXMEMORY=512mb
REDIS_SAVE_INTERVAL=900 # Auto-save alle
15 Min
Deine App erweitern:
# Environment Variable für deine App
hinzufügen:
REDIS_URL=redis://:dein-passwort@redis:6379
Networking in Coolify:
- Redis und App sind automatisch im
gleichen Docker Network
- Deine App kann Redis über redis:6379
erreichen
- Kein Port nach außen öffnen nötig
(Sicherheit!)
Wichtige Redis Konfiguration
Memory Management:
# Redis Config (über Command Parameter):
--maxmemory 512mb # Begrenze RAM Nutzung
--maxmemory-policy allkeys-lru # Alte Keys
löschen wenn voll
Persistence:
# Zwei Optionen kombinieren:
--appendonly yes # AOF für Durability
--save 900 1 # RDB Snapshot alle 15
Min
Security:
# Passwort setzen:
--requirepass dein-starkes-passwort
# Gefährliche Commands deaktivieren:
--rename-command FLUSHDB ""
--rename-command FLUSHALL ""
Monitoring in Coolify
Redis Logs überwachen:
- Coolify zeigt Redis Logs in Echtzeit
- Achte auf Memory Warnings
- Connection Errors beobachten
Wichtige Redis Metriken:
# Commands zum Monitoring (über redis-cli):
INFO memory # RAM Nutzung
INFO stats # Operations/sec
INFO clients # Verbindungen
MONITOR # Live Commands (nur
zum Debugging!)
Backup Strategy
Automatische Redis Backups:
# Script in deinem Container:
#!/bin/bash
# redis-backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
redis-cli --rdb
/backups/redis_backup_$DATE.rdb
# In Coolify als Cron Job alle 6 Stunden
Oder einfacher:
# Volume Mount für Persistence reicht:
volumes:
- redis-data:/data # Redis saved
automatisch hier
Separater Server - wann sinnvoll?
Bleib bei einem Server wenn:
- <10.000 Requests/Tag (definitiv dein
Fall)
- <1000 gleichzeitige User
- Development/Early Stage (definitiv dein
Fall)
Separater Redis Server nur bei:
- >100.000 Requests/Tag
- Multi-Region Setup
- Dedicated Redis Cluster mit Failover
Für uLoad: Ein Server reicht völlig!
Coolify Deployment Steps
1. Docker Compose erweitern:
# Zu deiner bestehenden docker-compose.yml
hinzufügen:
services:
# ... deine bestehenden Services
redis:
image: redis:7-alpine
command: >
redis-server
--appendonly yes
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
restart: unless-stopped
networks:
- app-network
healthcheck:
test: ["CMD", "redis-cli", "-a",
"${REDIS_PASSWORD}", "ping"]
interval: 30s
timeout: 10s
retries: 3
volumes:
redis-data:
networks:
app-network:
driver: bridge
2. Environment Variables in Coolify:
# Für Redis:
REDIS_PASSWORD=SuperSecurePassword123!
# Für deine App:
REDIS_URL=redis://:SuperSecurePassword123!@
redis:6379
3. Deploy & Test:
- Coolify deployed automatisch
- Teste Connection aus deiner App
- Check Redis Logs für Errors
Was beachten?
Security:
- Passwort setzen (Redis hat standardmäßig
keins!)
- Port nicht öffentlich machen (nur intern)
- Command Renaming für gefährliche Commands
Performance:
- Memory Limit setzen (512MB reicht für
Start)
- LRU Policy aktivieren (alte Keys werden
gelöscht)
- Connection Pooling in deiner App
Monitoring:
- Redis Logs in Coolify beobachten
- Memory Usage im Auge behalten
- Hit Rate messen (wie oft Cache getroffen
wird)
Troubleshooting
Häufige Probleme:
1. Connection refused: Redis Service nicht
gestartet
2. Auth failed: Passwort falsch oder nicht
gesetzt
3. Memory full: Maxmemory erreicht, LRU
Policy prüfen
Debug Commands:
# In Coolify Terminal (Redis Container):
redis-cli -a dein-passwort info
redis-cli -a dein-passwort ping
redis-cli -a dein-passwort client list
Meine Empfehlung
Setup für uLoad:
1. Gleicher Server (Hetzner VPS) ✅
2. Gleiches Coolify Projekt ✅
3. 512MB Memory Limit ✅
4. Passwort-geschützt ✅
5. Persistence aktiviert ✅
Vorteile:
- Einfachste Lösung
- Keine Extra-Kosten
- Latenz minimal (gleicher Server)
- Easy zu verwalten
Nachteile:
- Keine (für deine Use Case)
Redis auf deinem bestehenden Setup ist der
perfekte nächste Schritt! 🚀

View file

@ -0,0 +1,180 @@
Redis Cache für uLoad - Was bringt es
wirklich?
Das Hauptproblem aktuell
Jedes Mal wenn jemand einen deiner
Short-Links klickt, muss deine App:
1. PocketBase fragen "welche URL gehört zu
diesem Short-Code?"
2. Warten bis PocketBase in der SQLite
Datei sucht
3. Antwort zurückgeben und weiterleiten
Das dauert 50-100ms pro Klick. Bei vielen
Klicks wird PocketBase zum Flaschenhals.
Was Redis ändern würde
Redis ist wie ein ultra-schneller
Zwischenspeicher. Statt jedes Mal
PocketBase zu fragen, schaust du erst in
Redis nach. Das ist 20-50x schneller!
Die 3 größten Verbesserungen
1. Link-Redirects (90% deines Traffics)
Problem: Jeder Klick = PocketBase Query =
langsam
Lösung: Beliebte Links werden in Redis
gespeichert
Beispiel:
- Dein Link "ulo.ad/meeting" wird 100x am
Tag geklickt
- Ohne Redis: 100x PocketBase Query (100x
80ms = 8 Sekunden Serverzeit)
- Mit Redis: 1x PocketBase + 99x Redis (1x
80ms + 99x 2ms = 0.28 Sekunden)
Ergebnis: 30x schneller, 95% weniger
PocketBase Last
2. Dashboard Performance
Problem: Dein Dashboard lädt alle deine
Links aus PocketBase
Lösung: Links werden für 5 Minuten gecacht
Beispiel:
- Du hast 50 Links, checkst Dashboard 20x
am Tag
- Ohne Redis: 20x komplette Liste laden =
langsam
- Mit Redis: 1x laden, 19x aus Cache =
blitzschnell
3. Analytics & Statistiken
Problem: Click-Zahlen berechnen ist langsam
(viele Datenbankabfragen)
Lösung: Statistiken werden live berechnet
und gecacht
Beispiel:
- "Zeige Clicks der letzten 7 Tage" braucht
normalerweise komplizierte Queries
- Mit Redis: Zahlen werden kontinuierlich
aktualisiert, sofort verfügbar
Rate Limiting Verbesserung
Aktuell: Dein Rate Limiter vergisst alles
bei Server-Restart
Mit Redis: Rate Limits bleiben bestehen,
auch über Restarts hinweg
Das bedeutet: Angreifer können nicht mehr
durch Server-Restart deine Limits umgehen.
Konkrete Zahlen für dich
Traffic-Verteilung schätzen:
- 90% Redirects (Leute klicken deine Links)
- 8% Dashboard/API (Du managst deine Links)
- 2% Sonstiges (Login, Settings, etc.)
Performance ohne Redis:
- Redirect: 80ms durchschnittlich
- Dashboard laden: 300ms
- Bei 1000 Klicks/Tag: PocketBase ist
gestresst
Performance mit Redis:
- Redirect: 5ms (95% aus Cache)
- Dashboard laden: 20ms (meist aus Cache)
- Bei 10.000 Klicks/Tag: PocketBase
entspannt
Wann merkst du den Unterschied?
Sofort spürbar:
- Dashboard lädt viel schneller (besonders
mit vielen Links)
- Redirects sind blitzschnell
- Analytics laden sofort statt zu "denken"
Bei mehr Traffic:
- Server bleibt entspannt auch bei
Viral-Links
- Keine Timeouts mehr bei hoher Last
- PocketBase überlastet nicht
Skalierung:
- Ohne Redis: ~500 Redirects/Minute machbar
- Mit Redis: ~5000+ Redirects/Minute
machbar
Kosten vs. Nutzen
Option 1: Kostenlos starten
- Upstash Redis (10k Commands/Tag gratis)
- Perfekt zum Testen
- Upgrade wenn nötig
Option 2: Minimale Kosten
- €5-15/Monat für ordentlichen Redis
- Dafür 10x bessere Performance
Was du sparst:
- Weniger Server-Stress = längere
Hardware-Lebensdauer
- Bessere User Experience = mehr zufriedene
Nutzer
- Skalierung möglich ohne neuen Server
Die Realität für uLoad
Jetzt: Bei 100 Klicks gleichzeitig würde
dein Server wahrscheinlich strugglen
Mit Redis: Bei 1000 Klicks gleichzeitig
läuft alles smooth
Jetzt: Dashboard mit 100 Links braucht eine
Sekunde zum Laden
Mit Redis: Dashboard lädt in 0.1 Sekunden
Jetzt: Click-Statistiken berechnen dauert
ewig
Mit Redis: Statistiken sind immer aktuell
und sofort da
Meine ehrliche Einschätzung
Für uLoad ist Redis ein No-Brainer:
- Minimaler Aufwand (2-3 Tage Setup)
- Maximaler Nutzen (10x Performance)
- Kosten fast null (kann gratis starten)
Der größte Gewinn ist bei Redirects - das
ist dein Kernfeature und wird damit
ultra-schnell. Plus du bist ready für
Viral-Links die plötzlich 1000x geklickt
werden.
Bottom Line: Redis macht aus deinem "hobby
project" eine professionelle, skalierbare
Anwendung für praktisch null Zusatzkosten.
Das ist vermutlich das beste ROI was du
kriegen kannst! 🎯

View file

@ -0,0 +1,302 @@
# Redis Cache Architecture
## System Overview
uload uses Redis as a high-performance caching layer to accelerate link redirects and reduce database load.
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Browser │────▶│ SvelteKit │────▶│ Redis │
└─────────────┘ │ Server │ └─────────────┘
└─────────────┘ │
│ │ Cache Miss
│ ▼
│ ┌─────────────┐
└───────────▶│ PocketBase │
└─────────────┘
```
## Cache Implementation
### File Structure
```
src/lib/server/
├── redis.ts # Redis client configuration and helpers
└── linkCache.ts # Link-specific caching logic
src/routes/
├── [...slug]/
│ └── +page.server.ts # Link redirect with cache
└── api/
└── redis-status/
└── +server.ts # Redis health check endpoint
```
### Core Components
#### 1. Redis Client (`redis.ts`)
Provides a fault-tolerant Redis connection with automatic fallback:
```typescript
// Connection detection
const REDIS_ENABLED = !!(
process.env.REDIS_HOST &&
(process.env.REDIS_PASSWORD || process.env.NODE_ENV === 'development')
);
// Graceful degradation
if (!redis || !redisAvailable) return null;
```
#### 2. Link Cache (`linkCache.ts`)
Implements caching strategies for different link types:
```typescript
class LinkCache {
// Fast redirect caching
async getRedirectUrl(shortCode: string): Promise<string | null>
async cacheRedirect(shortCode: string, targetUrl: string, popular: boolean)
// Full object caching
async cacheLink(link: Link): Promise<void>
async getLink(shortCode: string): Promise<Link | null>
// Cache management
async invalidate(shortCode: string): Promise<void>
async warmCache(links: Link[]): Promise<void>
}
```
## Cache Strategy
### TTL (Time To Live) Policy
| Content Type | TTL | Reason |
|-------------|-----|---------|
| Popular Links | 24 hours | Frequently accessed, rarely changed |
| Normal Links | 5 minutes | Balance between performance and freshness |
| User Link Lists | 5 minutes | May change frequently |
| Password-Protected | Never cached | Security requirement |
| Expired Links | Never cached | Would bypass expiration check |
### Cache Key Patterns
```
redirect:{shortCode} # Direct URL for fast redirects
link:{shortCode} # Full link object with metadata
clicks:{shortCode} # Click counter
user:{userId}:links:page:{n} # Paginated user links
trending:links # Sorted set for analytics
test:ping # Health check key
```
### Cache Warming
Popular links are pre-loaded into cache on startup:
```typescript
async warmCache(links: Link[]): Promise<void> {
for (const link of links) {
await this.cacheRedirect(link.short_code, link.original_url, true);
}
}
```
## Performance Optimization
### 1. Cache-First Strategy
```typescript
// Check cache first (fastest path)
const cachedUrl = await linkCache.getRedirectUrl(shortCode);
if (cachedUrl) {
throw redirect(302, cachedUrl);
}
// Fall back to database
const link = await locals.pb.collection('links').getFirstListItem(...);
```
### 2. Async Cache Population
Cache writes are non-blocking to maintain low latency:
```typescript
// Cache for next time (non-blocking)
if (link.is_active && !link.password) {
await linkCache.cacheRedirect(shortCode, link.original_url);
}
```
### 3. Trending Analytics
Click tracking without blocking redirects:
```typescript
// Async increment hit counter (non-blocking)
this.incrementHitCount(shortCode).catch(console.error);
```
## Fallback Mechanism
### Graceful Degradation
The system continues functioning without Redis:
1. **Detection**: Check Redis availability on startup
2. **Fallback**: Skip cache operations if unavailable
3. **Recovery**: Attempt reconnection periodically
4. **Logging**: Track cache availability for monitoring
### Error Handling
All cache operations are wrapped in try-catch blocks:
```typescript
try {
await ensureRedisConnection();
// Cache operations...
} catch (error) {
console.error('Cache error:', error);
return null; // Continue without cache
}
```
## Security Considerations
### 1. No Sensitive Data Caching
- Password-protected links bypass cache
- User authentication tokens never cached
- Personal data has minimal TTL
### 2. Cache Invalidation
Links are invalidated when:
- Link is updated
- Link is deleted
- Password protection added
- Expiration date reached
### 3. Rate Limiting
Redis enables efficient rate limiting:
```typescript
const key = `rate:${ip}:${endpoint}`;
const count = await cache.incr(key);
if (count === 1) {
await cache.expire(key, 60); // 1 minute window
}
```
## Monitoring & Debugging
### Health Check Endpoint
`GET /api/redis-status`
```json
{
"connected": true,
"host": "localhost",
"enabled": true,
"available": true,
"cachedLinks": 42,
"error": null
}
```
### Console Logging
Development mode provides detailed logs:
```
✅ Redis: Connected successfully
Cache HIT! Redirecting from cache
Cache MISS - fetching from PocketBase
Cached redirect for future use
```
### Performance Metrics
Track cache effectiveness:
```typescript
// Hit rate calculation
const hits = await redis.get('stats:cache:hits') || 0;
const misses = await redis.get('stats:cache:misses') || 0;
const hitRate = hits / (hits + misses) * 100;
```
## Production Considerations
### 1. Memory Management
```bash
# Set max memory in Redis config
maxmemory 256mb
maxmemory-policy allkeys-lru
```
### 2. Persistence Options
```bash
# Disable persistence for cache-only use
save ""
appendonly no
```
### 3. Connection Pooling
```typescript
const redisConfig = {
retryDelayOnFailover: 100,
maxRetriesPerRequest: 3,
enableOfflineQueue: false,
lazyConnect: true
};
```
### 4. Monitoring Setup
- Use Redis INFO command for metrics
- Set up alerts for connection failures
- Monitor memory usage and eviction rate
- Track cache hit/miss ratio
## Scaling Strategies
### Horizontal Scaling
1. **Redis Cluster**: Distribute cache across nodes
2. **Read Replicas**: Separate read/write operations
3. **Sharding**: Partition by link patterns
### Vertical Scaling
1. **Memory**: Increase Redis memory allocation
2. **CPU**: Optimize for single-threaded performance
3. **Network**: Reduce latency with proximity
## Future Enhancements
### Planned Improvements
1. **Smart Preloading**: ML-based prediction of popular links
2. **Geolocation Caching**: CDN-style distributed cache
3. **Real-time Analytics**: Stream processing with Redis Streams
4. **Cache Warming API**: Admin endpoint for cache management
5. **A/B Testing**: Cache different versions for experiments
### Performance Goals
| Metric | Current | Target |
|--------|---------|--------|
| Cache Hit Rate | 70% | 90% |
| Redirect Latency | 20ms | 10ms |
| Memory Usage | 100MB | 50MB |
| TTL Optimization | Static | Dynamic |

View file

@ -0,0 +1,254 @@
# Redis Setup auf Coolify - Complete Guide
## Erfolgreiche Redis Integration für uLoad
Nach einigen Herausforderungen haben wir Redis erfolgreich auf Coolify zum Laufen gebracht. Hier sind die wichtigsten Learnings und die funktionierende Konfiguration.
## ✅ Funktionierende Konfiguration
### Redis Service in Coolify
#### 1. Redis als Database Service hinzufügen
- **Type:** Redis Database
- **Image:** redis:7.2
- **Name:** redis-database-[generated-id]
#### 2. General Settings
```
Username: default
Password: [Sicheres Passwort generieren]
Custom Docker Options: --protected-mode no --bind 0.0.0.0
```
**Wichtig:** Die Custom Docker Options sind KRITISCH! Ohne diese wird Redis Verbindungen ablehnen.
#### 3. Network Configuration
```
Ports Mappings: 6379:6379
Redis URL (internal): [wird automatisch generiert]
```
**Achtung:** Nicht 5432 verwenden (das ist PostgreSQL)!
### Hauptanwendung Environment Variables
#### Funktionierende Konfiguration:
```bash
REDIS_HOST=ycsoowwsc84s0s8gc8oooosk # Der Container-Name (NICHT der Service-Name!)
REDIS_PORT=6379
REDIS_USERNAME=default
REDIS_PASSWORD=[Das gleiche Passwort wie im Redis Service]
```
## 🔍 Wichtige Erkenntnisse
### 1. Container Name vs. Service Name
**Problem:** Der Coolify Service Name funktioniert nicht für die interne Kommunikation.
**Lösung:** Verwende den tatsächlichen Container-Namen:
- ❌ FALSCH: `redis-database-ycsoowwsc84s0s8gc8oooosk`
- ❌ FALSCH: `redis-database-ycsoowwsc84s0s8gc8oooosk.coolify`
- ✅ RICHTIG: `ycsoowwsc84s0s8gc8oooosk`
Der Container-Name findest du in den Redis Logs oder beim Container Start.
### 2. Protected Mode Problem
**Problem:** "Connection is closed" Fehler trotz korrekter Credentials.
**Lösung:** Redis Protected Mode deaktivieren:
```bash
--protected-mode no --bind 0.0.0.0
```
Diese Optionen MÜSSEN in "Custom Docker Options" gesetzt werden!
### 3. Environment Variables Format
**Problem:** REDIS_HOST wurde mit kompletter URL statt nur Hostname gesetzt.
**Lösung:**
- ❌ FALSCH: `REDIS_HOST=redis://default:password@host:6379`
- ✅ RICHTIG: `REDIS_HOST=ycsoowwsc84s0s8gc8oooosk`
REDIS_HOST darf NUR der Hostname sein, keine URL!
### 4. Port Mapping Confusion
**Problem:** Falscher Port (5432 statt 6379) wurde gemappt.
**Lösung:**
- Port 6379 ist Redis
- Port 5432 ist PostgreSQL
- Immer 6379:6379 für Redis verwenden
## 📋 Komplette Setup-Anleitung
### Schritt 1: Redis Service erstellen
1. In Coolify → New Resource → Database → Redis
2. Wähle redis:7.2 als Image
3. Setze Username: `default`
4. Generiere ein starkes Passwort
5. **WICHTIG:** Custom Docker Options: `--protected-mode no --bind 0.0.0.0`
6. Port Mapping: `6379:6379`
7. Deploy
### Schritt 2: Container Name ermitteln
1. Gehe zu Redis Service → Logs
2. Suche nach Container Name (z.B. `ycsoowwsc84s0s8gc8oooosk`)
3. Notiere diesen Namen!
### Schritt 3: Hauptapp konfigurieren
Environment Variables in deiner Hauptapp:
```bash
REDIS_HOST=[Container-Name aus Schritt 2]
REDIS_PORT=6379
REDIS_USERNAME=default
REDIS_PASSWORD=[Passwort aus Redis Service]
```
### Schritt 4: Testen
Erstelle einen Test-Endpoint in deiner App:
```typescript
// src/routes/test-redis/+server.ts
import { json } from '@sveltejs/kit';
import Redis from 'ioredis';
export async function GET() {
const redis = new Redis({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379'),
username: process.env.REDIS_USERNAME,
password: process.env.REDIS_PASSWORD
});
try {
await redis.ping();
await redis.set('test', 'Hello Redis!');
const value = await redis.get('test');
redis.disconnect();
return json({
success: true,
value,
host: process.env.REDIS_HOST
});
} catch (error) {
return json({
success: false,
error: error.message
}, { status: 500 });
}
}
```
## 🚀 Performance-Verbesserungen
Nach erfolgreicher Redis-Integration:
### Link Redirects
- **Vorher:** 50-100ms (PocketBase Query)
- **Nachher:** 2-5ms (Redis Cache)
- **Verbesserung:** 20-50x schneller!
### Dashboard Loading
- **Vorher:** 200-400ms
- **Nachher:** 10-20ms
- **Verbesserung:** 10-20x schneller!
### Analytics
- **Vorher:** 500-1500ms
- **Nachher:** 20-50ms
- **Verbesserung:** 10-30x schneller!
## 🐛 Troubleshooting
### "Connection is closed" Error
1. Check Custom Docker Options: `--protected-mode no --bind 0.0.0.0`
2. Verify Container Name (nicht Service Name!)
3. Check Password ist korrekt
### "ECONNREFUSED" Error
1. Redis Service läuft nicht
2. Falscher Host/Port
3. Network Isolation Problem
### "NOAUTH Authentication required"
1. Password nicht gesetzt in Environment Variables
2. Falsches Password
3. Username fehlt (sollte "default" sein)
### Debug Commands
Im Redis Container (via Coolify Terminal):
```bash
# Test Redis läuft
redis-cli ping
# Mit Auth
redis-cli -a [password] ping
# Check Config
redis-cli -a [password] CONFIG GET bind
redis-cli -a [password] CONFIG GET protected-mode
```
## 💡 Best Practices
### 1. Resource Limits
```bash
--maxmemory 512mb
--maxmemory-policy allkeys-lru
```
### 2. Persistence
```bash
--appendonly yes
--save 900 1 # Save every 15 min if at least 1 key changed
```
### 3. Security
- Niemals Redis Port öffentlich exponieren
- Starkes Passwort verwenden
- Protected Mode nur intern deaktivieren
### 4. Monitoring
- Memory Usage im Auge behalten
- Hit Rate tracken
- Slow Queries monitoren
## 📊 Resource-Bedarf
Für uLoad auf Hetzner CX21:
- **RAM:** 50-200MB (von 8GB verfügbar)
- **CPU:** <1% (von 2 vCPUs)
- **Disk:** <1GB (von 40GB)
Redis ist extrem ressourcen-effizient!
## 🎯 Zusammenfassung
Die wichtigsten Punkte für erfolgreiche Redis-Integration auf Coolify:
1. **Container-Name verwenden**, nicht Service-Name
2. **Protected Mode deaktivieren** mit Custom Docker Options
3. **Port 6379** verwenden, nicht 5432
4. **Environment Variables korrekt formatieren** (REDIS_HOST = nur Hostname)
5. **Test-Endpoint** erstellen zum Verifizieren
Mit dieser Konfiguration läuft Redis stabil und performant auf dem gleichen Hetzner VPS wie die Hauptanwendung, ohne zusätzliche Kosten und mit minimaler Latenz.
## 🔗 Weiterführende Dokumentation
- [Redis Best Practices](https://redis.io/docs/manual/patterns/)
- [Coolify Documentation](https://coolify.io/docs)
- [ioredis Documentation](https://github.com/redis/ioredis)
---
*Dokumentiert nach erfolgreicher Redis-Integration für uLoad auf Coolify, August 2025*

View file

@ -0,0 +1,303 @@
# Redis Cache - Local Development Setup
## Overview
Redis is used in uload to dramatically improve link redirect performance by caching frequently accessed links. This guide covers setting up Redis for local development.
## Prerequisites
- macOS with Homebrew installed
- Node.js 18+
- Running uload development environment
## Installation
### 1. Install Redis via Homebrew
```bash
# Install Redis
brew install redis
# Start Redis as a background service
brew services start redis
# Verify Redis is running
redis-cli ping
# Should return: PONG
```
### 2. Configure Environment Variables
Add the following to your `.env.development` file:
```env
# Redis Configuration (Local Development)
REDIS_HOST=localhost
REDIS_PORT=6379
# No password needed for local Redis
REDIS_PASSWORD=
```
### 3. Verify Connection
Start your development server with Redis environment variables:
```bash
# Option 1: If .env.development is loaded automatically
npm run dev
# Option 2: With explicit environment variables
REDIS_HOST=localhost REDIS_PORT=6379 npm run dev
```
Check the console output for:
```
✅ Redis: Connected successfully
```
### 4. Test Redis Status
Visit the Redis status endpoint:
```bash
curl http://localhost:5173/api/redis-status | jq
```
Expected response:
```json
{
"connected": true,
"host": "localhost",
"enabled": true,
"available": true,
"cachedLinks": 0,
"error": null
}
```
## How It Works
### Cache Flow
1. **First Visit (Cache MISS)**
```
User → Short Link → Check Redis (miss) → Query Database → Redirect → Cache Result
```
- Takes ~100-200ms
- Stores result in Redis for future requests
2. **Subsequent Visits (Cache HIT)**
```
User → Short Link → Check Redis (hit) → Redirect
```
- Takes ~10-20ms
- Skips database query entirely
### Cache Keys Structure
```
redirect:{shortCode} # Stores the target URL for quick redirects
link:{shortCode} # Stores full link object
clicks:{shortCode} # Stores click count
user:{userId}:links:page:{n} # Cached user link pages
trending:links # Sorted set of trending links
```
## Development Workflow
### 1. Monitor Redis Activity
Watch real-time Redis commands:
```bash
redis-cli monitor
```
### 2. View Cached Links
```bash
# List all cached redirects
redis-cli keys "redirect:*"
# Get specific redirect
redis-cli get "redirect:abc123"
# Check TTL (time to live)
redis-cli ttl "redirect:abc123"
```
### 3. Clear Cache
```bash
# Clear all Redis data
redis-cli flushall
# Clear specific key
redis-cli del "redirect:abc123"
```
### 4. Debug Cache Hits/Misses
Enable verbose logging in your browser console:
1. Visit a short link
2. Check browser console for:
- "Cache MISS - fetching from PocketBase"
- "Cache HIT! Redirecting from cache"
## Testing
### Run Test Suite
```bash
# Test local Redis connection
node test-local-redis.mjs
# Comprehensive cache test
node test-redis-cache.mjs
```
### Manual Testing
1. Create a short link in the app
2. Visit the link (first time = cache miss)
3. Visit again (second time = cache hit, faster)
4. Check `/api/redis-status` to see cached links count
## Configuration Options
### Cache TTL (Time To Live)
Edit `src/lib/server/linkCache.ts`:
```typescript
const CACHE_TTL = 86400; // 24 hours for popular links
const SHORT_TTL = 300; // 5 minutes for normal links
```
### Fallback Behavior
The app automatically handles Redis unavailability:
- If Redis is down, the app continues working without cache
- No errors shown to users
- Graceful degradation to database-only mode
## Troubleshooting
### Redis Won't Start
```bash
# Check if Redis is already running
ps aux | grep redis
# Check Redis service status
brew services list
# Restart Redis
brew services restart redis
# Check Redis logs
tail -f /opt/homebrew/var/log/redis.log
```
### Connection Refused
1. Verify Redis is running:
```bash
redis-cli ping
```
2. Check port availability:
```bash
lsof -i :6379
```
3. Ensure environment variables are set:
```bash
echo $REDIS_HOST
echo $REDIS_PORT
```
### Cache Not Working
1. Check Redis connection in app:
```bash
curl http://localhost:5173/api/redis-status
```
2. Verify Redis has memory available:
```bash
redis-cli info memory
```
3. Check for Redis errors in console output
### Performance Issues
1. Monitor Redis latency:
```bash
redis-cli --latency
```
2. Check Redis memory usage:
```bash
redis-cli info memory | grep used_memory_human
```
3. Clear old cache data:
```bash
redis-cli flushall
```
## Redis CLI Commands Reference
```bash
# Basic Commands
redis-cli ping # Test connection
redis-cli info # Server information
redis-cli monitor # Watch commands in real-time
redis-cli config get "*" # Show all configuration
# Key Operations
redis-cli keys "*" # List all keys (careful in production!)
redis-cli get key # Get value
redis-cli set key value # Set value
redis-cli del key # Delete key
redis-cli exists key # Check if key exists
redis-cli ttl key # Time to live in seconds
redis-cli expire key seconds # Set expiration
# Maintenance
redis-cli flushdb # Clear current database
redis-cli flushall # Clear all databases
redis-cli dbsize # Number of keys
redis-cli lastsave # Last save timestamp
# Performance
redis-cli --latency # Measure latency
redis-cli --latency-history # Latency over time
redis-cli slowlog get # Show slow queries
```
## Best Practices
1. **Don't Cache Sensitive Data**
- Password-protected links are never cached
- User-specific data has short TTLs
2. **Monitor Memory Usage**
- Redis uses in-memory storage
- Set appropriate max memory limits in production
3. **Use Appropriate TTLs**
- Short TTL for frequently changing data
- Long TTL for static content
4. **Handle Cache Invalidation**
- Clear cache when links are updated
- Implement cache warming for popular links
## Next Steps
- [Production Redis Setup](./redis-production-setup.md)
- [Cache Strategy Guide](./cache-strategy.md)
- [Performance Optimization](./performance.md)

View file

@ -0,0 +1,121 @@
# Redis Cache - Quick Start Guide
## 🚀 5-Minute Setup
### macOS/Linux
```bash
# 1. Install Redis
brew install redis
# 2. Start Redis
brew services start redis
# 3. Add to .env.development
echo "REDIS_HOST=localhost" >> .env.development
echo "REDIS_PORT=6379" >> .env.development
echo "REDIS_PASSWORD=" >> .env.development
# 4. Start app
npm run dev
# 5. Verify
curl http://localhost:5173/api/redis-status
```
### Windows (WSL2)
```bash
# 1. Install Redis in WSL2
sudo apt update
sudo apt install redis-server
# 2. Start Redis
sudo service redis-server start
# 3. Configure (same as macOS)
```
### Docker
```bash
# 1. Run Redis container
docker run -d -p 6379:6379 --name uload-redis redis:alpine
# 2. Configure (same as above)
```
## ✅ Verify It's Working
### Check Connection
```bash
# Should return: PONG
redis-cli ping
```
### Check App Status
Visit: http://localhost:5173/api/redis-status
Should see:
```json
{
"connected": true,
"available": true
}
```
### Test Cache Performance
1. Create a short link
2. Visit it (slow - cache miss)
3. Visit again (fast - cache hit!)
4. Check console for "Cache HIT!" message
## 🛠 Common Commands
```bash
# View all cached links
redis-cli keys "redirect:*"
# Clear cache
redis-cli flushall
# Monitor activity
redis-cli monitor
# Stop Redis
brew services stop redis
```
## 🔥 Quick Tips
1. **No Password Locally**: Leave REDIS_PASSWORD empty for local dev
2. **Auto-Fallback**: App works without Redis (just slower)
3. **Hot Reload**: Changes to Redis config need server restart
4. **Memory**: Redis uses ~50MB for thousands of links
## 📚 Learn More
- [Detailed Setup Guide](./redis-local-setup.md)
- [Architecture Overview](./redis-architecture.md)
- [Production Setup](./redis-production-setup.md)
## 🆘 Help
**Redis won't start?**
```bash
brew services restart redis
```
**Connection refused?**
```bash
# Check if running
ps aux | grep redis
```
**Cache not working?**
- Check console for Redis connection message
- Verify environment variables are loaded
- Try explicit env vars: `REDIS_HOST=localhost npm run dev`

View file

@ -0,0 +1,372 @@
# Referral & Attribution Tracking System für uload
## Executive Summary
Dieses Dokument beschreibt die Konzeption und Implementierungsstrategie eines umfassenden Referral- und Attribution-Tracking-Systems für die uload-Plattform. Das Ziel ist es, die komplette User Journey von einem geteilten Link über den App-Download bis hin zur zahlenden Kundschaft nachvollziehen zu können, während gleichzeitig höchste Datenschutzstandards gemäß DSGVO eingehalten werden.
## Problemstellung und Zielsetzung
### Aktuelle Herausforderung
Die uload-Plattform ermöglicht es Nutzern, verkürzte Links zu erstellen und zu teilen. Derzeit wird zwar das Klickverhalten auf diese Links getrackt (Browser, Gerät, Betriebssystem, Referer), jedoch endet die Nachverfolgung beim Klick. Es fehlt die Möglichkeit, die weitere User Journey zu verfolgen:
- Wer hat nach dem Klick tatsächlich die App heruntergeladen?
- Welche Nutzer haben sich nach dem Download registriert?
- Wer ist schließlich zahlender Kunde geworden?
- Welche Link-Ersteller generieren die wertvollsten Nutzer?
### Zielsetzung
Das neue System soll folgende Kernfunktionen bieten:
1. **Vollständige Attribution**: Nachverfolgung der User Journey vom ersten Klick bis zur Conversion
2. **Multi-Touch-Attribution**: Erfassung aller Berührungspunkte eines Nutzers mit verschiedenen Links
3. **Conversion-Tracking**: Messung von Downloads, Registrierungen und Käufen
4. **Performance-Analyse**: Identifikation der erfolgreichsten Link-Ersteller und Kampagnen
5. **DSGVO-Konformität**: Vollständige Einhaltung europäischer Datenschutzstandards
## Technische Herausforderungen
### Cross-Domain und Cross-Platform Tracking
Die größte technische Herausforderung besteht darin, Nutzer über verschiedene Domänen und Plattformen hinweg zu verfolgen:
1. **Domain-Wechsel**: Der Nutzer klickt auf ulo.ad, wird aber zur App-Download-Seite einer anderen Domain weitergeleitet
2. **Platform-Wechsel**: Vom Web-Browser zum App Store, dann zur nativen App
3. **Zeit-Verzögerung**: Zwischen Klick und App-Installation können Stunden oder Tage vergehen
4. **Gerätewechsel**: Nutzer klickt am Desktop, lädt aber die App am Smartphone herunter
### Datenschutzrechtliche Einschränkungen
Die DSGVO und moderne Browser-Technologien schaffen zusätzliche Hürden:
1. **Cookie-Beschränkungen**: Safari's Intelligent Tracking Prevention (ITP) und Firefox's Enhanced Tracking Protection blockieren Third-Party-Cookies
2. **Fingerprinting-Verbot**: Device Fingerprinting ist ohne explizite Einwilligung nicht DSGVO-konform
3. **Datensparsamkeit**: Nur notwendige Daten dürfen erhoben werden
4. **Transparenz**: Nutzer müssen über die Datenerhebung informiert werden
## Vergleich bestehender Lösungen
### Branch.io Ansatz
Branch.io nutzt eine Kombination aus verschiedenen Matching-Technologien:
**Deterministic Matching** (100% Genauigkeit):
- Verwendet eindeutige Identifikatoren wie IDFA (iOS) oder GAID (Android)
- Click-IDs in URL-Parametern
- Login-basiertes Matching über User-Accounts
**Probabilistic Matching** (70-90% Genauigkeit):
- Kombiniert IP-Adresse, User-Agent, Zeitstempel und Geräteinformationen
- Erstellt einen "Fingerprint" für wahrscheinliche Zuordnung
- Nutzt ein Zeitfenster von typischerweise 24-72 Stunden
**Deferred Deep Linking**:
- Speichert die Ziel-Information vor der App-Installation
- Nach Installation fragt die App den Branch-Server nach pending Deep Links
- Nutzer wird automatisch zum richtigen Inhalt in der App geleitet
### AppsFlyer/Adjust Methode
Diese Plattformen setzen auf:
**Server-to-Server Integration**:
- Direkte API-Kommunikation zwischen App-Backend und Attribution-Plattform
- Umgeht Browser-Restriktionen komplett
- Höhere Datenqualität durch serverseitige Validierung
**SKAdNetwork Integration** (iOS):
- Apples Privacy-freundliche Attribution-API
- Aggregierte Daten ohne Nutzer-Identifikation
- 24-48 Stunden Verzögerung in Reporting
**Multi-Touch Attribution Models**:
- First-Touch: Kredite gehen an ersten Touchpoint
- Last-Touch: Kredite gehen an letzten Touchpoint vor Conversion
- Linear: Gleichmäßige Verteilung auf alle Touchpoints
- Time-Decay: Neuere Touchpoints erhalten mehr Gewicht
### Limitierungen bestehender Lösungen
1. **Kosten**: Enterprise-Lösungen kosten oft 2000€+ pro Monat
2. **Komplexität**: Aufwendige Integration und Wartung erforderlich
3. **Datenschutz**: Nicht alle Ansätze sind DSGVO-konform
4. **Genauigkeit**: Probabilistic Matching erreicht nur 70-90% Genauigkeit
5. **Plattform-Abhängigkeiten**: iOS schränkt Tracking stark ein
## DSGVO-konforme Lösungsansätze
### Ansatz 1: Referral Code System
**Konzept**: Jeder Link-Ersteller erhält einen eindeutigen Referral-Code, der in der URL mitgegeben wird. Dieser Code wird durch die gesamte Journey hindurch weitergereicht.
**Funktionsweise**:
- Link-Ersteller teilt: `https://ulo.ad/download?ref=USER123`
- Code wird auf Download-Seite im LocalStorage gespeichert
- App liest Code beim ersten Start aus und meldet ihn zurück
- Keine personenbezogenen Daten des Endnutzers werden getrackt
**Vorteile**:
- 100% DSGVO-konform, da nur der Referrer getrackt wird
- 100% genaue Attribution möglich
- Keine Cookies oder Fingerprinting erforderlich
- Funktioniert plattformübergreifend
**Nachteile**:
- Erfordert aktive Weitergabe des Codes durch die App
- Kann bei App-Store-Downloads verloren gehen
- Keine Multi-Touch-Attribution möglich
### Ansatz 2: Session-basiertes Tracking mit Consent
**Konzept**: Temporäre Sessions mit kurzer Lebensdauer und anonymisierten Daten.
**Funktionsweise**:
- Bei Klick wird Session-ID generiert (30 Minuten Gültigkeit)
- Nur aggregierte Daten ohne Personenbezug werden gespeichert
- Täglicher Salt für Hashing verhindert langfristige Nachverfolgung
- Enhanced Tracking nur mit Legitimate Interest oder Consent
**Drei-Stufen-Modell**:
1. **Basis-Tracking** (ohne Consent):
- Aggregierte Metriken (Klicks pro Tag, Land, Gerätetyp)
- Gesaltete Hashes (ändern sich täglich)
- Keine persistenten Identifikatoren
2. **Analytics** (Legitimate Interest):
- Kurzzeitige Session-Cookies (max. 30 Minuten)
- Conversion-Tracking ohne Personenbezug
- Fraud-Detection
3. **Marketing** (explizites Opt-in):
- Vollständige User Journey
- Multi-Touch-Attribution
- Langzeit-Analyse
**Vorteile**:
- Flexibles Privacy-Modell
- Bessere Insights bei vorhandenem Consent
- Basis-Funktionalität ohne Einwilligung
**Nachteile**:
- Komplexere Implementierung
- Reduzierte Genauigkeit ohne Consent
- Consent-Banner kann Conversion beeinträchtigen
### Ansatz 3: Magic Link System
**Konzept**: Nutzer gibt E-Mail-Adresse ein und erhält personalisierten Download-Link.
**Funktionsweise**:
- Nutzer gibt E-Mail auf Landing Page ein
- System sendet Magic Link mit verschlüsseltem Token
- Token enthält Attribution-Informationen
- Nach Download kann Nutzer direkt zugeordnet werden
**Vorteile**:
- Explizite Einwilligung durch E-Mail-Eingabe
- 100% genaue Attribution
- Möglichkeit für Follow-up-Kommunikation
- DSGVO-konform mit Double-Opt-In
**Nachteile**:
- Zusätzlicher Schritt im Conversion-Funnel
- Nicht alle Nutzer wollen E-Mail angeben
- Verzögerung durch E-Mail-Versand
### Ansatz 4: Voucher/Promo-Code System
**Konzept**: Gamification-Ansatz mit manueller Code-Eingabe.
**Funktionsweise**:
- Jeder Link enthält prominenten Promo-Code
- Nutzer wird incentiviert, Code in App einzugeben
- Code aktiviert Vorteile (Rabatte, Features)
- Attribution erfolgt bei Code-Einlösung
**Vorteile**:
- Kein technisches Tracking erforderlich
- Nutzer hat volle Kontrolle
- Zusätzlicher Conversion-Anreiz
- 100% DSGVO-konform
**Nachteile**:
- Erfordert manuelle Aktion des Nutzers
- Nicht alle werden Code eingeben
- Zusätzliche Incentive-Kosten
## Empfohlene Implementierungsstrategie
### Phase 1: Quick Win mit Referral Codes (1 Woche)
**Ziel**: Schnelle Basis-Implementation ohne komplexe Infrastruktur
**Umsetzung**:
- Integration von Referral-Codes in bestehende Link-Struktur
- Weitergabe der Codes über URL-Parameter
- Einfaches Dashboard für Link-Ersteller
- Server-to-Server Webhook für App-Events
**Metriken**:
- Anzahl Klicks pro Referral-Code
- Conversions (Download, Registrierung, Kauf)
- Conversion-Rate pro Link-Ersteller
### Phase 2: Enhanced Analytics (1 Monat)
**Ziel**: Verbessertes Tracking mit Privacy-First-Ansatz
**Umsetzung**:
- Session-basiertes Tracking mit täglichem Salt
- Aggregierte Analytics ohne Personenbezug
- A/B-Testing verschiedener Attribution-Methoden
- Implementierung eines Consent-Banners für erweiterte Features
**Neue Features**:
- Conversion-Funnels
- Zeitbasierte Analysen
- Geografische Verteilung
- Device/Browser-Statistiken
### Phase 3: Multi-Touch Attribution (3 Monate)
**Ziel**: Vollständige Customer Journey Analyse
**Umsetzung**:
- Kombination mehrerer Tracking-Methoden
- Machine Learning für Probabilistic Matching
- Integration mit externen Analytics-Tools
- Advanced Reporting und Insights
**Erweiterte Funktionen**:
- Attribution-Modelle (First-Touch, Last-Touch, Linear)
- Kohorten-Analyse
- Lifetime-Value-Berechnung
- Predictive Analytics
### Phase 4: Enterprise Features (6 Monate)
**Ziel**: Professionelle Attribution-Plattform
**Umsetzung**:
- Fraud-Detection-System
- Real-Time Dashboards
- API für Drittanbieter-Integration
- White-Label-Lösungen für Großkunden
## Technische Architektur
### Datenmodell
**tracking_sessions**:
- Temporäre Sessions mit kurzer Lebensdauer
- Anonymisierte Nutzer-Identifikatoren
- Verknüpfung zu Links und Referrern
**conversion_events**:
- Event-Stream aller Conversions
- Attribution zu Sessions und Referral-Codes
- Zeitstempel und Event-Typen
**attribution_analytics**:
- Aggregierte Metriken
- Keine personenbezogenen Daten
- Optimiert für schnelle Abfragen
### API-Design
**Tracking-Endpoints**:
- POST /api/track/click - Initiale Klick-Erfassung
- POST /api/track/event - Event-Tracking (Download, Register, Purchase)
- GET /api/analytics/attribution - Attribution-Reports
**Webhook-System**:
- Empfang von App-Events
- Validierung und Zuordnung
- Asynchrone Verarbeitung
### Sicherheit und Datenschutz
**Datenschutz-Maßnahmen**:
- Verschlüsselung aller Daten in Transit und at Rest
- Automatische Datenlöschung nach definierten Zeiträumen
- Pseudonymisierung von Nutzer-Daten
- Audit-Logs für alle Datenzugriffe
**Compliance**:
- DSGVO-konforme Datenverarbeitung
- Privacy-by-Design-Prinzipien
- Transparente Datenschutzerklärung
- Nutzer-Rechte (Auskunft, Löschung, Portabilität)
## Metriken und KPIs
### Primäre Metriken
1. **Click-to-Install Rate**: Prozentsatz der Klicks, die zu App-Installationen führen
2. **Install-to-Registration Rate**: Prozentsatz der Installationen, die zu Registrierungen führen
3. **Registration-to-Purchase Rate**: Prozentsatz der Registrierungen, die zu Käufen führen
4. **Overall Conversion Rate**: End-to-End Conversion vom Klick zum zahlenden Kunden
### Sekundäre Metriken
1. **Time-to-Conversion**: Durchschnittliche Zeit von Klick zu Conversion
2. **Attribution-Window Performance**: Conversions nach Zeitfenstern
3. **Channel Performance**: Erfolg verschiedener Traffic-Quellen
4. **User Lifetime Value**: Langzeitwert der geworbenen Nutzer
### Qualitäts-Metriken
1. **Attribution Match Rate**: Prozentsatz erfolgreich zugeordneter Conversions
2. **False Positive Rate**: Fehlerhafte Zuordnungen
3. **Data Completeness**: Vollständigkeit der gesammelten Daten
4. **System Latency**: Verzögerung in der Datenverarbeitung
## Risiken und Mitigationsstrategien
### Technische Risiken
**Datenverlust bei Platform-Wechsel**:
- Mitigation: Redundante Tracking-Methoden, Fallback-Mechanismen
**Ungenauigkeit bei Probabilistic Matching**:
- Mitigation: Konservative Zuordnung, manuelle Validierung bei hochwertigen Conversions
**Skalierungsprobleme**:
- Mitigation: Event-Streaming-Architektur, horizontale Skalierung
### Rechtliche Risiken
**DSGVO-Verstöße**:
- Mitigation: Privacy-by-Design, regelmäßige Audits, Datenschutzbeauftragter
**Internationale Datenschutzgesetze**:
- Mitigation: Geo-basierte Compliance-Rules, lokale Datenspeicherung
### Geschäftliche Risiken
**Nutzer-Akzeptanz**:
- Mitigation: Transparente Kommunikation, Opt-in-Incentives
**Kosten-Nutzen-Verhältnis**:
- Mitigation: Phasenweise Einführung, kontinuierliche ROI-Messung
## Zusammenfassung und Ausblick
Das vorgeschlagene Referral- und Attribution-Tracking-System bietet uload die Möglichkeit, die komplette Customer Journey nachzuvollziehen und gleichzeitig höchste Datenschutzstandards einzuhalten. Durch die phasenweise Implementierung können schnelle Erfolge erzielt und das System kontinuierlich verbessert werden.
Die Kombination aus technischen Tracking-Methoden und nutzergesteuerten Elementen (wie Promo-Codes) schafft ein robustes System, das auch bei zunehmenden Privacy-Restriktionen funktionsfähig bleibt. Die vorgeschlagene Architektur ist skalierbar und kann mit dem Wachstum der Plattform mitwachsen.
Langfristig positioniert sich uload damit nicht nur als Link-Shortener, sondern als vollwertige Attribution-Plattform, die einen echten Mehrwert für Marketing-Teams und Content-Creator bietet. Dies eröffnet neue Monetarisierungsmöglichkeiten und stärkt die Wettbewerbsposition im Markt.
## Nächste Schritte
1. **Entscheidung über Implementierungsansatz**: Auswahl der initialen Tracking-Methode
2. **Technische Spezifikation**: Detaillierte Ausarbeitung der gewählten Lösung
3. **Datenschutz-Folgenabschätzung**: Formale DSGVO-Prüfung
4. **Proof of Concept**: Implementierung einer Minimal-Version
5. **Pilotphase**: Test mit ausgewählten Nutzern
6. **Rollout**: Schrittweise Einführung für alle Nutzer
Der Erfolg des Systems wird maßgeblich davon abhängen, wie gut es gelingt, die Balance zwischen Tracking-Genauigkeit und Datenschutz zu finden. Mit dem vorgeschlagenen mehrstufigen Ansatz ist uload bestens positioniert, um diese Herausforderung zu meistern und einen neuen Standard für datenschutzfreundliches Attribution-Tracking zu setzen.

View file

@ -0,0 +1,985 @@
# Detailvergleich: Automatisches Referral-Code-System vs. Manuelles Voucher/Promo-Code-System
## Einführung
Dieser Bericht vergleicht zwei grundlegend verschiedene Ansätze für Attribution-Tracking: das **automatische Referral-Code-System**, bei dem Tracking-Codes unsichtbar im Hintergrund mitgeführt werden, und das **manuelle Voucher/Promo-Code-System**, bei dem Nutzer aktiv Codes eingeben müssen, um Vorteile zu erhalten. Beide Systeme sind vollständig DSGVO-konform, unterscheiden sich jedoch fundamental in ihrer Philosophie, Nutzerpsychologie und Geschäftslogik.
## Grundlegende Philosophie beider Ansätze
### Automatisches Referral-Code-System: Die unsichtbare Hand
Das Referral-Code-System basiert auf dem Prinzip der **Reibungslosigkeit**. Es versucht, Attribution zu erreichen, ohne dass der Nutzer davon etwas mitbekommt. Die Philosophie dahinter ist, dass jede zusätzliche Nutzeraktion die Conversion-Rate senkt. Das System agiert wie ein unsichtbarer Begleiter, der Informationen über die Herkunft des Nutzers sammelt und weitergibt, ohne jemals in den Vordergrund zu treten.
### Manuelles Voucher/Promo-Code-System: Die bewusste Entscheidung
Das Voucher-System basiert auf dem gegenteiligen Prinzip der **bewussten Interaktion**. Es macht das Tracking zu einem Teil der User Experience und verwandelt es in einen Mehrwert. Die Philosophie hier ist, dass Nutzer, die aktiv einen Code eingeben, engagierter sind und eine stärkere Verbindung zum Produkt aufbauen. Das System nutzt psychologische Prinzipien wie Gamification, Exklusivität und Belohnung.
## Detaillierte Funktionsweise
### Automatisches Referral-Code-System
#### Der technische Ablauf im Detail
**Phase 1: Link-Generierung und Verteilung**
Wenn ein Content Creator oder Partner einen Link erstellt, wird automatisch ein eindeutiger Identifikator generiert und in die URL eingebettet. Dieser Prozess ist vollständig automatisiert:
- Der Referral-Code wird serverseitig generiert (z.B. `REF_USER123_CAMP456`)
- Er wird als URL-Parameter angehängt: `https://ulo.ad/download?ref=USER123`
- Alternative Einbettungen: Subdomain (`user123.ulo.ad`), Pfad (`ulo.ad/u/user123`)
**Phase 2: Code-Persistierung beim Klick**
Sobald ein Nutzer auf den Link klickt, beginnt die kritische Phase der Code-Persistierung:
1. **Browser-Storage-Hierarchie**: Das System versucht, den Code an mehreren Stellen zu speichern:
- LocalStorage (persistent, überlebt Browser-Neustart)
- SessionStorage (temporär, nur für aktuelle Sitzung)
- First-Party-Cookie (mit konfigurierbarer Lebensdauer)
- IndexedDB (für komplexere Datenstrukturen)
2. **Weiterleitungskette**: Bei jeder Weiterleitung wird der Code mitgeführt:
- Von der Landing Page zum App Store
- Über Zwischenseiten und Tracker
- Durch URL-Parameter oder HTTP-Header
3. **Fingerprint-Assoziation**: Optional kann ein Device-Fingerprint erstellt und mit dem Code assoziiert werden:
- Browser-Eigenschaften (User Agent, Sprache, Zeitzone)
- Screen-Eigenschaften (Auflösung, Farbtiefe)
- Installierte Plugins und Fonts
- Canvas/WebGL-Fingerprinting
**Phase 3: Cross-Platform-Übergang**
Der schwierigste Teil ist der Übergang vom Web zur App:
1. **Deep-Link-Integration**: Moderne App Stores unterstützen teilweise Deep Links:
- iOS: Universal Links mit Associated Domains
- Android: App Links mit Digital Asset Links
- Fallback: Custom URL Schemes
2. **Deferred Deep Linking**: Speicherung der Attribution für späteren Abruf:
- Server speichert Fingerprint → Referral-Code-Mapping
- App fragt beim ersten Start nach ausstehenden Attributions
- Matching über Zeitfenster und Wahrscheinlichkeit
3. **Browser-to-App-Kommunikation**: Verschiedene Techniken:
- Clipboard-API (Text in Zwischenablage)
- WebView-Bridge (JavaScript-Interface)
- QR-Code-Scanning (Code embedded im QR)
**Phase 4: Attribution-Vervollständigung**
Nach erfolgreicher App-Installation:
1. App sucht nach Referral-Code in verschiedenen Quellen
2. Gefundener Code wird an Backend gemeldet
3. Backend ordnet Conversion dem ursprünglichen Referrer zu
4. Analytics werden aktualisiert
#### Datenfluss und technische Architektur
**Frontend-Komponenten:**
```
Landing Page → JavaScript-Tracker → Storage APIs → Redirect Handler
```
**Backend-Komponenten:**
```
Link-Generator → Code-Database → Attribution-Engine → Analytics-Aggregator
```
**Datenstrukturen:**
- Referral-Codes: Key-Value-Store mit TTL
- Click-Events: Time-Series-Database
- Attributions: Relationale Datenbank
- Analytics: OLAP-Cube für schnelle Aggregationen
### Manuelles Voucher/Promo-Code-System
#### Der psychologische und technische Ablauf
**Phase 1: Code-Präsentation und Kommunikation**
Die Code-Präsentation ist entscheidend für den Erfolg:
1. **Visuelle Prominenz**: Der Code muss auffällig präsentiert werden:
- Große, lesbare Schriftart
- Kontrastierende Farben
- Animationen oder Highlights
- Copy-to-Clipboard-Button
2. **Wertversprechen**: Klare Kommunikation des Vorteils:
- "Spare 20% mit Code: SOMMER2024"
- "Exklusiver Zugang mit: VIP-ACCESS"
- "Erste 30 Tage gratis: TRIAL30"
- "Bonus-Features mit: PREMIUM-START"
3. **Multi-Channel-Präsenz**: Codes werden überall kommuniziert:
- Social Media Posts und Stories
- E-Mail-Signaturen
- Video-Overlays
- Podcast-Erwähnungen
- Physische Materialien (Flyer, Sticker)
**Phase 2: Nutzer-Journey mit Code**
Die Nutzer durchlaufen einen bewussten Prozess:
1. **Code-Entdeckung**: Nutzer sieht/hört Code
2. **Mentale Notiz**: Code wird bewusst wahrgenommen
3. **Motivation**: Vorteil motiviert zur Aktion
4. **Navigation**: Nutzer geht zur App/Website
5. **Code-Eingabe**: Aktive Eingabe des Codes
6. **Gratifikation**: Sofortige Belohnung/Feedback
**Phase 3: Code-Validierung und -Verarbeitung**
Das Backend-System muss robust und nutzerfreundlich sein:
1. **Eingabe-Normalisierung**:
- Case-insensitive Verarbeitung
- Entfernung von Leerzeichen und Sonderzeichen
- Ähnlichkeitsprüfung bei Tippfehlern
- Auto-Vervollständigung
2. **Validierungslogik**:
- Code-Existenz prüfen
- Gültigkeitszeitraum checken
- Verwendungslimits überprüfen
- Nutzer-Eligibility validieren
3. **Fehlerbehandlung**:
- Klare Fehlermeldungen ("Code abgelaufen", "Code bereits verwendet")
- Vorschläge bei ähnlichen Codes
- Support-Kontakt bei Problemen
**Phase 4: Belohnungsauslieferung und Tracking**
Nach erfolgreicher Validierung:
1. **Sofortige Gratifikation**:
- Visuelles Feedback (Konfetti-Animation, Success-Screen)
- Akustisches Feedback (Success-Sound)
- Textuelle Bestätigung
2. **Benefit-Aktivierung**:
- Rabatte werden angewendet
- Features werden freigeschaltet
- Bonusinhalte werden zugänglich
3. **Attribution-Recording**:
- Code-Verwendung wird geloggt
- Referrer wird gutgeschrieben
- Analytics werden aktualisiert
#### Gamification-Elemente und Psychologie
**Psychologische Trigger:**
1. **Verlustaversion**: "Nur noch 24 Stunden gültig!"
2. **Soziale Bewährtheit**: "Bereits 1.000x eingelöst"
3. **Exklusivität**: "Exklusiv für Follower"
4. **Reziprozität**: "Als Dankeschön für deine Treue"
5. **Commitment**: Aktive Eingabe verstärkt Bindung
**Gamification-Mechaniken:**
1. **Sammelbare Codes**: Serie von Codes für größere Belohnung
2. **Zeitlimitierte Codes**: Urgency durch Ablaufdatum
3. **Gestaffelte Belohnungen**: Bessere Codes für treue Nutzer
4. **Social Sharing**: Bonus für Weitergabe des Codes
5. **Achievement-System**: Badges für Code-Nutzung
## Vor- und Nachteile im Detail
### Automatisches Referral-Code-System
#### Vorteile
**1. Maximale Conversion-Rate**
Das größte Plus ist die Reibungslosigkeit. Studien zeigen, dass jeder zusätzliche Schritt im Conversion-Funnel zu einem Verlust von 10-30% der Nutzer führt. Das automatische System eliminiert diese Hürde komplett. Nutzer müssen:
- Nichts merken
- Nichts eingeben
- Keine zusätzliche Entscheidung treffen
**2. Universelle Anwendbarkeit**
Das System funktioniert überall:
- Bei impulsiven Käufen
- In Situationen mit wenig Zeit
- Für weniger technikaffine Nutzer
- Über alle Altersgruppen hinweg
**3. Skalierbarkeit ohne Limits**
- Keine Begrenzung bei Code-Anzahl
- Keine manuelle Verwaltung nötig
- Automatische Zuordnung
- Keine Support-Anfragen zu Codes
**4. Datenschutz-Einfachheit**
- Keine Nutzer-Interaktion = keine explizite Einwilligung nötig
- Rein technische Notwendigkeit
- Minimale Datenerhebung
**5. Technische Eleganz**
- Saubere, automatisierte Prozesse
- Weniger fehleranfällig
- Keine Tippfehler möglich
- Konsistente Attribution
#### Nachteile
**1. Fehlende Nutzer-Awareness**
Nutzer wissen nicht, dass sie getrackt werden:
- Keine bewusste Verbindung zum Referrer
- Keine Wertschätzung für den "Deal"
- Verpasste Marketing-Opportunity
**2. Technische Limitierungen**
- Browser-Restriktionen (ITP, ETP)
- Cookie-Blocker
- Private Browsing Modes
- Cross-Device-Probleme
**3. Attribution-Ungenauigkeiten**
- 60-80% Match-Rate typisch
- Probabilistic Matching unsicher
- Zeitfenster-Problematik
- False Positives möglich
**4. Keine Incentive-Möglichkeit**
- Kein direkter Nutzer-Vorteil
- Keine Gamification möglich
- Keine virale Mechanik
- Weniger Engagement
**5. Debugging-Schwierigkeiten**
- Schwer nachzuvollziehen, warum Attribution fehlschlägt
- Keine Nutzer-Rückmeldung
- Komplexe Fehlersuche
### Manuelles Voucher/Promo-Code-System
#### Vorteile
**1. Perfekte Attribution (nahezu 100%)**
Wenn ein Code eingegeben wird, ist die Zuordnung eindeutig:
- Keine technischen Unsicherheiten
- Keine False Positives
- Klare Kausalität
- Einfache Nachvollziehbarkeit
**2. Marketing-Multiplikator**
Codes sind selbst Marketing-Instrumente:
- Virales Potenzial durch Weitergabe
- Gesprächsthema in Communities
- Social-Media-Content
- Word-of-Mouth-Verstärker
**3. Nutzer-Engagement und -Bindung**
Die aktive Eingabe schafft Commitment:
- Bewusste Entscheidung für Produkt
- Positive Assoziation durch Belohnung
- Höhere Wertschätzung
- Stärkere Markenbindung
**4. Flexibilität und Kontrolle**
- Codes können jederzeit angepasst werden
- Verschiedene Vorteile für verschiedene Zielgruppen
- A/B-Testing von Incentives
- Saisonale Kampagnen
**5. Zusätzlicher Value-Layer**
- Codes als Produkt-Feature
- Differenzierung vom Wettbewerb
- Premium-Gefühl durch Exklusivität
- Community-Building-Tool
**6. Einfachheit und Transparenz**
- Keine komplexe Technik nötig
- DSGVO-unkritisch
- Nutzer verstehen das System
- Support kann einfach helfen
#### Nachteile
**1. Conversion-Friction**
Der größte Nachteil ist die zusätzliche Hürde:
- 20-40% niedrigere Conversion-Rate typisch
- Nutzer vergessen Codes
- Nutzer sind zu faul für Eingabe
- Mobile Eingabe umständlich
**2. Kognitive Belastung**
- Nutzer müssen sich Code merken
- Rechtschreibung muss stimmen
- Verwechslungsgefahr bei ähnlichen Codes
- Frustration bei Tippfehlern
**3. Verwaltungsaufwand**
- Codes müssen erstellt und verwaltet werden
- Gültigkeitszeiträume überwachen
- Missbrauch verhindern
- Support-Anfragen bearbeiten
**4. Kosten der Incentivierung**
- Rabatte schmälern Marge
- Features kosten Entwicklung
- Bonusinhalte müssen erstellt werden
- Kannibalisierung von Vollpreis-Verkäufen
**5. Betrugsanfälligkeit**
- Code-Sharing in Foren
- Automatisierte Code-Suche
- Mehrfachnutzung verhindern
- Fake-Accounts für Codes
## Psychologische und verhaltensökonomische Aspekte
### Die Psychologie des automatischen Trackings
**Unconscious Processing**
Das automatische System nutzt das Prinzip des "Unconscious Processing":
- Nutzer treffen Entscheidungen ohne bewusste Überlegung
- Reduzierte kognitive Last führt zu schnelleren Entscheidungen
- "System 1 Thinking" nach Kahneman
**Vorteile:**
- Höhere Spontankäufe
- Weniger Entscheidungsmüdigkeit
- Natürlicher Flow
**Nachteile:**
- Keine emotionale Verbindung
- Geringere Erinnerung
- Weniger Wertschätzung
### Die Psychologie der Code-Eingabe
**Active Participation Theory**
Die manuelle Code-Eingabe aktiviert mehrere psychologische Mechanismen:
1. **Effort Justification**: Menschen schätzen Dinge mehr, für die sie Aufwand betrieben haben
2. **Endowment Effect**: Der eingegebene Code wird als "eigener" Vorteil wahrgenommen
3. **Goal Gradient Effect**: Die Nähe zur Belohnung motiviert zur Vervollständigung
**Behavioral Patterns:**
1. **Code-Sammler**: Nutzer, die aktiv nach Codes suchen
2. **Deal-Hunter**: Preissensitive Nutzer mit hoher Motivation
3. **Brand-Advocates**: Nutzer, die Codes teilen und verbreiten
4. **Casual-User**: Gelegentliche Code-Nutzer bei Gelegenheit
## Anwendungsszenarien und optimale Einsatzgebiete
### Wann das automatische Referral-System optimal ist
**1. Niedrigpreisige Impulskäufe**
Bei Apps oder Services unter 10€ ist jede Hürde fatal:
- Casual Games
- Utility-Apps
- Content-Subscriptions
- Micro-Transactions
**Beispiel:** Eine Foto-Filter-App für 2,99€. Hier würde ein Promo-Code die Conversion drastisch senken.
**2. Zeitkritische Aktionen**
Wenn Nutzer schnell handeln müssen:
- Flash Sales
- Live-Events
- Breaking News Apps
- Trading-Plattformen
**Beispiel:** Eine Sport-Streaming-App während einem wichtigen Spiel.
**3. Technisch weniger versierte Zielgruppen**
Für Nutzer, die mit Code-Eingabe überfordert wären:
- Senioren-Apps
- Kinder-Produkte (Eltern als Käufer)
- Mainstream-Utility-Apps
**4. Hochvolumige Virale Kampagnen**
Wenn Masse über Qualität geht:
- Social-Media-Challenges
- Influencer-Kampagnen mit Millionen-Reichweite
- Viral-Marketing-Stunts
### Wann das Voucher-System optimal ist
**1. Premium-Produkte und Services**
Bei höheren Preispunkten ist die Extra-Motivation wertvoll:
- B2B-Software
- Premium-Subscriptions (>20€/Monat)
- Online-Kurse
- Professional Tools
**Beispiel:** Ein Projektmanagement-Tool für 50€/Monat mit 3-Monats-Rabatt.
**2. Community-getriebene Produkte**
Wenn Codes Teil der Community-Kultur werden:
- Gaming-Communities
- Fitness-Apps mit Gruppen
- Lern-Plattformen
- Creator-Tools
**Beispiel:** Ein Fitness-Tracker, wo Influencer ihre Community-Codes teilen.
**3. Saisonale und Event-basierte Kampagnen**
Codes passen perfekt zu zeitlichen Events:
- Black Friday (BLACK2024)
- Weihnachten (XMAS-DEAL)
- Produktlaunches (LAUNCH50)
- Jubiläen (5YEARS)
**4. Partnership und Kooperationen**
Codes sind ideal für Partnerschaften:
- Corporate Benefits
- Influencer-Kooperationen
- Cross-Promotions
- Affiliate-Programme
## Technische Implementierung im Detail
### Automatisches Referral-System: Architektur
**Frontend-Layer:**
1. **JavaScript-Tracker**: Lightweight Script (< 5KB)
- Event-Listener für Klicks
- Storage-Management
- Fingerprinting-Logik
2. **Storage-Strategie**: Redundante Speicherung
- LocalStorage als Primary
- Cookie als Fallback
- URL-Parameter als Backup
3. **Communication-Layer**:
- Beacon-API für Analytics
- Fetch für Attribution-Events
- WebSocket für Real-Time
**Backend-Layer:**
1. **Link-Service**: Microservice für Link-Management
- URL-Shortening
- Code-Generation
- Redirect-Handling
2. **Attribution-Engine**: Core-Attribution-Logic
- Fingerprint-Matching
- Probabilistic Attribution
- Rule-Engine
3. **Analytics-Pipeline**:
- Event-Stream-Processing
- Real-Time-Aggregation
- Batch-Processing für Reports
**Datenbank-Design:**
```
referral_codes:
- code_id (UUID)
- creator_id (User-Reference)
- campaign_id (Optional)
- created_at
- expires_at
- metadata (JSON)
attribution_events:
- event_id (UUID)
- code_id (Reference)
- event_type (click|install|purchase)
- timestamp
- confidence_score (0-100)
- attribution_method (deterministic|probabilistic)
```
### Voucher-System: Architektur
**Frontend-Layer:**
1. **Code-Input-Component**: User-Interface
- Auto-Complete
- Format-Validation
- Error-Handling
- Success-Animations
2. **Code-Display-Widgets**: Marketing-Components
- Banner-Generator
- QR-Code-Creator
- Share-Buttons
- Copy-Functions
**Backend-Layer:**
1. **Code-Management-Service**:
- CRUD-Operations
- Batch-Generation
- Import/Export
- Validation-Rules
2. **Redemption-Engine**:
- Real-Time-Validation
- Fraud-Detection
- Rate-Limiting
- Usage-Tracking
3. **Benefit-Processor**:
- Discount-Calculation
- Feature-Unlocking
- Notification-System
**Datenbank-Design:**
```
promo_codes:
- code_id (UUID)
- code_string (UNIQUE, Indexed)
- type (discount|feature|trial)
- value (JSON - abhängig von type)
- creator_id
- valid_from
- valid_until
- max_uses
- current_uses
code_redemptions:
- redemption_id (UUID)
- code_id
- user_id
- redeemed_at
- ip_address
- device_info
- granted_benefit (JSON)
```
## Hybride Ansätze und innovative Kombinationen
### Der "Best of Both Worlds" Ansatz
**Konzept: Optionaler Code-Layer**
Eine elegante Lösung kombiniert beide Systeme:
1. **Basis-Layer**: Automatisches Tracking läuft immer im Hintergrund
2. **Bonus-Layer**: Optionale Code-Eingabe für zusätzliche Vorteile
**Beispiel-Flow:**
- Nutzer klickt Link → Automatisches Tracking aktiv
- Landing-Page zeigt: "Bonus-Code für Extra-Vorteile: SPECIAL20"
- Nutzer kann ignorieren → Normale Conversion mit Attribution
- Oder Code eingeben → Extra-Vorteile + verstärkte Attribution
**Vorteile:**
- Basis-Attribution immer gesichert
- Zusätzliche Motivation durch Codes
- Selbst-Selektion von engaged Users
- Doppelte Validierung möglich
### Der "Progressive Disclosure" Ansatz
**Konzept: Codes werden schrittweise wichtiger**
1. **Phase 1**: Start ohne Codes, nur automatisches Tracking
2. **Phase 2**: Codes als optionale Bonus-Features
3. **Phase 3**: Premium-Features nur mit Codes
4. **Phase 4**: Gamification-System rund um Codes
Dies erlaubt organisches Wachstum der Code-Kultur.
### Der "Smart Code" Ansatz
**Konzept: Intelligente, kontextabhängige Codes**
Codes, die sich adaptiv verhalten:
- Gleicher Code, unterschiedliche Vorteile je nach Kontext
- Zeit-basierte Vorteile (morgens anders als abends)
- Geo-basierte Anpassungen
- User-History-abhängige Benefits
**Beispiel:**
Code "SMART2024" gibt:
- Neue Nutzer: 50% Rabatt ersten Monat
- Bestehende Nutzer: Extra-Features
- Premium-Nutzer: Gratis-Monat für Freund
## Metriken und Erfolgsmessung
### KPIs für automatisches Referral-System
**Primäre Metriken:**
1. **Attribution Rate**: Prozentsatz erfolgreich zugeordneter Conversions
- Benchmark: 60-80% für Web-to-App
- Ziel: >70%
2. **Attribution Confidence**: Sicherheit der Zuordnung
- Deterministic: 100% sicher
- Probabilistic High: 80-99% sicher
- Probabilistic Low: 50-79% sicher
3. **Time-to-Attribution**: Zeit von Klick zu Conversion
- Immediate: <1 Stunde
- Same-Day: 1-24 Stunden
- Multi-Day: >24 Stunden
**Sekundäre Metriken:**
1. **Code-Persistenz**: Wie lange bleiben Codes erhalten
2. **Cross-Device-Success**: Erfolgsrate über Geräte hinweg
3. **False-Positive-Rate**: Fehlerhafte Zuordnungen
4. **Technical-Failure-Rate**: Technische Ausfälle
### KPIs für Voucher-System
**Primäre Metriken:**
1. **Code-Redemption-Rate**: Prozentsatz eingelöster Codes
- Benchmark: 10-30% je nach Incentive
- Ziel: >20%
2. **Code-Viral-Coefficient**: Wie oft werden Codes geteilt
- Organische Weitergabe
- Social-Media-Shares
- Word-of-Mouth-Multiplikator
3. **Incentive-ROI**: Return on Investment der Rabatte
- Kosten der Rabatte vs. zusätzlicher Umsatz
- Lifetime-Value mit/ohne Code
- Kannibalisierungsrate
**Sekundäre Metriken:**
1. **Code-Entry-Errors**: Fehlerrate bei Eingabe
2. **Support-Tickets**: Anzahl Code-bezogener Anfragen
3. **Code-Fraud-Rate**: Missbrauchsversuche
4. **Time-to-Redemption**: Zeit von Code-Sichtung zu Eingabe
### Vergleichende Metriken
| Metrik | Automatisches System | Voucher-System |
|--------|---------------------|----------------|
| **Setup-Komplexität** | Hoch (Technik) | Niedrig (Business) |
| **Attribution-Genauigkeit** | 60-80% | 95-100% |
| **Conversion-Rate-Impact** | 0% (neutral) | -20 bis -40% |
| **Nutzer-Engagement** | Niedrig | Hoch |
| **Viral-Potenzial** | Niedrig | Hoch |
| **Wartungsaufwand** | Niedrig | Mittel |
| **Skalierbarkeit** | Exzellent | Gut |
| **Kosten pro Conversion** | Niedrig | Mittel-Hoch |
## Reale Fallstudien und Learnings
### Fallstudie 1: Gaming-App mit automatischem Tracking
**Ausgangslage:**
- Casual Mobile Game, Free-to-Play
- Zielgruppe: 18-35 Jahre
- Monetarisierung durch In-App-Käufe
**Implementation:**
- Automatisches Referral-Tracking
- Keine Promo-Codes initially
**Ergebnisse:**
- 73% Attribution-Rate
- 2.3x höhere Install-Rate vs. Promo-Codes
- Aber: 40% niedrigerer Lifetime-Value
**Learning:**
Automatisches Tracking maximiert Volume, aber Qualität leidet.
### Fallstudie 2: Fitness-App mit Voucher-System
**Ausgangslage:**
- Premium Fitness-App, 19,99€/Monat
- Zielgruppe: 25-45 Jahre, gesundheitsbewusst
- Influencer-Marketing-Fokus
**Implementation:**
- Personalisierte Influencer-Codes
- 30% Rabatt für 3 Monate
**Ergebnisse:**
- 98% Attribution-Genauigkeit
- 24% Redemption-Rate
- 3.2x höherer LTV vs. organische Nutzer
- Starke Community-Bildung
**Learning:**
Codes schaffen Commitment und Community.
### Fallstudie 3: B2B-SaaS mit Hybrid-Modell
**Ausgangslage:**
- Projektmanagement-Tool
- 50-500€/Monat je nach Plan
- Lange Sales-Cycles
**Implementation:**
- Automatisches Tracking für Trial-Signups
- Voucher-Codes für Paid-Conversions
**Ergebnisse:**
- 89% Combined Attribution
- 45% höhere Trial-to-Paid-Rate mit Codes
- Vereinfachtes Partner-Programm
**Learning:**
Hybrid-Modelle können das Beste aus beiden Welten vereinen.
## Kosten-Nutzen-Analyse
### Automatisches Referral-System
**Einmalige Kosten:**
- Entwicklung: 15.000-30.000€
- Testing: 3.000-5.000€
- Integration: 5.000-10.000€
- **Gesamt: 23.000-45.000€**
**Laufende Kosten (monatlich):**
- Server/Infrastructure: 200-1.000€
- Maintenance: 500-1.000€
- Monitoring: 100-300€
- **Gesamt: 800-2.300€/Monat**
**ROI-Berechnung:**
Bei 10.000 Conversions/Monat und 70% Attribution:
- 7.000 zugeordnete Conversions
- Bei 10€ Provision: 70.000€ korrekt zugeordnet
- ROI-Breakeven: 1-2 Monate
### Voucher-System
**Einmalige Kosten:**
- Entwicklung: 8.000-15.000€
- Design/UX: 3.000-5.000€
- Integration: 2.000-5.000€
- **Gesamt: 13.000-25.000€**
**Laufende Kosten (monatlich):**
- Rabatte/Incentives: 5-30% des Umsatzes
- Code-Management: 300-500€
- Support: 500-1.500€
- Fraud-Prevention: 200-500€
- **Gesamt: 1.000-2.500€ + Rabatte**
**ROI-Berechnung:**
Bei 10.000 Sichtkontakten und 20% Redemption:
- 2.000 Code-Nutzer
- Bei 30% höherem LTV (+20€): 40.000€ Mehrwert
- Minus 20% Rabattkosten: 32.000€ Netto
- ROI-Breakeven: 2-3 Monate
## Zukunftstrends und Entwicklungen
### Technologische Entwicklungen
**Für automatisches Tracking:**
1. **Privacy-Sandbox (Google)**: Neue Attribution-APIs
- Aggregated Reporting API
- Attribution Reporting API
- Impact: Könnte Genauigkeit verbessern
2. **SKAdNetwork 5.0 (Apple)**: Erweiterte Attribution
- Multiple Conversion-Windows
- Re-Engagement-Attribution
- Impact: Bessere iOS-Attribution
3. **Server-Side-Tracking**: Trend weg vom Client
- Höhere Zuverlässigkeit
- Umgehung von Blockern
- Impact: Renaissance des automatischen Trackings
**Für Voucher-Systeme:**
1. **AI-generierte Codes**: Personalisierte Code-Generation
- Individuelle Codes per ML
- Optimierte Incentive-Höhe
- Impact: Höhere Redemption-Rates
2. **Voice-Commerce**: Codes per Spracheingabe
- Alexa/Siri-Integration
- Vereinfachte Eingabe
- Impact: Reduzierte Friction
3. **Blockchain-Vouchers**: NFT-basierte Codes
- Handelbare Vouchers
- Transparente Attribution
- Impact: Neue Geschäftsmodelle
### Markt- und Nutzertrends
**Verändertes Nutzerverhalten:**
1. **Privacy-Awareness**: Nutzer wollen Kontrolle
- Vorteil für transparente Voucher-Systeme
- Herausforderung für verstecktes Tracking
2. **Deal-Culture**: Rabatt-Erwartungshaltung
- Codes werden zur Normalität
- Ohne Code kein Kauf
3. **Social Commerce**: Shopping als soziales Erlebnis
- Codes als Social Currency
- Gruppen-Deals und Sharing
**Regulatorische Entwicklungen:**
1. **Strengere Datenschutzgesetze**
- Vorteil für Voucher-Systeme
- Mehr Compliance-Aufwand für Tracking
2. **Platform-Policies**
- App-Store-Regeln zu Tracking
- Einschränkungen für Incentives
## Entscheidungsframework
### Entscheidungsmatrix
| Faktor | Gewicht | Automatisch | Voucher |
|--------|---------|-------------|----------|
| **Technische Komplexität** | 15% | 3/10 | 8/10 |
| **Attribution-Genauigkeit** | 20% | 7/10 | 10/10 |
| **Conversion-Rate** | 25% | 10/10 | 6/10 |
| **Nutzer-Engagement** | 15% | 3/10 | 9/10 |
| **Skalierbarkeit** | 10% | 10/10 | 7/10 |
| **DSGVO-Compliance** | 10% | 10/10 | 10/10 |
| **Kosten** | 5% | 8/10 | 5/10 |
| **Gewichteter Score** | 100% | **7.5/10** | **7.8/10** |
### Entscheidungsbaum
```
Start: Was ist das primäre Ziel?
├─> Maximale Reichweite/Volume?
│ └─> Budget < 20k?
│ ├─> JA: Voucher-System
│ └─> NEIN: Automatisches System
├─> Maximale Attribution-Genauigkeit?
│ └─> Voucher-System
├─> Premium-Positionierung?
│ └─> Nutzer B2B?
│ ├─> JA: Voucher-System
│ └─> NEIN: Hybrid-Ansatz
└─> Virales Wachstum?
└─> Zielgruppe < 25 Jahre?
├─> JA: Voucher mit Gamification
└─> NEIN: Automatisches System
```
## Finale Empfehlung für uload
### Kurzfristige Strategie (3 Monate)
**Start mit Voucher-System für schnelle Validierung:**
**Begründung:**
1. **Geringere technische Komplexität** ermöglicht schnelleren Start
2. **100% Attribution** liefert klare Daten für Investoren/Partner
3. **Marketing-Story** ("Exklusive Codes für Early Adopters")
4. **Community-Building** von Anfang an
5. **Flexibilität** für Experimente mit Incentive-Höhen
**Konkrete Umsetzung:**
- Einfache Code-Struktur: CREATOR-KAMPAGNE (z.B. PETER-LAUNCH)
- Initial hohe Incentives (30-50%) für Momentum
- Fokus auf Influencer und Early Adopters
- Klare Kommunikation des Mehrwerts
### Mittelfristige Strategie (3-12 Monate)
**Migration zu Hybrid-System:**
**Phase 1:** Voucher-System optimieren
- A/B-Tests verschiedener Incentive-Höhen
- Optimierung der Code-Präsentation
- Aufbau einer Code-Kultur in der Community
**Phase 2:** Automatisches Tracking ergänzen
- Parallelbetrieb beider Systeme
- Vouchers als Premium-Option
- Automatisches Tracking als Fallback
**Phase 3:** Datengetriebene Optimierung
- Analyse welches System für welche Zielgruppe funktioniert
- Segmentierung der Ansätze nach Kampagnen-Typ
- Machine Learning für optimale System-Auswahl
### Langfristige Vision (12+ Monate)
**Intelligentes Attribution-Ecosystem:**
Ein System, das kontextabhängig entscheidet:
- **AI-gesteuerte Methodenwahl**: Automatische Auswahl basierend auf User-Signals
- **Progressive Enhancement**: Start simpel, wird sophistizierter mit User-Reife
- **Multi-Touch-Attribution**: Kombination beider Methoden für vollständiges Bild
- **Blockchain-Integration**: Transparente, unveränderliche Attribution-Chain
## Zusammenfassung
Die Entscheidung zwischen automatischem Referral-Tracking und manuellem Voucher-System ist keine binäre Wahl zwischen "richtig" und "falsch", sondern eine strategische Entscheidung basierend auf:
1. **Geschäftsziele**: Volume vs. Qualität
2. **Zielgruppe**: Tech-Affinität und Engagement-Level
3. **Ressourcen**: Technische vs. Marketing-Ressourcen
4. **Zeithorizont**: Quick-Win vs. langfristige Optimierung
5. **Marktpositionierung**: Discount-Brand vs. Premium-Brand
**Für uload spezifisch empfehle ich:**
**Start mit Voucher-System**, weil:
- Schnellere Time-to-Market
- Perfekte Attribution für Investor-Demos
- Community-Building-Potenzial
- Geringeres technisches Risiko
**Evolution zum Hybrid-System**, weil:
- Best of Both Worlds
- Maximale Flexibilität
- Datengetriebene Optimierung möglich
- Zukunftssicherheit
Die Voucher-Codes sollten nicht als technische Limitation gesehen werden, sondern als Feature, das die Marke stärkt und eine engagierte Community aufbaut. Der kurzfristige Conversion-Verlust wird durch höhere Nutzer-Qualität und bessere Attribution mehr als kompensiert.
Langfristig wird die Kombination beider Ansätze uload ermöglichen, verschiedene Nutzer-Segmente optimal anzusprechen und dabei sowohl Wachstum als auch Profitabilität zu maximieren.

View file

@ -0,0 +1,851 @@
# Das Voucher-Code-System: Motor für Community-Building und Affiliate Marketing
## Einführung: Warum Voucher-Codes mehr sind als nur Tracking
Voucher-Codes sind auf den ersten Blick simple Rabattcodes - doch bei genauerer Betrachtung offenbaren sie sich als mächtige Werkzeuge für Community-Building, virales Marketing und nachhaltige Geschäftsentwicklung. Für uload bieten sie die perfekte Balance zwischen technischer Einfachheit, DSGVO-Konformität und Marketing-Potenzial. Dieser Bericht zeigt, wie ein durchdachtes Voucher-System zur Grundlage eines florierenden Ökosystems werden kann.
## Die Psychologie hinter erfolgreichen Voucher-Systemen
### Das Prinzip der sozialen Währung
Voucher-Codes funktionieren als **soziale Währung**. Menschen teilen Codes nicht nur, um anderen einen Gefallen zu tun, sondern auch, um ihren eigenen sozialen Status zu erhöhen. "Ich habe einen exklusiven Code für dich" ist eine Form von sozialem Kapital. Der Teilende positioniert sich als Insider, als jemand mit Zugang zu besonderen Vorteilen.
Diese Dynamik ist besonders stark, wenn:
- Codes limitiert oder exklusiv sind
- Der Teilende selbst einen Vorteil erhält (Win-Win)
- Die Codes personalisiert sind (PETERS-SPECIAL vs. GENERIC123)
- Eine Geschichte oder Kontext mitgeliefert wird
### Die Macht der Reziprozität
Robert Cialdini's Prinzip der Reziprozität besagt, dass Menschen sich verpflichtet fühlen, Gefälligkeiten zu erwidern. Ein Voucher-Code aktiviert diesen Mechanismus gleich dreifach:
1. **Creator zu Follower**: "Ich gebe dir einen Rabatt"
2. **Follower zu Creator**: "Ich nutze deinen Code" (Social Proof)
3. **Follower zu Follower**: "Ich teile diesen tollen Code weiter"
Diese Reziprozitätskette schafft ein sich selbst verstärkendes System.
### Gamification und Sammelverhalten
Menschen sind natürliche Sammler. Voucher-Codes können diesen Trieb nutzen:
- **Sammlung verschiedener Codes** für verschiedene Vorteile
- **Zeitlimitierte Codes** erzeugen Urgency
- **Achievement-Systeme** ("10 Codes genutzt = VIP Status")
- **Kombinierbare Codes** für größere Belohnungen
Das Eingeben eines Codes wird zur bewussten, befriedigenden Handlung - wie das Einlösen eines Gutscheins oder das Freischalten eines Achievement in einem Spiel.
## Community-Building durch Voucher-Codes
### Codes als Identitätsstifter
Voucher-Codes können zu einem integralen Teil der Community-Identität werden. Beispiele aus erfolgreichen Communities:
**Gaming-Communities:**
- Streamer haben eigene Codes, die zur "Crew" dazugehören
- Codes werden in Chat-Nachrichten wie Insider-Witze verwendet
- "Bist du Team NINJA oder Team VIKING?" (verschiedene Creator-Codes)
**Fitness-Communities:**
- Trainer-spezifische Codes schaffen Zugehörigkeit
- "Train with Team ALEX20" wird zum Motto
- Challenges verbunden mit speziellen Event-Codes
**Bildungs-Communities:**
- Dozenten-Codes für ihre Studenten
- Kurs-spezifische Codes für Lerngruppen
- Alumni-Codes als dauerhafter Benefit
### Hierarchien und Exklusivität
Ein gestaffeltes Code-System schafft natürliche Community-Hierarchien:
**Öffentliche Ebene:**
- Allgemeine Codes mit kleinen Rabatten (10%)
- Für jeden zugänglich
- Einstieg in die Community
**Member-Ebene:**
- Bessere Codes für registrierte Community-Mitglieder (20%)
- Erfordert Anmeldung/Engagement
- Gefühl der Zugehörigkeit
**VIP-Ebene:**
- Exklusive Codes für Top-Contributors (30-50%)
- Früher Zugang zu neuen Features
- Status-Symbol in der Community
**Inner Circle:**
- Persönliche Codes für engste Supporter
- Unlimited Benefits
- Co-Creation Möglichkeiten
### Community-Events und Kampagnen
Voucher-Codes sind perfekte Katalysatoren für Community-Events:
**Flash-Mobs und Challenges:**
- "Die ersten 100, die Code FLASH24 nutzen..."
- Zeitlich begrenzte Community-Aktionen
- Gemeinsame Ziele ("10.000 Code-Nutzungen = Feature X für alle")
**Seasonal Campaigns:**
- Weihnachts-Codes als Geschenk-Tradition
- Geburtstags-Codes für Community-Jubiläen
- Back-to-School Codes für Bildungs-Apps
**Collaborative Unlocks:**
- Codes, die erst ab X Nutzungen aktiviert werden
- Community muss zusammenarbeiten
- Geteilter Erfolg stärkt Zusammenhalt
## Das perfekte Affiliate-Marketing-System
### Warum Voucher-Codes ideal für Affiliates sind
**Transparenz und Vertrauen:**
Affiliates sehen in Echtzeit:
- Wie oft ihr Code genutzt wurde
- Welche Conversions daraus resultierten
- Ihre exakte Provision
Diese Transparenz schafft Vertrauen und motiviert zu mehr Engagement. Im Gegensatz zu obskuren Tracking-Pixeln ist ein Code greifbar und nachvollziehbar.
**Einfachheit der Integration:**
Affiliates müssen:
- Keine komplexen Tracking-Links generieren
- Keine technischen Integrationen vornehmen
- Keine Cookies oder Pixel einbauen
Ein einfacher Code reicht. Das senkt die Einstiegshürde dramatisch.
**Flexibilität in der Vermarktung:**
Codes funktionieren überall:
- Social Media Posts und Stories
- YouTube-Video-Beschreibungen
- Podcast-Erwähnungen
- E-Mail-Newsletter
- WhatsApp-Gruppen
- Offline-Events
### Strukturierung eines Affiliate-Programms
**Tier 1: Micro-Influencer (100-1.000 Follower)**
- Persönlicher Code: NAME20
- Benefit für Nutzer: 20% Rabatt
- Provision: 15% auf Lifetime des Kunden
- Minimum: Keine Anforderungen
- Support: Self-Service Dashboard
**Tier 2: Mid-Tier Influencer (1.000-10.000 Follower)**
- Custom Code nach Wahl
- Benefit für Nutzer: 25% Rabatt
- Provision: 20% auf Lifetime
- Minimum: 10 Conversions/Monat
- Support: Monatliche Check-ins
**Tier 3: Macro-Influencer (10.000+ Follower)**
- Multiple Codes für verschiedene Kampagnen
- Benefit für Nutzer: 30% Rabatt + Extras
- Provision: 25% auf Lifetime
- Minimum: 50 Conversions/Monat
- Support: Dedicated Account Manager
**Tier 4: Strategic Partners**
- White-Label-Codes
- Custom Benefits
- Provision: Individual verhandelt
- Co-Marketing-Aktivitäten
- Support: Partnership Team
### Performance-Optimierung für Affiliates
**A/B-Testing von Codes:**
Affiliates können verschiedene Codes testen:
- SAVE20 vs. DISCOUNT20 vs. DEAL20
- Verschiedene Rabatthöhen
- Zeitlimitierte vs. dauerhafte Codes
- Feature-Unlocks vs. Preis-Rabatte
**Saisonale und Event-Codes:**
Spezielle Codes für maximale Conversion:
- BLACK50 für Black Friday
- SUMMER30 für Sommerferien
- NEWYEAR für Neujahrsvorsätze
- TAXDAY für Steuersoftware
**Personalisierte Landing Pages:**
Jeder Code führt zu angepasster Experience:
- Begrüßung mit Affiliate-Namen
- Angepasste Value Proposition
- Social Proof des Affiliates
- Direkter Support-Kontakt
## Technische Implementierung eines robusten Voucher-Systems
### Code-Generierung und -Struktur
**Intelligente Code-Patterns:**
Die Struktur der Codes sollte sowohl menschenfreundlich als auch systemoptimiert sein:
**Format-Optionen:**
1. **Personalisiert-einfach**: PETER, SARAH, TECH
2. **Personalisiert-komplex**: PETER2024, SARAH-APP
3. **Kampagnen-basiert**: LAUNCH50, SUMMER30
4. **Hybrid**: PETER-LAUNCH, SARAH-VIP
**Generierungs-Strategien:**
**Manuelle Generierung** für VIP-Partner:
- Persönliche Abstimmung
- Wunsch-Codes möglich
- Marken-Alignment
**Semi-automatisch** für reguläre Affiliates:
- Template-basiert: {NAME}-{CAMPAIGN}
- Validierung gegen Blacklist
- Eindeutigkeitsprüfung
**Voll-automatisch** für Massen-Kampagnen:
- Algorithmus-generiert
- Collision-Vermeidung
- Batch-Generierung
### Validierung und Sicherheit
**Multi-Layer-Validierung:**
1. **Format-Validierung**: Entspricht der Code dem erwarteten Pattern?
2. **Existenz-Prüfung**: Gibt es diesen Code im System?
3. **Zeitliche-Validierung**: Ist der Code noch gültig?
4. **Nutzer-Eligibility**: Darf dieser Nutzer den Code verwenden?
5. **Usage-Limits**: Wurde das Maximum erreicht?
6. **Fraud-Detection**: Ungewöhnliche Nutzungsmuster?
**Sicherheitsmaßnahmen:**
**Rate-Limiting:**
- Max. 5 Code-Versuche pro Minute
- IP-basierte Beschränkungen
- Device-Fingerprinting
**Fraud-Prevention:**
- Velocity-Checks (zu viele Nutzungen zu schnell)
- Geo-Blocking (Codes nur in bestimmten Ländern)
- Device-Limits (ein Code pro Gerät)
- Referrer-Validation
**Abuse-Handling:**
- Automatische Code-Deaktivierung bei Missbrauch
- Blacklisting von Nutzern/IPs
- Alert-System für Anomalien
### Dashboard und Analytics
**Affiliate-Dashboard Features:**
**Real-Time Metrics:**
- Live-Counter für Code-Nutzungen
- Conversion-Funnel-Visualisierung
- Earnings-Ticker
- Trend-Analysen
**Performance-Insights:**
- Beste Tageszeiten für Conversions
- Geo-Performance
- Device-Breakdown
- Vergleich mit Peer-Group
**Optimization-Tools:**
- A/B-Test-Results
- Suggested Improvements
- Best-Practice-Tipps
- Success Stories
**Admin-Dashboard Features:**
**Code-Management:**
- Bulk-Creation und -Editing
- Regelbasierte Automation
- Quick-Actions (Pause, Extend, Modify)
- Template-Library
**Affiliate-Management:**
- Performance-Rankings
- Automatic Tier-Upgrades
- Commission-Berechnungen
- Auszahlungs-Management
**Business Intelligence:**
- Customer-Lifetime-Value nach Code
- Churn-Rate nach Acquisition-Channel
- ROI-Berechnungen
- Forecasting-Modelle
## Marketing-Strategien mit Voucher-Codes
### Content-Marketing Integration
**Blog-Posts und Artikel:**
"Die 10 besten Promo-Codes für [Produkt] im November 2024"
- SEO-optimiert für Code-Suchen
- Regelmäßig aktualisiert
- User-Generated-Content einbinden
**Video-Content:**
"Unboxing mit exklusivem Code"
- Code als Call-to-Action
- Visual einblenden
- Beschreibung und Kommentare
**Podcast-Sponsoring:**
"Nutze Code PODCAST für 20% Rabatt"
- Einfach zu merken
- Mündlich kommunizierbar
- Tracking von Audio-Conversions
### Social Media Strategien
**Instagram:**
- Story-Sticker mit Codes
- Swipe-Up mit vorausgefülltem Code
- IGTV-Tutorials mit Code-Reveals
- Reels mit Code-Challenges
**TikTok:**
- Viral Challenges mit Codes
- Duett-Videos mit Code-Sharing
- Live-Streams mit Flash-Codes
- Comment-Codes für Engagement
**Twitter/X:**
- Thread-Kampagnen mit Code am Ende
- Retweet-für-Code Aktionen
- Space-exklusive Codes
- Trending-Hashtags mit Codes
**LinkedIn:**
- B2B-Codes für Professionals
- Artikel mit Industry-Insights und Codes
- Company-Page-Updates
- Employee-Advocacy mit Personal Codes
### E-Mail-Marketing
**Welcome-Series:**
1. Tag 1: Welcome + WELCOME20
2. Tag 3: Feature-Highlight + TRYIT15
3. Tag 7: Success-Stories + SUCCESS25
4. Tag 14: Urgency + LASTCHANCE30
**Segmentierte Kampagnen:**
- Inaktive Nutzer: COMEBACK50
- Power-User: VIP-EXCLUSIVE
- Trial-Auslauf: STAYWITHUS40
- Geburtstage: BIRTHDAY-GIFT
**Referral-Programme:**
- "Gib deinen Freunden FRIEND30"
- "Für jede Nutzung erhältst du..."
- Leaderboards in Newsletter
## Psychologische Optimierung
### Code-Naming-Psychologie
**Emotionale Trigger:**
- WINNING (Gewinner-Gefühl)
- EXCLUSIVE (Exklusivität)
- SMART (Intelligente Entscheidung)
- FREEDOM (Freiheit/Unabhängigkeit)
**Urgency-Codes:**
- LAST24 (Zeitdruck)
- ENDING (Knappheit)
- NOW50 (Sofort-Handlung)
- TODAY (Tagesaktion)
**Value-Kommunikation:**
- SAVE50 (Klarer Sparvorteil)
- HALFPRICE (Einfache Mathematik)
- BUNDLE (Mehrwert)
- PREMIUM (Upgrade-Gefühl)
**Community-Codes:**
- FAMILY (Zugehörigkeit)
- TEAM (Gemeinschaft)
- CLUB (Exklusivität)
- INSIDER (Privileg)
### Timing und Präsentation
**Optimale Code-Platzierung:**
1. **Above-the-Fold**: Sofort sichtbar
2. **Exit-Intent**: Letzte Chance
3. **Cart-Abandonment**: Rettungsversuch
4. **Post-Purchase**: Für nächsten Kauf
5. **Milestone-Moments**: Achievements
**Zeitliche Optimierung:**
- **Morgens (6-9 Uhr)**: Productivity-Codes
- **Mittags (12-14 Uhr)**: Lunch-Break-Deals
- **Abends (19-22 Uhr)**: Relaxation-Rewards
- **Wochenende**: Weekend-Warriors
**Visuelle Gestaltung:**
- Kontrastreiche Farben
- Animierte Elemente
- Copy-Button prominent
- Countdown-Timer
- Success-Animations
## Erfolgsmetriken und KPIs
### Primäre Performance-Indikatoren
**Code-Performance-Metriken:**
1. **Redemption Rate**: Prozentsatz der eingelösten Codes
- Benchmark: 15-25% für general Codes
- Ziel: >20% für Affiliate-Codes
- Top-Performer: >40% für VIP-Codes
2. **Viral Coefficient**: Weitergabe-Rate der Codes
- Formel: (Neue Nutzer durch Code) / (Code-Nutzer)
- Benchmark: 0.5-1.5
- Ziel: >1.0 (selbsttragender Wachstum)
3. **Code-to-Customer-Value**: Lifetime-Value pro Code-Typ
- Organisch: Baseline 100%
- General-Codes: 80-90% of Baseline
- Affiliate-Codes: 110-130% of Baseline
- VIP-Codes: 150%+ of Baseline
### Affiliate-spezifische KPIs
**Partner-Performance:**
1. **Affiliate Activation Rate**: Aktive vs. registrierte Affiliates
2. **Average Revenue per Affiliate**: Monatlicher Durchschnittsumsatz
3. **Affiliate Lifetime Value**: Gesamtwert eines Affiliate-Partners
4. **Churn Rate**: Absprungrate von Affiliates
**Quality Metrics:**
1. **Customer Quality Score**: Retention/LTV von Affiliate-Kunden
2. **Fraud Rate**: Prozentsatz ungültiger Conversions
3. **Support Ticket Rate**: Support-Aufwand pro Affiliate
4. **Brand Alignment Score**: Marken-Fit der Affiliates
### Community-Metriken
**Engagement-Indikatoren:**
1. **Code-Sharing-Rate**: Wie oft werden Codes geteilt
2. **Community-Generated-Content**: UGC mit Codes
3. **Code-Discussion-Volume**: Erwähnungen in Foren/Social
4. **Ambassador-Growth**: Wachstum von Super-Usern
**Netzwerk-Effekte:**
1. **Referral-Chains**: Länge von Empfehlungsketten
2. **Cluster-Coefficient**: Vernetzungsgrad der Community
3. **Influence-Score**: Einfluss einzelner Code-Creators
4. **Community-Health-Index**: Gesamtgesundheit
## Fallstudien erfolgreicher Voucher-Systeme
### Fallstudie 1: Fitness-App "FitLife"
**Ausgangslage:**
- Premium-Fitness-App, 29€/Monat
- Zielgruppe: 25-45 Jahre
- Problem: Hohe Akquisitionskosten
**Voucher-Strategie:**
- Personal-Trainer erhalten individuelle Codes
- 30% Rabatt für erste 3 Monate
- Trainer erhalten 20% recurring commission
**Ergebnisse nach 6 Monaten:**
- 340 aktive Trainer-Affiliates
- 12.000 neue Kunden über Codes
- 65% niedrigere CAC
- 85% höhere 6-Monats-Retention
- Community von 50.000 aktiven Mitgliedern
**Erfolgsfaktoren:**
- Trainer als vertrauenswürdige Autoritäten
- Win-Win-Situation (Trainer verdienen mit)
- Community-Events mit Code-Challenges
### Fallstudie 2: SaaS-Tool "ProjectPro"
**Ausgangslage:**
- B2B-Projektmanagement-Tool
- 50-500€/Monat je nach Teamgröße
- Problem: Lange Sales-Cycles
**Voucher-Strategie:**
- Branchen-spezifische Codes (AGENCY30, STARTUP40)
- Consultants als Affiliates
- Gestaffelte Benefits nach Teamgröße
**Ergebnisse nach 12 Monaten:**
- 89 Partner-Consultants
- 450 Enterprise-Kunden
- 3.2x höherer LTV
- 45 Tage kürzerer Sales-Cycle
- 15 Branchen-Communities aufgebaut
**Erfolgsfaktoren:**
- B2B-Empfehlungen extrem wertvoll
- Consultants bringen ganze Teams
- Industry-Events mit exklusiven Codes
### Fallstudie 3: Gaming-Platform "PlayHub"
**Ausgangslage:**
- Gaming-Subscription-Service
- 9,99€/Monat
- Zielgruppe: 16-30 Jahre
**Voucher-Strategie:**
- Streamer-Codes mit Gamification
- Leaderboard für Code-Nutzungen
- Monatliche Preise für Top-Affiliates
**Ergebnisse nach 3 Monaten:**
- 1.200 Streamer aktiviert
- 180.000 Code-Redemptions
- Viral Coefficient: 2.3
- 400% Wachstum in 3 Monaten
- Sehr aktive Discord-Community
**Erfolgsfaktoren:**
- Perfekter Fit zur Gaming-Kultur
- Competitive Element durch Leaderboard
- Integration in Streaming-Content
## Häufige Fehler und wie man sie vermeidet
### Fehler 1: Zu komplexe Code-Strukturen
**Problem:**
Codes wie "XYZPROMO2024Q4SPECIAL50" sind unmöglich zu merken.
**Lösung:**
- Kurz und prägnant (max. 10 Zeichen)
- Merkbare Wörter statt Zeichensalat
- Konsistente Struktur
### Fehler 2: Inkonsistente Rabatthöhen
**Problem:**
Nutzer warten auf bessere Codes, wenn Rabatte stark variieren.
**Lösung:**
- Klare Tier-Struktur
- Vorhersehbare Rabatt-Level
- Seltene Special-Events
### Fehler 3: Fehlende Fraud-Prevention
**Problem:**
Code-Sharing in Gutschein-Foren kannibalisiert Vollpreis-Verkäufe.
**Lösung:**
- Personalisierte Codes mit Limits
- Geo-Restrictions
- Time-based Validity
### Fehler 4: Schlechte Affiliate-Betreuung
**Problem:**
Affiliates fühlen sich alleingelassen und werden inaktiv.
**Lösung:**
- Regelmäßige Check-ins
- Performance-Feedback
- Success-Resources
- Community-Building
### Fehler 5: Keine Mobile-Optimierung
**Problem:**
Code-Eingabe auf Mobile ist frustrierend.
**Lösung:**
- Auto-Complete
- Copy-Paste-Optimierung
- QR-Code-Alternative
- One-Click-Apply
## Rechtliche Aspekte und Compliance
### DSGVO-Konformität
**Vollständige Compliance durch:**
1. **Transparenz**: Nutzer weiß genau, was getrackt wird
2. **Zweckbindung**: Nur für Attribution und Rabatt
3. **Minimierung**: Nur notwendige Daten (Code + Timestamp)
4. **Keine PII**: Keine personenbezogenen Daten des Endnutzers nötig
**Best Practices:**
- Klare Datenschutzerklärung
- Opt-in für Marketing-Kommunikation
- Sichere Speicherung von Affiliate-Daten
- Regelmäßige Audits
### Steuerliche Aspekte
**Für Affiliates:**
- Provisionen sind Einkommen
- Meldepflicht ab bestimmten Grenzen
- Rechnungsstellung erforderlich
- Umsatzsteuer-Thematik
**Für Unternehmen:**
- Rabatte als Marketing-Ausgaben
- Provisions-Buchhaltung
- Internationale Steuer-Compliance
- Transfer-Pricing bei Länder-Übergreifend
### Verbraucherschutz
**Wichtige Regeln:**
- Keine irreführende Werbung
- Klare Bedingungen
- Tatsächliche Verfügbarkeit
- Keine versteckten Kosten
## Skalierung und Internationalisierung
### Lokalisierung von Code-Kampagnen
**Kulturelle Anpassung:**
**USA:**
- Aggressive Discounts (50-70%)
- FREEDOM, AMERICA, SUPER
- Black Friday/Cyber Monday Focus
**Deutschland:**
- Moderate Rabatte (20-30%)
- SPAR, VORTEIL, EXKLUSIV
- Qualität vor Quantität
**Japan:**
- Gruppen-Codes populär
- Saisonale Codes (Sakura, NewYear)
- Höflichkeit in Kommunikation
**Technische Lokalisierung:**
- Währungs-Anpassung
- Zeitzonen-Management
- Lokale Payment-Methods
- Sprach-spezifische Codes
### Wachstums-Strategien
**Phase 1: Launch (0-1.000 Nutzer)**
- 10-20 Hand-selektierte Affiliates
- Hohe Rabatte (40-50%)
- Persönliche Betreuung
- Quick Iterations
**Phase 2: Growth (1.000-10.000 Nutzer)**
- 100+ Affiliates
- Tiered System einführen
- Automation Tools
- Community Building
**Phase 3: Scale (10.000-100.000 Nutzer)**
- 1.000+ Affiliates
- Self-Service Platform
- API-Integration
- International Expansion
**Phase 4: Maturity (100.000+ Nutzer)**
- Enterprise Partnerships
- White-Label Solutions
- Advanced Analytics
- Market Leadership
## Zukunft der Voucher-Systeme
### Technologische Innovationen
**AI-Powered Personalization:**
- Individuelle Codes basierend auf Nutzer-Verhalten
- Optimale Rabatthöhe per Machine Learning
- Predictive Code-Generation
**Blockchain-Integration:**
- NFT-Codes als handelbare Assets
- Transparente Attribution-Chain
- Dezentralisierte Affiliate-Netzwerke
**Voice-Commerce:**
- Alexa/Siri Code-Eingabe
- Audio-Codes in Podcasts
- Voice-activated Rewards
**AR/VR-Integration:**
- Codes in virtuellen Welten
- AR-Scavenger-Hunts
- VR-Shopping mit Codes
### Markt-Trends
**Subscription-Economy:**
- Codes für Subscription-Services
- Tier-Upgrades via Codes
- Retention-Codes
**Creator-Economy:**
- Jeder Creator wird Affiliate
- Micro-Influencer-Revolution
- Community-Commerce
**Sustainability-Focus:**
- Eco-Codes für nachhaltige Choices
- Carbon-Offset-Codes
- Social-Impact-Codes
## Implementierungs-Roadmap für uload
### Monat 1: Foundation
**Woche 1-2: System-Design**
- Code-Format festlegen
- Datenbank-Schema
- API-Spezifikation
- Security-Konzept
**Woche 3-4: MVP-Entwicklung**
- Basic Code-Generation
- Validation-Engine
- Simple Dashboard
- Integration in Checkout
### Monat 2: Launch
**Woche 5-6: Testing & Refinement**
- Internal Testing
- Security Audit
- Performance Testing
- UX-Optimierung
**Woche 7-8: Soft Launch**
- 10 Beta-Affiliates
- Feedback sammeln
- Iterationen
- Documentation
### Monat 3: Growth
**Woche 9-10: Public Launch**
- Marketing-Kampagne
- Affiliate-Rekrutierung
- Press-Coverage
- Community-Events
**Woche 11-12: Optimization**
- A/B-Testing
- Performance-Analyse
- Feature-Erweiterungen
- Skalierung
### Monat 4-6: Expansion
- Internationale Märkte
- Enterprise-Features
- API-Öffnung
- Strategic Partnerships
## Erfolgsfaktoren für uload
### Unique Selling Propositions
1. **"Der fairste Deal im Link-Shortening"**
- Transparente Provisionen
- Win-Win für alle Beteiligten
- Community-First-Ansatz
2. **"Codes, die Geschichten erzählen"**
- Personalisierte Codes
- Narrative Marketing
- Emotional Connection
3. **"Von Creatorn für Creator"**
- Community-Driven Development
- Creator-Feedback-Loop
- Gemeinsames Wachstum
### Quick Wins
1. **Launch-Partner-Programm**
- 10 High-Profile-Affiliates
- Exklusive Launch-Codes
- PR-Story
2. **Viral-Challenge**
- Code-Hunt auf Social Media
- Preise für Finder
- User-Generated-Content
3. **Community-Milestone**
- "10.000 Codes = Feature X"
- Gemeinsames Ziel
- Celebration-Event
### Langfristige Vision
**Jahr 1: Foundation**
- 1.000 aktive Affiliates
- 100.000 Code-Redemptions
- Profitabilität erreichen
**Jahr 2: Expansion**
- 10.000 aktive Affiliates
- 1 Million Code-Redemptions
- International Launch
**Jahr 3: Leadership**
- 50.000 aktive Affiliates
- 10 Millionen Code-Redemptions
- Marktführer in Europa
## Fazit: Voucher-Codes als strategischer Hebel
Voucher-Codes sind für uload weit mehr als ein simples Tracking-Tool. Sie sind:
1. **Community-Builder**: Schaffen Zugehörigkeit und Identität
2. **Growth-Engine**: Ermöglichen virales, nachhaltiges Wachstum
3. **Trust-Creator**: Transparenz schafft Vertrauen bei Affiliates
4. **Revenue-Generator**: Win-Win-Modell für alle Beteiligten
5. **Brand-Differentiator**: Unterscheidungsmerkmal im Markt
Der Schlüssel zum Erfolg liegt nicht in der Technologie selbst, sondern in der durchdachten Orchestrierung von Psychologie, Community, Marketing und Technik. Voucher-Codes sind das perfekte Instrument, um aus einzelnen Nutzern eine engagierte Community zu formen und aus Affiliates echte Partner zu machen.
Für uload bedeutet dies konkret: Start simple, think big. Beginnt mit einem einfachen Code-System, aber designed es von Anfang an für Skalierung. Baut eine Kultur um die Codes herum. Macht sie zu einem Teil der Marken-DNA. Und vor allem: Hört auf eure Community. Sie wird euch zeigen, wie die Codes optimal genutzt werden können.
Die Zukunft gehört den Plattformen, die es schaffen, Technologie menschlich zu machen. Voucher-Codes sind genau das: Eine technische Lösung, die menschliche Bedürfnisse nach Zugehörigkeit, Anerkennung und Vorteil bedient. Für uload ist dies die Chance, nicht nur ein Tool zu bauen, sondern ein Ökosystem zu schaffen, in dem jeder gewinnt.

View file

@ -0,0 +1,501 @@
# Implementierungsansätze für Voucher-System in uload
## Übersicht
Dieses Dokument analysiert verschiedene technische Ansätze zur Integration eines Voucher/Promo-Code-Systems in die bestehende uload-Architektur. Basierend auf der aktuellen Codebasis werden drei Hauptansätze vorgestellt: Minimal MVP, Integrierte Lösung und Enterprise-Ready System.
## Aktuelle Architektur-Analyse
### Bestehende Komponenten
**Datenbank-Struktur (PocketBase):**
- `links` Collection mit Workspace-Support
- `users` Collection mit Subscription-Status
- `clicks` Collection für Analytics
- `workspaces` Collection für Team-Features
- Bereits vorhandene Tag-System-Architektur
**Frontend-Stack:**
- SvelteKit mit Server-Side-Rendering
- Tailwind CSS für UI
- Form-Actions für Backend-Interaktionen
**Business-Logic:**
- Link-Limits basierend auf Subscription
- Workspace-basierte Link-Organisation
- Bereits implementierte Short-Code-Generierung
## Ansatz 1: Minimal MVP (1-2 Wochen)
### Konzept
Schnelle Integration durch Erweiterung der bestehenden Link-Struktur. Voucher-Codes werden als spezielle Links behandelt.
### Technische Umsetzung
**Datenbank-Erweiterung:**
```
links Collection erweitern:
- voucher_code: string (optional, unique)
- voucher_type: select ['discount', 'feature', 'trial']
- voucher_value: json (z.B. {discount: 30, currency: 'EUR'})
- voucher_valid_until: date
- voucher_max_uses: number
- voucher_current_uses: number
- is_voucher: bool (unterscheidet Voucher von normalen Links)
```
**Implementation:**
1. Neues Feld `voucher_code` in bestehender `links` Collection
2. Voucher-Validation im bestehenden Redirect-Flow (`[...slug]/+page.server.ts`)
3. Einfaches Admin-Interface in `/my/vouchers`
**Vorteile:**
- Minimale Änderungen an bestehender Architektur
- Nutzt vorhandene Link-Analytics
- Schnelle Time-to-Market
- Keine neuen Dependencies
**Nachteile:**
- Vermischung von Links und Vouchers
- Limitierte Voucher-Features
- Schwierig zu skalieren
**Aufwand:**
- Backend: 3-4 Tage
- Frontend: 2-3 Tage
- Testing: 1-2 Tage
## Ansatz 2: Dedizierte Voucher-Collections (2-3 Wochen)
### Konzept
Saubere Trennung durch eigene Datenstrukturen für Vouchers, aber Integration in bestehende Flows.
### Technische Umsetzung
**Neue Collections:**
```
vouchers:
- id: string
- code: string (unique, indexed)
- creator_id: relation -> users
- workspace_id: relation -> workspaces
- type: select ['percentage', 'fixed', 'feature', 'trial']
- value: json
- conditions: json (min_amount, eligible_plans, etc.)
- valid_from: date
- valid_until: date
- max_redemptions: number
- max_redemptions_per_user: number
- metadata: json
voucher_redemptions:
- id: string
- voucher_id: relation -> vouchers
- user_id: relation -> users (optional für anonyme)
- session_id: string
- redeemed_at: datetime
- applied_value: json
- referrer_url: string
- ip_hash: string
- user_agent: string
```
**API-Struktur:**
```
/api/voucher/validate - POST - Prüft Voucher
/api/voucher/redeem - POST - Löst Voucher ein
/api/voucher/stats - GET - Analytics für Creator
```
**Frontend-Routes:**
```
/voucher/[code] - Landing Page mit Voucher
/my/vouchers - Voucher-Management
/my/vouchers/create - Neuer Voucher
/my/vouchers/[id]/analytics - Voucher-Analytics
```
**Integration Points:**
1. Download-Page zeigt Voucher-Code prominent
2. Session-Storage für Voucher-Persistenz
3. Webhook für App-Integration
**Vorteile:**
- Saubere Architektur
- Flexibel erweiterbar
- Unabhängige Voucher-Features
- Bessere Performance durch Separation
**Nachteile:**
- Mehr Entwicklungsaufwand
- Neue Collections zu verwalten
- Komplexere Deployment
**Aufwand:**
- Backend: 5-7 Tage
- Frontend: 4-5 Tage
- Testing: 2-3 Tage
- Integration: 2 Tage
## Ansatz 3: Enterprise-Ready Affiliate System (4-6 Wochen)
### Konzept
Vollständiges Affiliate-Management-System mit Vouchers als Kernkomponente.
### Technische Umsetzung
**Erweiterte Datenstruktur:**
```
affiliates:
- id: string
- user_id: relation -> users
- tier: select ['bronze', 'silver', 'gold', 'platinum']
- commission_rate: number
- lifetime_earnings: number
- current_balance: number
- payout_threshold: number
- payment_details: json (encrypted)
- approved_at: datetime
- suspended_at: datetime
campaigns:
- id: string
- name: string
- affiliate_id: relation -> affiliates
- start_date: datetime
- end_date: datetime
- budget: number
- spent: number
- target_conversions: number
- actual_conversions: number
voucher_templates:
- id: string
- name: string
- code_pattern: string (z.B. "AFFILIATE-{RANDOM}")
- default_value: json
- auto_generate: bool
- requires_approval: bool
conversions:
- id: string
- voucher_redemption_id: relation
- user_id: relation -> users
- event_type: select ['signup', 'purchase', 'subscription']
- event_value: number
- commission_amount: number
- commission_paid: bool
- attributed_to: relation -> affiliates
```
**Advanced Features:**
**Multi-Touch Attribution:**
```typescript
// Tracking mehrerer Touchpoints
interface AttributionChain {
touchpoints: [{
voucher_code: string,
timestamp: Date,
weight: number // Anteil an Conversion
}],
model: 'first_touch' | 'last_touch' | 'linear' | 'time_decay'
}
```
**Fraud Detection:**
```typescript
interface FraudSignals {
velocity_score: number, // Zu viele Redemptions zu schnell
ip_diversity: number, // Verschiedene IPs
device_fingerprint_matches: number,
behavioral_anomalies: string[]
}
```
**Real-Time Dashboard:**
- WebSocket-Updates für Live-Metriken
- Heatmaps für geografische Verteilung
- Conversion-Funnel-Visualization
- A/B-Test-Results
**API-Ecosystem:**
```
/api/v1/affiliates - CRUD für Affiliates
/api/v1/campaigns - Campaign Management
/api/v1/vouchers - Voucher Operations
/api/v1/analytics - Comprehensive Analytics
/api/v1/webhooks - Event Notifications
/api/v1/payouts - Commission Management
```
**Integration-Features:**
- Stripe Connect für automatische Auszahlungen
- Slack/Discord-Notifications
- Zapier-Integration
- CSV-Export für Buchhaltung
- API-SDK für Partner
**Vorteile:**
- Komplett-Lösung für Affiliate-Marketing
- Skaliert auf Enterprise-Level
- Maximale Flexibilität
- Competitive Advantage
**Nachteile:**
- Hoher initialer Aufwand
- Komplexität in Wartung
- Overhead für kleine Teams
- Längere Time-to-Market
**Aufwand:**
- Backend: 15-20 Tage
- Frontend: 10-15 Tage
- Testing: 5-7 Tage
- Documentation: 2-3 Tage
- Integration: 3-5 Tage
## Empfohlene Strategie: Progressiver Ansatz
### Phase 1: Start mit Ansatz 2 (Dedizierte Collections)
**Warum:**
- Balance zwischen Schnelligkeit und Sauberkeit
- Solide Grundlage für Erweiterungen
- Ermöglicht frühe Validierung
**Initiale Features:**
- Basic Voucher CRUD
- Simple Redemption-Flow
- Basis-Analytics
- Manual Affiliate-Onboarding
### Phase 2: Schrittweise Erweiterung
**Nach 1-2 Monaten:**
- Automated Code-Generation
- Tiered Affiliate-System
- Enhanced Analytics
- Email-Integration
**Nach 3-4 Monaten:**
- Commission-Tracking
- Fraud-Detection
- API für Partner
- Advanced Dashboard
### Phase 3: Enterprise Features
**Nach 6+ Monaten:**
- Multi-Touch Attribution
- Automated Payouts
- White-Label Options
- ML-based Optimization
## Technische Requirements
### Backend-Anforderungen
**Neue API-Endpoints:**
```typescript
// Voucher-Validation
POST /api/voucher/validate
Body: { code: string, context?: any }
Response: { valid: boolean, discount?: number, message?: string }
// Voucher-Redemption
POST /api/voucher/redeem
Body: { code: string, session_id: string, user_id?: string }
Response: { success: boolean, applied_value: any }
// Affiliate-Dashboard
GET /api/affiliate/stats
Response: { redemptions: number, earnings: number, ... }
```
**PocketBase-Rules:**
```javascript
// Vouchers Collection Rules
listRule: "@request.auth.id = creator_id || is_public = true"
viewRule: "@request.auth.id = creator_id || code = @request.data.code"
createRule: "@request.auth.id != ''"
updateRule: "@request.auth.id = creator_id"
deleteRule: "@request.auth.id = creator_id"
```
### Frontend-Komponenten
**Neue Komponenten benötigt:**
```
VoucherInput.svelte - Code-Eingabe mit Validation
VoucherBadge.svelte - Visuelle Code-Darstellung
VoucherStats.svelte - Analytics-Dashboard
VoucherCreator.svelte - Code-Generator
AffiliateOnboarding.svelte - Partner-Registration
CommissionOverview.svelte - Earnings-Dashboard
```
### Infrastructure
**Caching-Strategy:**
```typescript
// Redis/In-Memory Cache für häufige Voucher
const voucherCache = new Map<string, VoucherData>();
const CACHE_TTL = 300; // 5 Minuten
// Cache-Warming für populäre Codes
async function warmCache() {
const popularVouchers = await getPopularVouchers();
popularVouchers.forEach(v => voucherCache.set(v.code, v));
}
```
**Rate-Limiting:**
```typescript
// Verhindere Voucher-Brute-Force
const rateLimiter = {
maxAttempts: 10,
windowMs: 60000, // 1 Minute
blockDurationMs: 600000 // 10 Minuten
};
```
## Migration von bestehenden Daten
Falls bereits Referral-Links existieren:
```typescript
// Migration Script
async function migrateReferralLinks() {
const referralLinks = await pb.collection('links')
.getFullList({ filter: 'is_referral = true' });
for (const link of referralLinks) {
await pb.collection('vouchers').create({
code: link.short_code.toUpperCase(),
creator_id: link.user_id,
type: 'percentage',
value: { discount: 20 },
// ... mapping
});
}
}
```
## Testing-Strategie
### Unit-Tests
```typescript
// Voucher-Validation Tests
describe('VoucherValidation', () => {
test('validates expired vouchers', () => {});
test('checks redemption limits', () => {});
test('applies conditions correctly', () => {});
});
```
### Integration-Tests
```typescript
// End-to-End Redemption Flow
describe('VoucherRedemption', () => {
test('complete redemption journey', async () => {
// 1. Create voucher
// 2. Validate voucher
// 3. Redeem voucher
// 4. Check analytics
});
});
```
### Load-Testing
```bash
# K6 Script für Voucher-Endpoints
k6 run --vus 100 --duration 30s voucher-load-test.js
```
## Sicherheitsüberlegungen
### Voucher-Code-Generation
```typescript
// Sichere Code-Generation
function generateSecureCode(prefix: string): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const random = crypto.getRandomValues(new Uint8Array(8));
let code = prefix;
for (const byte of random) {
code += chars[byte % chars.length];
}
return code;
}
```
### SQL-Injection-Prevention
```typescript
// Immer Parameterized Queries
const voucher = await pb.collection('vouchers')
.getFirstListItem(`code = {:code}`, { code: userInput });
// Niemals: `code = "${userInput}"`
```
### Rate-Limiting und Fraud-Detection
```typescript
// Fraud-Signale
const fraudIndicators = {
tooManyRedemptions: redemptions > 10 && timeWindow < 3600,
suspiciousPattern: hasSimilarTimestamps(redemptions),
knownAbuser: blacklist.includes(ipHash)
};
```
## Monitoring und Analytics
### Key Metrics
```typescript
interface VoucherMetrics {
// Performance
redemptionRate: number, // Redemptions / Impressions
conversionValue: number, // Revenue from Voucher Users
// Quality
fraudRate: number, // Fraudulent / Total Redemptions
abuseRate: number, // Multi-Use Attempts / Total
// Business
customerAcquisitionCost: number,
lifetimeValue: number,
returnOnInvestment: number
}
```
### Logging
```typescript
// Strukturiertes Logging
logger.info('voucher_redeemed', {
code: voucher.code,
user_id: user?.id,
session_id: session.id,
value: voucher.value,
timestamp: new Date().toISOString()
});
```
## Zusammenfassung
Für uload empfiehlt sich der **progressive Ansatz mit Start bei Ansatz 2** (Dedizierte Collections):
**Sofort umsetzbar (Woche 1-2):**
- Basis Voucher-System
- Simple Redemption
- Creator-Dashboard
**Kurzfristig erweiterbar (Monat 1-2):**
- Affiliate-Tiers
- Advanced Analytics
- Fraud-Detection
**Langfristig skalierbar (Monat 3+):**
- Full Attribution
- Automated Payouts
- Enterprise Features
Dieser Ansatz bietet die beste Balance zwischen schneller Markteinführung und langfristiger Skalierbarkeit, während er perfekt zur bestehenden uload-Architektur passt.

View file

@ -0,0 +1,246 @@
# Toast Integration Status - uLoad
## 📊 Übersicht
Stand: 16. Januar 2025 (Letzte Aktualisierung: 15:45 Uhr)
Dieses Dokument zeigt den aktuellen Status der Toast-Integration in uLoad.
---
## ✅ Bereits implementiert
### 1. **Username Setup** (`/setup-username`)
- **Datei:** `src/routes/(app)/setup-username/+page.svelte`
- **Implementierte Toasts:**
- ✅ **Success:** "Username "{username}" erfolgreich gesetzt! 🎉"
- ✅ **Error:** Zeigt spezifische Fehlermeldungen
- **Status:** Vollständig implementiert und getestet
### 2. **Authentication** (`/login`, `/logout`)
- **Dateien:**
- `src/routes/login/+page.svelte`
- `src/lib/components/Navigation.svelte`
- **Implementierte Toasts:**
- ✅ **Login Success:** "Erfolgreich angemeldet"
- ✅ **Login Error:** "Anmeldung fehlgeschlagen" + Details
- ✅ **Logout:** "Erfolgreich abgemeldet"
- ✅ **Email Verification:** "E-Mail erfolgreich bestätigt"
- ✅ **Register Success:** "Erfolgreich registriert! Bitte bestätige deine E-Mail."
- ✅ **Token Expired:** Warning Toast für abgelaufene Links
- **Status:** Vollständig implementiert
### 3. **Link Management** (`/my/links`)
- **Dateien:**
- `src/routes/(app)/my/links/+page.svelte`
- `src/lib/components/links/LinkCard.svelte`
- `src/lib/components/links/LinkList.svelte`
- **Implementierte Toasts:**
- ✅ **Link Created:** "Link erfolgreich erstellt"
- ✅ **Link Copied:** "Link in Zwischenablage kopiert 📋"
- ✅ **Link Deleted:** "Link gelöscht"
- ✅ **Creation Error:** Spezifische Fehlermeldungen
- **Status:** Vollständig implementiert
### 4. **Profile & Settings** (`/settings`)
- **Datei:** `src/routes/(app)/settings/+page.svelte`
- **Implementierte Toasts:**
- ✅ **Profile Updated:** "Profil erfolgreich aktualisiert"
- ✅ **Password Changed:** "Passwort erfolgreich geändert"
- ✅ **Update Errors:** Spezifische Fehlermeldungen
- **Status:** Vollständig implementiert
---
## 🔄 Noch zu implementieren
### 5. **Registration & Password Reset** (`/register`, `/forgot-password`, `/reset-password`)
**Benötigte Toasts:**
- [ ] Registration Form Validation: Inline-Validierung
- [ ] Password Reset Requested: "Passwort-Reset-Link wurde gesendet"
- [ ] Password Reset Success: "Passwort erfolgreich zurückgesetzt"
- [ ] Reset Link Invalid: "Ungültiger oder abgelaufener Link"
### 6. **Link Management - Erweitert**
**Benötigte Toasts:**
- [ ] Link Updated: "Link erfolgreich aktualisiert"
- [ ] Link Expired: "Link ist abgelaufen"
- [ ] Max Clicks Reached: "Maximale Klicks erreicht"
- [ ] Link Password Set: "Passwort gesetzt"
- [ ] Bulk Actions: "X Links gelöscht/aktualisiert"
### 7. **Profile - Erweitert**
**Benötigte Toasts:**
- [ ] Avatar Uploaded: "Profilbild erfolgreich hochgeladen"
- [ ] Avatar Deleted: "Profilbild entfernt"
- [ ] Bio Updated: "Bio aktualisiert"
- [ ] Social Links Added: "Social Media verknüpft"
- [ ] Privacy Settings: "Datenschutzeinstellungen aktualisiert"
### 5. **Subscription & Billing** (`/pricing`, `/billing`)
**Benötigte Toasts:**
- [ ] Subscription Upgraded: "Erfolgreich auf Pro-Plan upgraded! 🚀"
- [ ] Subscription Cancelled: "Abo wurde gekündigt. Zugang bis Monatsende aktiv."
- [ ] Payment Failed: "Zahlung fehlgeschlagen"
- [ ] Payment Method Updated: "Zahlungsmethode aktualisiert"
### 6. **Tag Management** (`/tags`)
**Benötigte Toasts:**
- [ ] Tag Created: "Tag erstellt"
- [ ] Tag Deleted: "Tag gelöscht"
- [ ] Tag Updated: "Tag aktualisiert"
- [ ] Tags Applied: "Tags angewendet"
### 7. **Analytics & Stats** (`/analytics`)
**Benötigte Toasts:**
- [ ] Data Exported: "Daten erfolgreich exportiert"
- [ ] Report Generated: "Bericht erstellt"
- [ ] Period Updated: "Zeitraum aktualisiert"
### 8. **API & Integrations** (`/api`, `/integrations`)
**Benötigte Toasts:**
- [ ] API Key Generated: "API-Schlüssel generiert"
- [ ] API Key Copied: "API-Schlüssel kopiert"
- [ ] Integration Connected: "Integration erfolgreich verbunden"
- [ ] Integration Disconnected: "Integration getrennt"
### 9. **Error States**
**Allgemeine Error-Toasts:**
- [ ] Network Error: "Netzwerkfehler - Bitte überprüfe deine Internetverbindung"
- [ ] Permission Denied: "Keine Berechtigung für diese Aktion"
- [ ] Session Expired: "Sitzung abgelaufen - Bitte melde dich erneut an"
- [ ] Rate Limit: "Zu viele Anfragen - Bitte warte einen Moment"
- [ ] Server Error: "Serverfehler - Bitte versuche es später erneut"
### 10. **Form Validations**
**Validierungs-Toasts:**
- [ ] Invalid Email: "Ungültige E-Mail-Adresse"
- [ ] Password Too Weak: "Passwort zu schwach"
- [ ] Required Field: "Pflichtfeld: {fieldname}"
- [ ] Invalid URL: "Ungültige URL"
- [ ] File Too Large: "Datei zu groß (max. {size})"
---
## 📝 Implementierungs-Checkliste
### Phase 1: Kritische User-Flows (Priorität: HOCH)
- [ ] Login/Logout
- [ ] Link erstellen
- [ ] Link kopieren
- [ ] Fehlermeldungen
### Phase 2: CRUD-Operationen (Priorität: MITTEL)
- [ ] Profile Updates
- [ ] Link Management
- [ ] Tag Management
- [ ] Settings
### Phase 3: Premium Features (Priorität: NIEDRIG)
- [ ] Subscription Management
- [ ] Analytics
- [ ] API Keys
- [ ] Integrations
---
## 🎯 Implementierungs-Guidelines
### Best Practices:
1. **Immer den Toast Service verwenden:**
```typescript
import { notify, toastMessages } from '$lib/services/toast';
```
2. **Konsistente Nachrichten:**
- Erfolg: Kurz und positiv
- Fehler: Klar und hilfreich
- Info: Neutral und informativ
3. **Promise-Pattern für async Operationen:**
```typescript
notify.promise(saveOperation(), {
loading: 'Wird gespeichert...',
success: 'Erfolgreich gespeichert!',
error: (err) => `Fehler: ${err.message}`
});
```
4. **Undo-Actions wo sinnvoll:**
```typescript
notify.action('Link gelöscht', 'Rückgängig', async () => {
await restoreLink(id);
});
```
---
## 📊 Metriken
### Aktueller Status:
- **Implementiert:** 1 von ~50 Toast-Integrationen (2%)
- **Service erstellt:**
- **Styling komplett:**
- **Dark Mode Support:**
### Geschätzter Aufwand:
- **Phase 1:** ~2 Stunden
- **Phase 2:** ~3 Stunden
- **Phase 3:** ~2 Stunden
- **Gesamt:** ~7 Stunden
---
## 🚀 Nächste Schritte
1. **Priorität 1:** Login/Logout Toasts implementieren
2. **Priorität 2:** Link-Management Toasts
3. **Priorität 3:** Error-Handling vereinheitlichen
4. **Priorität 4:** Alle Forms mit Validierungs-Toasts ausstatten
---
## 📌 Notizen
- Toast Service ist zentral in `/lib/services/toast.ts`
- Vordefinierte Nachrichten reduzieren Duplikation
- Mobile-First: Toasts funktionieren mit Swipe-to-dismiss
- A11y: Screen-Reader Support ist automatisch dabei
---
## 🔗 Verwandte Dokumente
- [Toast Implementation Plan](./toast-notifications.md)
- [Toast Service API](../../src/lib/services/toast.ts)
- [Svelte Sonner Docs](https://github.com/wobsoriano/svelte-sonner)

View file

@ -0,0 +1,261 @@
# Toast Notifications - Implementation Plan
## 📋 Overview
Integration von **Svelte Sonner** für moderne Toast-Benachrichtigungen in uLoad.
## 🎯 Ziele
- Nutzer über Aktionen informieren (Erfolg, Fehler, Loading)
- Konsistente UX über die gesamte App
- Mobile-freundliche Benachrichtigungen
- Minimaler Setup mit maximaler Flexibilität
## 📦 Implementation Steps
### Phase 1: Installation & Setup
```bash
# 1. Package installieren
npm install svelte-sonner
# 2. Toaster in Root-Layout einbinden
# src/routes/+layout.svelte
```
### Phase 2: Basis-Integration
```svelte
<!-- src/routes/+layout.svelte -->
<script>
import { Toaster } from 'svelte-sonner';
// ... existing imports
</script>
<!-- Am Ende des Templates -->
<Toaster position="bottom-right" expand={false} richColors closeButton duration={4000} />
```
### Phase 3: Custom Styling
```css
/* src/app.css - Tailwind/Theme Integration */
:root {
/* Light Mode */
--sonner-toast-background: theme('colors.white');
--sonner-toast-text: theme('colors.gray.900');
--sonner-toast-border: theme('colors.gray.200');
/* Success */
--sonner-success-bg: theme('colors.green.50');
--sonner-success-border: theme('colors.green.200');
--sonner-success-text: theme('colors.green.800');
/* Error */
--sonner-error-bg: theme('colors.red.50');
--sonner-error-border: theme('colors.red.200');
--sonner-error-text: theme('colors.red.800');
/* Info */
--sonner-info-bg: theme('colors.blue.50');
--sonner-info-border: theme('colors.blue.200');
--sonner-info-text: theme('colors.blue.800');
}
.dark {
/* Dark Mode */
--sonner-toast-background: theme('colors.gray.800');
--sonner-toast-text: theme('colors.gray.100');
--sonner-toast-border: theme('colors.gray.700');
/* Success */
--sonner-success-bg: theme('colors.green.900/20');
--sonner-success-border: theme('colors.green.800');
--sonner-success-text: theme('colors.green.400');
/* Error */
--sonner-error-bg: theme('colors.red.900/20');
--sonner-error-border: theme('colors.red.800');
--sonner-error-text: theme('colors.red.400');
}
```
### Phase 4: Helper Service
```typescript
// src/lib/services/toast.ts
import { toast } from 'svelte-sonner';
export const notify = {
// Success Messages
success: (message: string) => toast.success(message),
// Error Messages with optional details
error: (message: string, details?: string) => {
if (details) {
toast.error(message, {
description: details
});
} else {
toast.error(message);
}
},
// Loading → Success/Error Pattern
promise: async <T>(
promise: Promise<T>,
messages: {
loading: string;
success: string | ((data: T) => string);
error: string | ((error: any) => string);
}
) => {
return toast.promise(promise, messages);
},
// Info Messages
info: (message: string) => toast.info(message),
// Custom with Actions
action: (message: string, actionLabel: string, onAction: () => void) => {
toast(message, {
action: {
label: actionLabel,
onClick: onAction
}
});
}
};
```
## 🔄 Migration Plan
### 1. Username Setup Page
```typescript
// src/routes/(app)/setup-username/+page.svelte
import { notify } from '$lib/services/toast';
// Nach erfolgreichem Setzen
notify.success('Username erfolgreich gesetzt! 🎉');
// Bei Fehler
notify.error('Username bereits vergeben');
```
### 2. Link Management
```typescript
// Link erstellen
notify.promise(createLink(data), {
loading: 'Link wird erstellt...',
success: 'Link erfolgreich erstellt!',
error: (err) => `Fehler: ${err.message}`
});
// Link kopieren
notify.success('Link in Zwischenablage kopiert 📋');
// Link löschen mit Undo
notify.action('Link gelöscht', 'Rückgängig', async () => {
await restoreLink(linkId);
notify.success('Link wiederhergestellt');
});
```
### 3. Authentication
```typescript
// Login
notify.success('Erfolgreich angemeldet');
// Logout
notify.info('Erfolgreich abgemeldet');
// Email-Verifikation
notify.info('Bestätigungsmail wurde gesendet');
// Passwort zurücksetzen
notify.success('Passwort-Reset-Link wurde gesendet');
```
### 4. Profile Updates
```typescript
// Profil speichern
notify.promise(updateProfile(data), {
loading: 'Profil wird aktualisiert...',
success: 'Profil erfolgreich gespeichert',
error: 'Fehler beim Speichern des Profils'
});
// Avatar hochladen
notify.promise(uploadAvatar(file), {
loading: 'Bild wird hochgeladen...',
success: 'Profilbild aktualisiert',
error: 'Fehler beim Upload'
});
```
### 5. Subscription/Payment
```typescript
// Upgrade
notify.success('Erfolgreich auf Pro-Plan upgraded! 🚀');
// Payment failed
notify.error('Zahlung fehlgeschlagen', 'Bitte Zahlungsmethode überprüfen');
// Subscription cancelled
notify.info('Abo wurde gekündigt. Zugang bis Monatsende aktiv.');
```
## 🎨 Toast-Typen & Verwendung
| Typ | Verwendung | Beispiel |
| ----------- | --------------------- | ------------------------------ |
| **success** | Erfolgreiche Aktionen | "Link erstellt", "Gespeichert" |
| **error** | Fehler & Probleme | "Fehler beim Speichern" |
| **info** | Informationen | "Neue Version verfügbar" |
| **loading** | Laufende Prozesse | "Wird geladen..." |
| **promise** | Async-Operationen | API-Calls, Datei-Uploads |
| **action** | Mit Aktion-Button | "Gelöscht" → "Rückgängig" |
## 📱 Mobile Considerations
- **Position**: `bottom-center` auf Mobile für bessere Erreichbarkeit
- **Swipe to dismiss**: Automatisch aktiviert
- **Stacking**: Maximal 3 Toasts gleichzeitig
- **Duration**: 4 Sekunden (außer bei Aktionen)
## 🧪 Testing Checklist
- [ ] Toast erscheint bei Success-Actions
- [ ] Toast erscheint bei Fehlern
- [ ] Promise-basierte Toasts zeigen alle 3 States
- [ ] Dark Mode Styling funktioniert
- [ ] Mobile Swipe-to-dismiss funktioniert
- [ ] Undo-Actions funktionieren
- [ ] Toasts stören keine anderen UI-Elemente
- [ ] Screen-Reader Kompatibilität
## 📊 Metriken
Nach Implementation tracken:
- Toast-Interaktionen (dismissals, action clicks)
- Häufigste Toast-Typen
- Durchschnittliche Anzeigedauer
## 🚀 Rollout
1. **Week 1**: Installation & Basic Setup
2. **Week 2**: Migration kritischer User-Flows (Login, Links)
3. **Week 3**: Vollständige Migration aller Feedback-Messages
4. **Week 4**: A/B Testing & Optimierung
## 📝 Notes
- Svelte Sonner unterstützt auch **Custom Components** als Toasts
- Bei Bedarf können wir spezielle Toast-Typen für uLoad erstellen (z.B. "Link-Preview-Toast")
- Toast-History könnte in Zukunft implementiert werden