# Nimuli — Master Design Spec

**Datum:** 2026-05-15
**Status:** Design abgeschlossen, bereit für Implementation-Planung
**Autor:** Boban Blaskovic
**Projekt-Typ:** Standalone SaaS (eigene Codebase, getrennt von CluPilot)

---

## 1. Produkt-Übersicht

**Nimuli** ist eine All-in-One Link-Management-Plattform.

**Kern-Features:**
- Short-Links mit Whitelabel-Custom-Domains
- Dynamische QR-Codes (Logo, Farben, alle Types: URL/vCard/WiFi/PDF/MP3/Text)
- Link-in-Bio Microsites mit Block-Editor
- Smart-Routing (Geo, Device, OS, Time, Language, UTM)
- A/B-Testing mit Conversion-Tracking
- Pixel-Injection (Meta/Google/TikTok via Interstitial)
- Klick-Analytics mit Live-Dashboards
- AI-Suite (Auto-Slug, A/B-Generator, Anomalie-Detection, Insight-Reports, Routing-per-Prompt)
- REST-API + Outgoing-Webhooks
- Multi-Workspace (Agency-Use-Case)

**Markt:** DACH-Start, DE+EN i18n, geplant EU-Expansion.

**Marken + Domains:**
- Marke: **Nimuli**
- Marketing-Site: `nimuli.com`
- App/Dashboard: `app.nimuli.com`
- Short-Redirect-Domain: `nimu.li`
- Whitelabel-Subdomains: `*.nimu.li` (User-Subdomain)
- Custom-Domains: `{kunden-domain}.com` via CNAME → nimu.li

**Differenzierung:**
- Pixel-Injection im Standard-Plan (Bitly ignoriert das)
- AI-Suite ab Tag 1 (Konkurrenz hat das nicht oder spärlich)
- Agency-fokussierte Features (Multi-Workspace, Whitelabel, Reseller)
- EU-Hosting, DSGVO-first

---

## 2. Gesamt-Architektur

### Lokale Entwicklung
Single-Host Docker Compose. Alle Services in einem Compose-File:
- `nginx`, `app` (Octane), `queue`, `scheduler`, `reverb`, `mysql`, `redis`, `mailpit`

### Production-Cluster (Hetzner Cloud)

```
                    ┌──────────────────────┐
                    │  Hetzner LB (Public) │
                    │  Failover-IP, SSL    │
                    └──────────┬───────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        │                      │                      │
        ▼                      ▼                      ▼
   ┌────────┐            ┌────────┐            ┌────────┐
   │ web-01 │            │ web-02 │            │ web-03 │
   │ Docker │            │ Docker │            │ Docker │
   │ app+   │            │ app+   │            │ app+   │
   │ nginx  │            │ nginx  │            │ nginx  │
   └───┬────┘            └───┬────┘            └───┬────┘
       │                     │                     │
       └──────────┬──────────┴──────────┬──────────┘
                  │                     │
            ┌─────▼─────┐         ┌─────▼─────┐
            │  DB-01    │         │ Redis-01  │
            │  MySQL    │         │ Cache+    │
            │           │         │ Queue+    │
            │           │         │ Sessions  │
            └───────────┘         └───────────┘

        ┌──────────────┐         ┌──────────────────┐
        │ worker-01    │         │ CDN (bunny.net   │
        │ Queue +      │         │ oder Hetzner     │
        │ Scheduler +  │         │ Storage Box CDN) │
        │ Reverb       │         │                  │
        └──────────────┘         └──────────────────┘
```

**DNS-Routing:**
- `app.nimuli.com` → LB-IP → web-Pool
- `nimu.li`, `*.nimu.li` → LB-IP → web-Pool (Redirect-Service)
- `ws.nimuli.com` → direkt worker-01 (Reverb, kein LB)
- `{custom-domain}` → CNAME → nimu.li → LB

**Kosten:** ~60-85€/Monat Hetzner.

### Drei Haupt-Subsysteme

1. **Redirect-Service** — Hot-Path. `nimu.li/{slug}` → Redis-Lookup → 302 + async Klick-Event. Ziel <10ms p95.
2. **App-Dashboard** — `app.nimuli.com`. Livewire-CRUD, Analytics, Workspace-Mgmt, Billing.
3. **Background-Worker** — Queue für Klick-Events → Rollups, Email, Stripe-Webhooks, AI-Calls, Pixel-Server-Side-Sends, Domain-SSL-Provisioning.

---

## 3. Stack

| Bereich | Technologie |
|---------|-------------|
| Backend | Laravel 12 + Octane (Swoole oder FrankenPHP) |
| Frontend | Livewire v3 + Alpine.js + Tailwind v4 (`@theme`) |
| Realtime | Laravel Reverb (WebSockets) |
| Auth | Laravel Breeze (Livewire-Stack) + `pragmarx/google2fa` (2FA) |
| Permissions | `spatie/laravel-permission` (per Workspace scoped) |
| Modals | Wire Elements Modal |
| Charts | Chart.js 4.x |
| QR-Codes | `chillerlan/php-qrcode` (Backend), QR-JS-Lib für Live-Preview |
| Image-Processing | `intervention/image-laravel` (Resize, WebP, EXIF-Strip, Auto-Rotate) |
| Media-Storage | `spatie/laravel-medialibrary` |
| Audit | `spatie/laravel-activitylog` |
| Settings | `spatie/laravel-settings` |
| Backup | `spatie/laravel-backup` (4×/Tag, 14d Retention) |
| Translations | DB-Table + Redis-Cache (Custom-Implementation, Admin-UI) + Spatie-Translatable für Model-Felder |
| Subscriptions | Laravel Cashier (Stripe) |
| Queue | Redis + Horizon |
| Search | Eloquent `WHERE LIKE` (MySQL FULLTEXT optional) |
| Testing | Pest 3 + Livewire-Testing + Browser-Tests |
| Static Analysis | PHPStan Level 6+ |
| Code-Style | Laravel Pint |
| CI/CD | GitHub Actions → SSH-Deploy zu Hetzner |
| Container | Docker Compose |
| Filesystem | Lokal NAS-Mount (dev), Hetzner Storage Box (prod) |

---

## 4. Modul-Struktur (Domain-Driven)

```
app/
├─ Domains/
│  ├─ Workspace/           Tenant-Container, Members, Invitations
│  ├─ Domain/              Custom Domains, SSL-Provisioning
│  ├─ Link/                Short-Links, Variants (A/B)
│  ├─ QrCode/              QR-Generator, Templates, Renderers
│  ├─ Bio/                 Link-in-Bio Microsites
│  ├─ Analytics/           Click-Tracking, Rollups, Queries
│  ├─ Routing/             Smart-Routing Rule-Engine, A/B, Pixel-Inject
│  ├─ Subscription/        Stripe-Billing, Plan-Limits
│  ├─ Translation/         i18n Admin
│  ├─ Ai/                  Phase-1 AI-Suite
│  ├─ Webhook/             Outgoing-Webhooks
│  ├─ Api/                 REST-API-Layer
│  └─ Ads/                 Phase-3 (Meta + Google + TikTok)
├─ Http/
│  ├─ Controllers/         RedirectController (Hot-Path, KEIN Livewire)
│  ├─ Middleware/          ResolveWorkspace, EnforceLimits, LocaleFromUser
│  └─ Resources/           API-Transformers
├─ Livewire/
│  ├─ Layouts/             AppLayout, GuestLayout, PublicBioLayout
│  └─ Pages/               Per Domain
└─ Console/
   └─ Commands/            SyncStripe, ProvisionSsl, ResolveDomains, Rollups
```

**Architektur-Prinzipien:**

1. **Domain-Folder-Struktur** statt Type-Folders.
2. **Actions-Pattern** für alle Writes (`CreateLink`, `UpdateLink`, etc.).
3. **Alle Views via Livewire-Components.** Normale Controller nicht für Views nutzen. Ausnahme: `RedirectController` (kein View, nur 302-Response, Hot-Path).

---

## 5. Datenmodell

### Kern-Tabellen

```sql
-- USERS
users
├─ id, ulid, name, email (unique), password
├─ email_verified_at, two_factor_secret, two_factor_recovery
├─ locale (de/en), theme (dark/light/system)
├─ default_workspace_id (nullable, fk)
└─ timestamps, soft_deletes

-- WORKSPACES (Tenants)
workspaces
├─ id, ulid (unique, in URL), name, slug (display)
├─ owner_id (fk users)
├─ plan_id (fk plans), trial_ends_at
├─ branding (json: logo, primary_color, accent_color)
├─ stripe_id, stripe_customer_metadata (json)
└─ timestamps, soft_deletes

workspace_members
├─ id, workspace_id (fk), user_id (fk)
├─ role (enum: owner, admin, editor, viewer)
├─ invited_by, joined_at
└─ unique(workspace_id, user_id)

workspace_invitations
├─ id, workspace_id, email, role, token (unique)
├─ invited_by, expires_at, accepted_at
└─ timestamps

billing_profiles
├─ id, workspace_id (fk), billing_user_id (fk users)
├─ company_name (nullable), vat_number (nullable, VIES-validated)
├─ address_line_1, address_line_2, city, postal_code, country
├─ email_billing
└─ timestamps

-- DOMAINS
domains
├─ id, workspace_id (fk), hostname (unique)
├─ type (enum: short, bio, both)
├─ verified_at, verification_token
├─ ssl_status (pending/active/failed), ssl_issued_at, ssl_expires_at
├─ is_default (bool, true für system nimu.li)
└─ timestamps

-- LINKS
links
├─ id, ulid, workspace_id (fk), domain_id (fk, nullable → nimu.li default)
├─ slug (varchar 64, indexed mit domain_id unique)
├─ target_url (text)
├─ title, description, favicon_url
├─ status (active/disabled/expired)
├─ password (nullable, encrypted)
├─ expires_at, click_limit
├─ rules (json: smart-routing-config)
├─ pixel_config (json: meta_id, google_id, tiktok_id)
├─ tags (json array)
├─ created_by, updated_by
└─ timestamps, soft_deletes

link_variants                  -- A/B-Testing
├─ id, link_id (fk), label, target_url, weight
├─ clicks_count, conversions_count
└─ timestamps

-- QR CODES
qr_codes
├─ id, ulid, workspace_id, link_id (nullable für direct-QR)
├─ type (url/vcard/wifi/pdf/mp3/text)
├─ payload (json), style (json: colors, logo, frame)
├─ is_dynamic, scan_limit, expires_at
└─ timestamps, soft_deletes

-- LINK-IN-BIO
bio_pages
├─ id, ulid, workspace_id, domain_id (nullable)
├─ slug (unique mit domain_id), title, description, og_image
├─ theme (json), is_published
└─ timestamps, soft_deletes

bio_blocks
├─ id, bio_page_id (fk), position, type
├─ config (json: type-specific)
└─ timestamps

-- ANALYTICS (Raw, 90 Tage retention, monatlich partitioniert)
clicks
├─ id (bigint), link_id (fk), variant_id (nullable)
├─ workspace_id (denormalized)
├─ clicked_at (indexed)
├─ ip_hash (sha256 mit daily-rotating salt — DSGVO)
├─ country, city, device, os, browser
├─ referrer_host, referrer_path
├─ utm_source, utm_medium, utm_campaign, utm_content, utm_term, language
└─ append-only, no updates

-- ANALYTICS Rollups
clicks_hourly       (link_id, hour, country, device, count, unique_visitors)
clicks_daily        (link_id, day, country, count, unique_visitors)
clicks_by_referrer  (link_id, day, referrer_host, count)
clicks_by_utm       (link_id, day, utm_source, utm_medium, utm_campaign, count)

-- BILLING
plans
├─ id, name, stripe_price_id, monthly_price_cents
├─ workspace_limit, member_limit, custom_domain_limit
├─ link_limit, click_limit_monthly
└─ features (json)

subscriptions, subscription_items   (Cashier-Standard)

-- TRANSLATIONS
translations
├─ id, locale (de/en), key, value (text)
├─ group, namespace, updated_by
└─ unique(locale, namespace, group, key), INDEX(locale, group)

-- API + WEBHOOKS
api_tokens                          (Sanctum-Standard)
webhooks
├─ id, workspace_id, url, secret, events (json), is_active
└─ timestamps

webhook_deliveries
├─ id, webhook_id, event, payload, status, response_code, attempts
└─ timestamps

-- AUDIT
activity_log                        (Spatie-Standard)
```

### Redis-Keys

```
link:{slug}                          Hash (default nimu.li-Domain)
link:{domain_id}:{slug}              Hash (Custom-Domain)
  → target, status, rules_json, expires_at, workspace_id, pixel_config

clicks:{link_id}:{date}              Counter (INCR pro Klick)
clicks:{workspace_id}:monthly:{ym}   Counter für Plan-Enforcement

lang:{locale}                        Hash mit allen Translation-Keys
workspace:{ulid}                     Hash mit cached Settings

ratelimit:redirect:{ip}              Sliding-Window-Counter
session:{id}                         Laravel-Session

ab_sticky:{link_id}:{ip_hash}        ULID des Variants, TTL 24h
```

### Wichtige Constraints

- `(domain_id, slug)` unique — gleicher Slug auf verschiedenen Domains erlaubt
- `clicks` append-only
- Soft-Deletes auf User-Content
- Stripe-Customer auf `workspaces`, nie auf `users`
- IP-Adresse niemals roh — immer SHA256(ip + daily_salt) mit Salt-Rotation nach 24h

---

## 6. Redirect-Flow + Smart-Routing

### Request-Pipeline

```
1. GET https://nimu.li/x7k
2. nginx → app (Octane)
3. RedirectController::__invoke('x7k')
4. Domain-Resolve via Cache (Host-Header)
5. Redis HGETALL link:{domain_id}:{slug} (Fallback DB)
6. Pre-Checks: status, expires_at, click_limit, password, plan_click_limit
7. Bot-Detection (UA-Pattern, optional AbuseIPDB)
8. Smart-Routing-Resolve (Rules + Context: geo/device/os/time/lang/referrer/utm)
9. A/B-Variant-Pick mit Sticky-Hash (IP+Link, 24h Redis-TTL)
10. Pixel-Injection-Decision (Interstitial-HTML oder direkt 302)
11. Fire-and-forget Click-Event (Redis-INCR + Queue-Job)
12. 302-Response (Ziel <10ms p95)
```

### Smart-Routing Rule-Engine

JSON-Konfiguration pro Link mit Priorisierten Rules:

```json
{
  "rules": [
    {
      "id": "rule-1",
      "priority": 1,
      "conditions": [
        { "field": "device", "op": "in", "value": ["mobile"] },
        { "field": "os", "op": "equals", "value": "ios" }
      ],
      "match": "all",
      "target": "https://apps.apple.com/app/123"
    },
    {
      "id": "rule-2",
      "priority": 2,
      "conditions": [
        { "field": "country", "op": "in", "value": ["DE","AT","CH"] }
      ],
      "match": "all",
      "target": "https://example.de"
    }
  ],
  "fallback": "https://example.com"
}
```

**Rule-Fields:** `country`, `city`, `language`, `device`, `os`, `time_hour`, `weekday`, `date`, `referrer_host`, `utm_*`

**Operators:** `equals`, `not_equals`, `in`, `not_in`, `contains`, `starts_with`, `between`, `greater_than`, `less_than`

**Match-Modes:** `all` (AND), `any` (OR)

**Engine** evaluiert in Priority-Reihenfolge, erste Match gewinnt. Fallback wenn keine Match.

### Klick-Verarbeitung

```
RecordClickJob:
  1. INSERT INTO clicks (...)
  2. Broadcast(new ClickRecordedEvent($click)) → Reverb → Live-Dashboard
  3. Wenn Conversion-API enabled (Phase 2): SendMetaCapiJob, SendGoogleConversionJob
  4. Webhook-Trigger: workspace.webhooks where event='click.recorded'
```

### Rollup-Schedule

| Cron | Job |
|------|-----|
| every 15 min | RollupHourlyJob (clicks → clicks_hourly) |
| daily 02:00 | RollupDailyJob (clicks_hourly → clicks_daily) |
| daily 03:00 | PruneRawClicksJob (DELETE WHERE clicked_at < now()-90d) |
| daily 04:00 | CheckSslExpiryJob |
| hourly | VerifyPendingDomainsJob |
| weekly mon 09:00 | SendWeeklyInsightReportJob (AI-Feature) |
| 00:00, 06:00, 12:00, 18:00 | DatabaseBackupJob |

---

## 7. Multi-Tenancy

### Workspace-Modell

- Single-DB, `workspace_id` Foreign Key auf allen Workspace-Resourcen
- ULID statt sequenzieller ID in URL für Unguessability
- URL-Pattern: `app.nimuli.com/w/{workspace_ulid}/...`
- Solo-User: Auto-Redirect zu `default_workspace_ulid`
- Multi-Workspace-User (Agency): URL-Slug bestimmt aktiven Kontext, Multi-Tab-fähig

### Workspace-Rollen

| Rolle | Rechte |
|-------|--------|
| Owner | Alles + Billing + Workspace-Delete |
| Admin | Alles außer Billing + Workspace-Delete |
| Editor | Links/QR/Bio erstellen+bearbeiten+löschen |
| Viewer | Nur Lesen, Analytics |

### Plan-Limits (vorläufig)

| Plan | Workspaces/User | Members/Workspace | Custom Domains | Links | Klicks/Monat | Preis |
|------|----------------|-------------------|----------------|-------|--------------|-------|
| Free | 1 | 1 | 0 (nimu.li only) | 50 | 1.000 | 0€ |
| Pro | 1 | 3 | 1 | 1.000 | 25.000 | 19€ |
| Business | 3 | 10 | 5 | 10.000 | 250.000 | 79€ |
| Agency | unlimited | unlimited | unlimited | unlimited | 5M (pay-as-you-go danach) | 199€ |

---

## 8. Billing

### Stripe-Setup

- Stripe + Stripe Tax + PayPal als Method + SEPA-Lastschrift
- Customer pro Workspace (nicht pro User)
- Cashier für Subscription-Management
- Webhook-Endpoint mit Signature-Verify + Idempotency-Check

### Rechnungs-Konzept

- Rechnung zeigt **Billing-Profile-Daten** (User oder Firma) oben
- Custom-Field "Workspace": {workspace.name}
- Footer: "Bezahlt für Workspace: {workspace.name}"
- VAT-ID-Validation via VIES (EU-VAT-MOSS-Konformität)
- Reverse-Charge B2B intra-EU automatisch via Stripe Tax

### Plan-Enforcement

- Limit-Checks vor Action (Pre-Flight)
- Redis-Counter für Klick-Limit (real-time)
- Soft-Block bei 90% Klick-Limit (Warning), Hard-Block bei 100% (Redirect-Page "Plan-Limit erreicht")
- Owner-Email bei Limit-Hit + Upgrade-CTA

---

## 9. i18n + Translation-System

### DB-backed Translations

```
DB-Table: translations
├─ id, locale, namespace, group, key, value, updated_by
└─ unique(locale, namespace, group, key)

Redis:
  lang:de  → Hash { 'auth.login': 'Anmelden', ... }
  lang:en  → Hash { 'auth.login': 'Sign in', ... }
```

**Helper:**
```php
__('auth.login')
  → Redis HGET lang:{current_locale} auth.login
  → Fallback: DB → Cache → Lang-File
```

**Admin-UI:** Translation-Manager (CRUD über Keys, Diff-View zwischen Locales, Bulk-Import/Export, Missing-Key-Auto-Add bei `__()`-Call in Dev-Mode).

### Sprachen Phase 1

DE + EN. Phase 2 EU-Expansion: FR, ES, IT, NL.

### Model-Translations

`spatie/laravel-translatable` für Bio-Pages (multi-language Bio-Inhalte für internationale Brands).

---

## 10. Theme + Design-System

### Dual-Mode

- **Dark Mode (Default):** A-Style — CluPilot-inspiriert, Dark-Tech, Neon-Akzente, Mono-Zahlen
- **Light Mode:** B-Style — Vibrant-Modern, Gradients (Lila→Pink), friendly

### Tailwind v4 `@theme`

```css
@import "tailwindcss";

@theme {
    --color-bg: #0a0a0f;
    --color-s1: #111117;
    --color-s2: #16161e;
    --color-s3: #1c1c26;
    --color-b1: rgb(255 255 255 / 6%);
    --color-b2: rgb(255 255 255 / 10%);
    --color-t1: #f0f0f5;
    --color-t2: #8888a0;
    --color-t3: #44445a;
    --color-blue: #4f8ef7;
    --color-green: #3ecf8e;
    --color-amber: #f5a623;
    --color-red: #f05252;
    --font-mono: 'JetBrains Mono', monospace;
    --font-sans: 'Inter', sans-serif;
}

[data-theme="light"] {
    --color-bg: #ffffff;
    --color-s1: #ffffff;
    --color-s2: #f9fafb;
    --color-s3: #f3f4f6;
    --color-b1: #e5e7eb;
    --color-b2: #d1d5db;
    --color-t1: #111827;
    --color-t2: #6b7280;
    --color-t3: #9ca3af;
    --color-blue: #7c3aed;
    --color-green: #10b981;
    --color-amber: #f59e0b;
    --color-red: #ef4444;
}
```

**Custom-Style-Regel:** Keine Inline-Styles im Markup außer für Progressbar-Width-Berechnungen.

### Layout-Struktur

```
┌────────┬─────────────────────────────────────┐
│Sidebar │  Topbar (Workspace-Switcher,        │
│ 240px  │  Search, User-Menu, Theme-Toggle)   │
│fixed   │─────────────────────────────────────│
│        │                                     │
│ Logo   │  Content Area                       │
│ WS-Box │  (Livewire-Page-Component)          │
│ Nav    │                                     │
│ Plan   │                                     │
│  Box   │                                     │
└────────┴─────────────────────────────────────┘
```

Mobile (<768px): Sidebar als Drawer mit Hamburger.

### Mobile-First

- Default-Styles für Mobile, dann `md:`/`lg:` für Desktop
- Touch-Targets min 44×44px
- Drawer-Nav, Bottom-Action-Bars, Swipe-Gesten
- PWA-Manifest + Service-Worker (Offline-Read für Analytics)

---

## 11. Sicherheit + DSGVO

### Auth-Härtung

- Argon2id Passwort-Hashing
- 2FA via TOTP + Recovery-Codes
- Cookie-Flags: `secure`, `httpOnly`, `SameSite=Lax`
- Login-Rate-Limit 5/15min/IP
- Pwned-Password-Check via HaveIBeenPwned-API

### Workspace-Isolation

- Global Scope `workspace_id = current_workspace`
- Policies + Middleware-Check
- 404 statt 403 bei Cross-Workspace (Existenz nicht leaken)

### Input-Validation

- Mass-Assignment: `$guarded = ['id', 'workspace_id', 'created_by']` global
- Validierung via FormRequests
- HTMLPurifier auf User-Content (Bio-Blocks)
- SVG-Sanitizer auf Logo-Uploads
- File-Upload-Whitelist, Mime-Check, EXIF-Strip

### Webhooks

- HMAC-SHA256-Signatur `X-Nimuli-Signature` auf Outgoing
- SSRF-Schutz: private IP-Ranges blockiert (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16)
- Retry mit Exponential-Backoff (5 Versuche)

### Custom-Domain

- DNS-TXT-Record-Verifizierung
- Let's-Encrypt-ACME-SSL
- Renewal-Cron 30d vor Expiry mit Alerts

### Redirect-Härtung

- Rate-Limit 100 req/min/IP (Sliding-Window-Redis)
- Bot-Detection
- Google-Safe-Browsing-Check auf target_url bei Create + Daily-Re-Check
- Phishing-Domains werden auto-disabled

### DSGVO

- IP-Hash mit täglich-rotierendem Salt (24h irreversibel)
- Cookie-Banner-Logik in Bio-Pages (per Workspace-Setting)
- AVV-PDF auto-generierbar
- Datenexport (Art. 20): JSON-Bundle, Hintergrund-Job, Signed-URL 7d
- Recht auf Vergessen: 30d Soft-Delete → Hard-Delete
- Drittland-Transfers (Stripe, OpenAI/Anthropic, MaxMind): SCC + DPF aktiviert
- EU-Hosting (Hetzner DE)

### Security-Headers

- Strict-CSP, HSTS, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin

---

## 12. Backup + Disaster-Recovery

- `spatie/laravel-backup`
- 4× täglich MySQL-Dump (00:00, 06:00, 12:00, 18:00)
- Retention 14 Tage (= 56 Dumps gespeichert)
- Storage: Hetzner Storage Box (separate Region)
- Verschlüsselt
- Wöchentliche Restore-Drill auf Test-Instanz

---

## 13. Test-Strategie

| Layer | Tool | Ziel |
|-------|------|------|
| Unit | Pest | Actions, Resolvers, Rule-Engine |
| Feature | Pest | HTTP-Routes, Auth, Workspace-Scoping |
| Livewire | Pest + Livewire-Testing | Jede Page-Component, Forms, Actions |
| Integration | Pest | Stripe-Webhook (mocked), Email, Queue-Jobs |
| E2E | Pest 3 Browser | Critical-Paths: Register → Workspace → Link → Klick → Analytics |
| Performance | k6 | Redirect p95 <10ms, Dashboard <500ms |
| Security | OWASP-ZAP + manuell | Vor Launch |

**TDD-Approach:** Red-Green-Refactor, Test zuerst. 80%+ Coverage als Smell-Indikator.

**CI-Pipeline (GitHub Actions):**

```yaml
on: [push, pull_request]
jobs:
  test:
    - composer install
    - npm ci + npm run build
    - php artisan migrate (test DB)
    - vendor/bin/pest --parallel
    - php artisan pint --test
    - php artisan phpstan analyse
  deploy (on main):
    - SSH zu Hetzner
    - Pull, migrate, restart-Container
```

**Health-Checks:**
- `/health` endpoint: DB, Redis, Disk, Queue-Length
- UptimeRobot/BetterStack 1min-Polling
- Status-Page öffentlich (status.nimuli.com)

---

## 14. Phasen-Roadmap

**Hinweis:** Big-Bang-Launch Phase 1 (Wunsch des Users, kein Wave-Split). Total 12-16 Wochen Vollzeit.

### Phase 1 — Core + AI + API/Webhooks (12-16 Wochen)

**Inhalt:**
- Setup, Auth+2FA, Workspaces, Domains, Links, Analytics, Billing, Whitelabel, Theme-Switch, i18n
- Smart-Routing, A/B-Testing, Link-Schutz, Pixel-Injection, QR-Codes, Link-in-Bio
- AI-Suite (Auto-Slug, A/B-Generator, A/B-Explainer, Routing-per-Prompt, Anomalie-Detection, Insight-Report)
- API v1 (REST + Sanctum + Rate-Limit per Plan) + Outgoing-Webhooks

**Launch-Kriterien:**
- Stripe Live-Mode, 4 Pläne kaufbar
- DSGVO-Audit clean (AVV, Datenschutz, Cookie-Logik)
- Sentry, Uptime-Monitor, Status-Page
- Onboarding-Tour, Email-Sequenzen, Hilfe-Docs

### Phase 2 — 3rd-Party Integrationen (6-8 Wochen)

- Zapier-App-Listing
- Make.com-Modules
- Slack OAuth + Notifications
- Discord Webhooks
- Shopify-App-Listing
- Conversion-API: Meta CAPI + Google Enhanced Conversions Server-Side

### Phase 2.5 (parallel) — Mobile App iOS+Android

- React Native + Expo
- Features: Login, Workspace-Switch, Quick-Link-Create (Share-Extension), Analytics-Read-Only, Push-Notifications, QR-Scanner
- Push-Service: Expo Push oder Firebase FCM

### Phase 3 — Ads-Management (10-14 Wochen)

- Meta OAuth + Ad-Read + Ad-Create + CAPI-Full
- Google Ads OAuth + Read + Create + Enhanced Conversions
- TikTok Ads (optional)
- Unified Campaign-View Cross-Platform
- Budget-Alerts + Auto-Pause-Rules (CPL-basiert)

### Post-Phase-3 (Optional/On-Demand)

- ClickHouse-Migration bei >50M Klicks/Monat
- Edge-Redirects via Cloudflare Workers (globale Latenz <50ms)
- Marketplace für Bio-Templates (Revenue-Share)
- White-Label-Reseller-Tier
- Custom-Reports-Builder (Drag-Drop)

---

## 15. Risiken + Mitigations

| Risiko | Likelihood | Impact | Mitigation |
|--------|-----------|--------|-----------|
| Spam/Phishing-Missbrauch | hoch | hoch | Safe-Browsing-Check, Manual-Review-Queue für Free-Tier, Account-Auto-Suspend |
| DDoS auf Redirects | mittel | hoch | Rate-Limit Redis, LB-DDoS-Schutz, später Cloudflare-Edge |
| MySQL überlastet bei Klick-Spike | mittel | mittel | INSERT async via Queue, Rollups, Plan-Click-Limits |
| Custom-Domain SSL läuft ab | hoch | mittel | Cron-Renewal 30/14/7/1d-Alerts |
| OpenAI/Anthropic-API-Ausfall | mittel | niedrig | Graceful Degradation, Core läuft weiter |
| Stripe-Webhook-Verlust | niedrig | mittel | Idempotency-Store + Daily-Reconciliation-Job |
| Hetzner-Ausfall / DB-Korruption | niedrig | hoch | 4×/Tag Backup, 14d Retention, separate Region, Wochen-Restore-Drill |
| Konkurrenz launcht ähnliches AI-Feature | hoch | mittel | Iterations-Tempo, Agency-Nische-Fokus |
| Solo-Dev-Burnout (Big-Bang 16 Wochen) | hoch | hoch | Vom User akzeptiert; trotzdem regelmäßige Checkpoints, MVP-Mindset |
| GDPR-Klage Pixel-Injection | mittel | hoch | Consent-Banner Pflicht-Feature, AVV, transparente Datenschutzerklärung |

---

## 16. Offene Punkte für Implementation-Plan

Diese Details werden im Implementation-Plan konkretisiert:

- Exakte Migrationen-Reihenfolge
- Konkrete Route-Definitionen (Web + API)
- Konkrete Livewire-Component-Liste mit View-Pfaden
- AI-Provider-Wahl (Anthropic Claude vs. OpenAI vs. beide via Adapter-Pattern)
- Reverb-Channel-Definitionen + Authorization-Logic
- Stripe-Product/Price-Setup-Skript
- Seed-Daten für Demo-Workspace
- E-Mail-Template-Liste
- Onboarding-Tour-Steps
- Marketing-Site (`nimuli.com`) — Stack: Statisches Astro/Next oder Teil der App?

---

## 17. Erfolgs-Kriterien Spec

- [x] Architektur klar (Dev + Prod)
- [x] Stack festgelegt
- [x] Modul-Struktur dokumentiert
- [x] Datenmodell komplett
- [x] Redirect-Pipeline beschrieben
- [x] Multi-Tenancy-Modell klar
- [x] Billing-Konzept (inkl. Rechnungs-Anzeige)
- [x] i18n-System mit DB+Redis
- [x] Theme + Tailwind-Setup
- [x] Sicherheit + DSGVO
- [x] Backup-Strategie
- [x] Test-Strategie
- [x] Phasen-Roadmap
- [x] Risiken + Mitigations

**Spec-Status:** Bereit für `writing-plans`-Skill zur Erstellung des Implementation-Plans.