diff --git a/CLAUDE.md b/CLAUDE.md
index 05a55a0..1dfd553 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -17,236 +17,74 @@ Multi-Tenant CMS für 3 aktive Websites unter einer Payload CMS 3.x Instanz:
- **Runtime:** Node.js 22.x
- **Datenbank:** PostgreSQL 17.6 (separater Server)
- **Connection Pool:** PgBouncer 1.24.1 (Transaction-Mode)
-- **Reverse Proxy:** Caddy 2.9.x mit Let's Encrypt (Dev) / Nginx (Prod)
+- **Reverse Proxy:** Caddy 2.9.x (Dev) / Nginx (Prod)
- **Process Manager:** PM2
- **Package Manager:** pnpm
-- **Cache:** Redis 7.x (optional, mit In-Memory-Fallback)
+- **Cache:** Redis 7.x (optional, In-Memory-Fallback)
- **Job Queue:** BullMQ (Redis-basiert)
- **Analytics:** Umami 3.x
-- **AI Tools:** Claude Code, Codex CLI, Gemini CLI
## Architektur
-### Development (VLAN 181 - porwoll.tech)
+**Development:** `Internet → Cloudflare → Caddy (sv-caddy) → sv-payload:3000 → PgBouncer:6432 → PostgreSQL (sv-postgres:5432)`
-```
-Internet → Cloudflare → 37.24.237.181 → Caddy (sv-caddy) → Services
- ↓
- ┌───────────────────────────┴───────────────────────────┐
- │ │
- sv-payload:3000 sv-frontend:3000-3008
- (Payload CMS) (9 Frontend-Projekte)
- │
- PgBouncer (6432)
- │
- PostgreSQL (sv-postgres:5432)
-```
+| Hostname | IP | Service |
+|----------|-----|---------|
+| sv-caddy | 10.10.181.99 | Caddy Reverse Proxy |
+| sv-payload | 10.10.181.100 | Payload CMS + Redis |
+| sv-postgres | 10.10.181.101 | PostgreSQL 17 |
+| sv-frontend | 10.10.181.104 | Multi-Frontend Dev (9 Projekte) |
-| LXC | Hostname | IP | Service | Status |
-|-----|----------|-----|---------|--------|
-| 699 | sv-caddy | 10.10.181.99 | Caddy Reverse Proxy | ✅ Running |
-| 700 | sv-payload | 10.10.181.100 | Payload CMS + Redis | ✅ Running |
-| 701 | sv-postgres | 10.10.181.101 | PostgreSQL 17 + Redis Commander | ✅ Running |
-| 702 | sv-dev-payload | 10.10.181.102 | Payload Experimental | ⏸️ Stopped |
-| 703 | sv-analytics | 10.10.181.103 | Umami Analytics | ✅ Running |
-| 704 | sv-frontend | 10.10.181.104 | Multi-Frontend Dev (9 Projekte) | ✅ Running |
+**Production (Hetzner 3):** `cms.c2sgmbh.de:3001` (Payload), `analytics.c2sgmbh.de:3000` (Umami)
-### Production (Hetzner 3)
+→ Details: `docs/INFRASTRUCTURE.md`
-| Service | URL | Port |
-|---------|-----|------|
-| Payload CMS | https://cms.c2sgmbh.de | 3001 |
-| Umami Analytics | https://analytics.c2sgmbh.de | 3000 |
-| PostgreSQL 17 | localhost | 5432 |
-| Redis Cache | localhost | 6379 |
+## Multi-Tenant
-## Wichtige Pfade
+Verwendet `@payloadcms/plugin-multi-tenant`.
-```
-/home/payload/payload-cms/ # Projektroot
-├── src/
-│ ├── payload.config.ts # Haupt-Konfiguration
-│ ├── collections/ # Alle Collections
-│ │ ├── Users.ts
-│ │ ├── Media.ts
-│ │ ├── Tenants.ts
-│ │ ├── Posts.ts
-│ │ ├── Categories.ts
-│ │ ├── Portfolios.ts
-│ │ ├── PortfolioCategories.ts
-│ │ ├── FAQs.ts
-│ │ ├── Team.ts
-│ │ ├── ServiceCategories.ts
-│ │ ├── Services.ts
-│ │ ├── EmailLogs.ts
-│ │ ├── AuditLogs.ts
-│ │ └── ...
-│ ├── app/(payload)/api/ # Custom API Routes
-│ │ ├── users/login/route.ts # Custom Login mit Audit
-│ │ ├── send-email/route.ts
-│ │ ├── email-logs/
-│ │ │ ├── export/route.ts
-│ │ │ └── stats/route.ts
-│ │ └── test-email/route.ts
-│ ├── lib/
-│ │ ├── email/ # E-Mail-System
-│ │ │ ├── tenant-email-service.ts
-│ │ │ ├── payload-email-adapter.ts
-│ │ │ ├── newsletter-service.ts # Newsletter Double Opt-In
-│ │ │ └── newsletter-templates.ts # E-Mail-Templates
-│ │ ├── security/ # Security-Module
-│ │ │ ├── rate-limiter.ts
-│ │ │ ├── csrf.ts
-│ │ │ ├── ip-allowlist.ts
-│ │ │ └── data-masking.ts
-│ │ ├── queue/ # BullMQ Job Queue
-│ │ │ ├── queue-service.ts
-│ │ │ ├── jobs/email-job.ts
-│ │ │ ├── jobs/pdf-job.ts
-│ │ │ ├── workers/email-worker.ts
-│ │ │ └── workers/pdf-worker.ts
-│ │ ├── pdf/ # PDF-Generierung
-│ │ │ └── pdf-service.ts
-│ │ ├── search.ts # Volltextsuche
-│ │ └── redis.ts # Redis Cache Client
-│ └── hooks/ # Collection Hooks
-│ ├── sendFormNotification.ts
-│ ├── sendNewsletterConfirmation.ts # Newsletter Double Opt-In
-│ ├── invalidateEmailCache.ts
-│ └── auditLog.ts
-├── tests/ # Test Suite
-│ ├── unit/security/ # Security Unit Tests
-│ └── int/ # Integration Tests
-├── scripts/
-│ ├── run-queue-worker.ts # Queue Worker Starter
-│ └── backup/ # Backup-System
-│ ├── backup-db.sh # PostgreSQL Backup-Skript
-│ ├── restore-db.sh # PostgreSQL Restore-Skript
-│ ├── setup-backup.sh # Interaktives Setup
-│ └── README.md # Backup-Dokumentation
-├── .env # Umgebungsvariablen
-├── ecosystem.config.cjs # PM2 Config
-└── .next/ # Build Output
-```
-
-## Umgebungsvariablen (.env)
-
-> **Hinweis:** Sensible Credentials (DB_PASSWORD, SMTP_PASS, etc.) werden aus `~/.pgpass`
-> und Umgebungsvariablen gelesen. Niemals Klartext-Passwörter in diese Datei schreiben!
-
-```env
-# Datenbank (Passwort in ~/.pgpass oder als Umgebungsvariable)
-DATABASE_URI=postgresql://payload:${DB_PASSWORD}@127.0.0.1:6432/payload_db
-PAYLOAD_SECRET=a53b254070d3fffd2b5cfcc3
-PAYLOAD_PUBLIC_SERVER_URL=https://pl.porwoll.tech
-NEXT_PUBLIC_SERVER_URL=https://pl.porwoll.tech
-NODE_ENV=production
-PORT=3000
-
-# E-Mail (Global Fallback)
-SMTP_HOST=smtp.example.com
-SMTP_PORT=587
-SMTP_SECURE=false
-SMTP_USER=user@example.com
-SMTP_PASS=secret
-SMTP_FROM_ADDRESS=noreply@c2sgmbh.de
-SMTP_FROM_NAME=Payload CMS
-
-# Redis Cache
-REDIS_URL=redis://localhost:6379
-
-# Security
-CSRF_SECRET=your-csrf-secret # PFLICHT in Production (oder PAYLOAD_SECRET)
-TRUST_PROXY=true # PFLICHT hinter Reverse-Proxy (Caddy/Nginx)
-SEND_EMAIL_ALLOWED_IPS= # Optional: Komma-separierte IPs/CIDRs
-ADMIN_ALLOWED_IPS= # Optional: IP-Beschränkung für Admin-Panel
-BLOCKED_IPS= # Optional: Global geblockte IPs
-
-# Meta (Facebook + Instagram) OAuth
-META_APP_ID=your-app-id # Facebook App ID
-META_APP_SECRET=your-app-secret # Facebook App Secret
-META_REDIRECT_URI=https://your-domain/api/auth/meta/callback
-
-# YouTube OAuth (existing)
-GOOGLE_CLIENT_ID=your-client-id # Google Cloud Console
-GOOGLE_CLIENT_SECRET=your-client-secret
-YOUTUBE_REDIRECT_URI=https://your-domain/api/youtube/callback
-
-# Cron Jobs
-CRON_SECRET=your-64-char-hex # Auth für Cron-Endpoints
-```
-
-## PgBouncer Connection Pooling
-
-PgBouncer läuft auf dem App-Server und pooled Datenbankverbindungen:
-
-```bash
-# Konfiguration
-/etc/pgbouncer/pgbouncer.ini
-/etc/pgbouncer/userlist.txt # chmod 600
-
-# Service
-sudo systemctl status pgbouncer
-sudo systemctl restart pgbouncer
-
-# Statistiken abfragen
-# Pool-Statistiken (Passwort aus ~/.pgpass)
-PGPASSWORD="$DB_PASSWORD" psql -h 127.0.0.1 -p 6432 -U payload -d pgbouncer -c "SHOW POOLS;"
-PGPASSWORD="$DB_PASSWORD" psql -h 127.0.0.1 -p 6432 -U payload -d pgbouncer -c "SHOW STATS;"
-```
-
-**Konfiguration:**
-| Parameter | Wert | Beschreibung |
-|-----------|------|--------------|
-| pool_mode | transaction | Verbindung wird nach Transaktion freigegeben |
-| default_pool_size | 20 | Standard-Pool-Größe pro DB/User |
-| min_pool_size | 5 | Mindestens gehaltene Verbindungen |
-| reserve_pool_size | 5 | Reserve für Lastspitzen |
-| max_db_connections | 50 | Max. Verbindungen zu PostgreSQL |
-| max_client_conn | 200 | Max. Clients zu PgBouncer |
-
-**Verbindungen:**
-- App → PgBouncer: `127.0.0.1:6432` (DATABASE_URI)
-- PgBouncer → PostgreSQL: `10.10.181.101:5432` (TLS 1.3, `server_tls_sslmode = require`)
-
-**Direkte Verbindung (für Migrationen/CLI):**
-
-PgBouncer im Transaction-Mode kann Probleme mit lang laufenden Migrationen verursachen.
-Für solche Fälle das `db-direct.sh` Skript verwenden:
-
-```bash
-# Migrationen direkt an PostgreSQL (umgeht PgBouncer)
-./scripts/db-direct.sh migrate
-
-# Interaktive psql-Session
-./scripts/db-direct.sh psql
-
-# Schema-Änderungen
-./scripts/db-direct.sh migrate:create
-```
-
-Das Skript liest Credentials aus `~/.pgpass` (chmod 600).
-
-## Multi-Tenant Plugin
-
-Verwendet `@payloadcms/plugin-multi-tenant` für Mandantenfähigkeit.
-
-**Aktuelle Tenants:**
| ID | Name | Slug |
|----|------|------|
| 1 | porwoll.de | porwoll |
| 4 | Complex Care Solutions GmbH | c2s |
| 5 | Gunshin | gunshin |
-**User-Tenant-Zuweisung:** Tabelle `users_tenants`
+User-Tenant-Zuweisung: Tabelle `users_tenants`
+
+## Wichtige Pfade
+
+```
+/home/payload/payload-cms/
+├── src/
+│ ├── payload.config.ts # Haupt-Konfiguration
+│ ├── collections/ # Alle Collections (55+)
+│ ├── app/(payload)/api/ # Custom API Routes
+│ ├── lib/
+│ │ ├── email/ # E-Mail-System (tenant-spezifisch)
+│ │ ├── security/ # Rate-Limiter, CSRF, IP-Allowlist
+│ │ ├── queue/ # BullMQ Jobs & Workers
+│ │ ├── pdf/ # PDF-Generierung
+│ │ ├── retention/ # Data Retention (DSGVO)
+│ │ ├── integrations/meta/ # Facebook + Instagram API
+│ │ ├── jobs/ # UnifiedSyncService, JobLogger
+│ │ ├── search.ts # Volltextsuche
+│ │ └── redis.ts # Redis Cache Client
+│ └── hooks/ # Collection Hooks
+├── tests/ # Unit & Integration Tests
+├── scripts/
+│ ├── db-direct.sh # Direkte DB-Verbindung (umgeht PgBouncer)
+│ ├── sync-schema.sh # Schema-Sync nach Collection-Änderungen
+│ └── backup/ # Backup-System (→ scripts/backup/README.md)
+├── .env # Umgebungsvariablen
+├── ecosystem.config.cjs # PM2 Config
+└── .github/workflows/ # CI/CD Pipelines
+```
## Wichtige Befehle
```bash
# Entwicklung
pnpm dev
-
-# Production Build
pnpm build
# Migrationen
@@ -261,116 +99,56 @@ pnpm payload migrate
pnpm payload generate:importmap
# PM2
-pm2 status
-pm2 logs payload
-pm2 logs queue-worker
-pm2 restart payload
-pm2 restart queue-worker
+pm2 status | pm2 logs payload | pm2 restart payload
+pm2 logs queue-worker | pm2 restart queue-worker
# Tests
-pnpm test # Alle Tests
-pnpm test:security # Security Tests
-pnpm test:access-control # Access Control Tests
-pnpm test:coverage # Mit Coverage-Report
+pnpm test # Alle Tests
+pnpm test:security # Security Tests
+pnpm test:access-control # Access Control Tests
+pnpm test:coverage # Mit Coverage-Report
+
+# Lint & Format
+pnpm lint # ESLint
+pnpm typecheck # TypeScript Check (4GB heap)
+pnpm format:check # Prettier Check
+pnpm format # Prettier Auto-Fix
+
+# Direkte DB-Verbindung (umgeht PgBouncer für Migrationen)
+./scripts/db-direct.sh migrate
+./scripts/db-direct.sh psql
# Backup
-/home/payload/backups/postgres/backup-db.sh --verbose # Manuelles Backup
-scripts/backup/setup-backup.sh # Backup-System einrichten
+/home/payload/backups/postgres/backup-db.sh --verbose
```
-## Git Branching Workflow
+## Git Workflow
-**Wichtig:** Immer zuerst auf `develop` entwickeln, nach Freigabe mit `main` mergen.
-
-```
-develop ──────●────●────●────────●────── (Entwicklung)
- \ /
-main ────────●────────────●────────── (Production)
-```
-
-### Branches
+**Regel:** Immer auf `develop` entwickeln, nach Freigabe nach `main` mergen.
| Branch | Zweck | Deployment |
|--------|-------|------------|
| `develop` | Aktive Entwicklung | Staging (pl.porwoll.tech) |
| `main` | Stabile Version | Production (cms.c2sgmbh.de) |
-| `feature/*` | Feature-Branches | Lokal / PR nach develop |
+| `feature/*` | Feature-Branches | PR nach develop |
-### Entwicklungs-Workflow
+**Commit-Konventionen:** `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`
-1. **Auf develop arbeiten:**
- ```bash
- git checkout develop
- git pull origin develop
- ```
+**Workflow nach Code-Änderungen:**
+1. Code ändern (auf `develop`)
+2. `pnpm build` → `pm2 restart payload`
+3. Bei Collection-Änderungen zusätzlich: `pnpm payload migrate:create`
-2. **Änderungen committen:**
- ```bash
- git add .
- git commit -m "feat/fix/docs: beschreibung"
- git push origin develop
- ```
+## KRITISCH: Neue Collections hinzufügen
-3. **Nach Freigabe: develop → main mergen:**
- ```bash
- git checkout main
- git pull origin main
- git merge develop
- git push origin main
- ```
+Payload CMS verwendet `payload_locked_documents_rels` für Document-Locks. Diese Tabelle benötigt eine `{collection}_id` Spalte für JEDE Collection. Ohne → RSC-Fehler nach Login:
-4. **develop aktuell halten (falls main Hotfixes hat):**
- ```bash
- git checkout develop
- git merge main
- git push origin develop
- ```
-
-### Commit-Konventionen
-
-| Prefix | Verwendung |
-|--------|------------|
-| `feat:` | Neue Features |
-| `fix:` | Bug-Fixes |
-| `docs:` | Dokumentation |
-| `refactor:` | Code-Refactoring |
-| `test:` | Tests |
-| `chore:` | Maintenance |
-
----
-
-## Workflow nach Code-Änderungen
-
-1. Code ändern (auf `develop` Branch)
-2. `pnpm build`
-3. `pm2 restart payload`
-4. Testen unter https://pl.porwoll.tech/admin
-
-### Bei Collection/Global-Änderungen (zusätzlich)
-
-1. `pnpm payload migrate:create` - Migration erstellen
-2. `git add src/migrations/` - Migration committen
-3. Auf PROD nach Deployment: `./scripts/sync-schema.sh` wird automatisch ausgeführt
-
-### ⚠️ KRITISCH: Neue Collections hinzufügen
-
-Beim Hinzufügen einer neuen Collection müssen **System-Tabellen** manuell aktualisiert werden!
-
-**Problem:** Payload CMS verwendet `payload_locked_documents_rels` um Document-Locks über alle Collections zu tracken. Diese Tabelle benötigt eine `{collection}_id` Spalte für JEDE Collection. Ohne diese Spalte tritt nach dem Login ein RSC-Fehler auf:
```
-Error: An error occurred in the Server Components render
-caused by: column payload_locked_documents_rels.{collection}_id does not exist
+column payload_locked_documents_rels.{collection}_id does not exist
```
-**Lösung:** Die Migration für eine neue Collection MUSS folgendes enthalten:
-
+**Migration MUSS enthalten:**
```sql
--- 1. Collection-Tabellen erstellen (normal)
-CREATE TABLE IF NOT EXISTS "{collection}" (...);
-CREATE TABLE IF NOT EXISTS "{collection}_rels" (...); -- falls benötigt
-CREATE TABLE IF NOT EXISTS "{collection}_locales" (...); -- falls lokalisiert
-
--- 2. KRITISCH: System-Tabelle aktualisieren!
ALTER TABLE "payload_locked_documents_rels"
ADD COLUMN IF NOT EXISTS "{collection}_id" integer
REFERENCES {collection}(id) ON DELETE CASCADE;
@@ -379,1115 +157,245 @@ CREATE INDEX IF NOT EXISTS "payload_locked_documents_rels_{collection}_idx"
ON "payload_locked_documents_rels" ("{collection}_id");
```
-**Beispiel-Migration:** `src/migrations/20260109_020000_add_blogwoman_collections.ts`
+Beispiel: `src/migrations/20260109_020000_add_blogwoman_collections.ts`
-**Array-Felder:** Collections mit Array-Feldern (z.B. `hours_structured` in Locations) benötigen zusätzliche Tabellen:
-```sql
-CREATE TABLE IF NOT EXISTS "{collection}_{array_field}" (
- "id" serial PRIMARY KEY NOT NULL,
- "_order" integer NOT NULL,
- "_parent_id" integer NOT NULL REFERENCES {collection}(id) ON DELETE CASCADE,
- -- Array-Feld-Spalten hier
-);
-```
+**Array-Felder:** Collections mit Arrays benötigen zusätzliche `{collection}_{array_field}` Tabellen.
-## Bekannte Besonderheiten
+## Bekannte Besonderheiten & Gotchas
-- **ES Modules:** package.json hat `"type": "module"`, daher PM2 Config als `.cjs`
-- **Plugin ImportMap:** Nach Plugin-Änderungen `pnpm payload generate:importmap` ausführen
+- **ES Modules:** `"type": "module"` in package.json → PM2 Config als `.cjs`
+- **Plugin ImportMap:** Nach Plugin-Änderungen `pnpm payload generate:importmap`
- **User-Tenant-Zuweisung:** Neue User müssen manuell Tenants zugewiesen bekommen
-- **Admin Login:** Custom Route mit Audit-Logging, unterstützt JSON und `_payload` FormData
-- **Queue Worker:** Benötigt `tsx` als explizite devDependency (für TypeScript-Ausführung via PM2)
+- **Admin Login:** Custom Route mit Audit-Logging (`src/app/(payload)/api/users/login/route.ts`)
+- **Queue Worker:** Benötigt `tsx` als devDependency (TypeScript via PM2)
+- **PgBouncer:** Transaction-Mode kann Migrationen stören → `./scripts/db-direct.sh`
+- **TRUST_PROXY=true:** PFLICHT hinter Reverse-Proxy, sonst funktionieren Rate-Limiting und IP-Allowlists nicht
+- **CSRF_SECRET:** PFLICHT in Production (oder PAYLOAD_SECRET) - Server startet nicht ohne
## Build-Konfiguration
-Der Build ist für speichereffizientes Kompilieren optimiert:
-
- `package.json`: `--max-old-space-size=2048` (2GB Heap-Limit)
- `next.config.mjs`: `experimental.cpus: 1`, `workerThreads: false`
-**WICHTIG:** Der Server hat 8GB RAM ohne Swap. Bei laufendem VS Code Server kann der Build mit reduziertem Memory ausgeführt werden:
-
+**Server hat 8GB RAM ohne Swap.** Bei laufendem VS Code kann Build OOM werden:
```bash
-pm2 stop payload # Speicher freigeben
+pm2 stop payload
NODE_OPTIONS="--no-deprecation --max-old-space-size=1024" ./node_modules/.bin/next build
pm2 start payload
```
-Ohne PM2-Stop und mit VS Code wird der Build vom OOM Killer beendet (Exit code 137).
+## Mehrsprachigkeit
-## Mehrsprachigkeit (i18n)
-
-Das System unterstützt Deutsch (default) und Englisch:
-
-- **Admin UI:** `@payloadcms/translations` für DE/EN
-- **Content:** Localization mit Fallback auf Deutsch
-- **Datenbank:** `_locales` Tabellen für lokalisierte Felder
-- **API:** `?locale=de` oder `?locale=en` Parameter
-- **Frontend:** Routing über `/[locale]/...`
+Deutsch (default) + Englisch. API: `?locale=de|en`. DB: `_locales` Tabellen.
## URLs
-- **Admin Panel:** https://pl.porwoll.tech/admin
-- **API:** https://pl.porwoll.tech/api
-- **API-Dokumentation (Swagger UI):** https://pl.porwoll.tech/api/docs
-- **OpenAPI JSON:** https://pl.porwoll.tech/api/openapi.json
-- **E-Mail API:** https://pl.porwoll.tech/api/send-email (POST, Auth erforderlich)
-- **Test-E-Mail:** https://pl.porwoll.tech/api/test-email (POST, Admin erforderlich)
-- **E-Mail Stats:** https://pl.porwoll.tech/api/email-logs/stats (GET, Auth erforderlich)
-- **PDF-Generierung:** https://pl.porwoll.tech/api/generate-pdf (POST/GET, Auth erforderlich)
-- **Newsletter Anmeldung:** https://pl.porwoll.tech/api/newsletter/subscribe (POST, öffentlich)
-- **Newsletter Bestätigung:** https://pl.porwoll.tech/api/newsletter/confirm (GET/POST)
-- **Newsletter Abmeldung:** https://pl.porwoll.tech/api/newsletter/unsubscribe (GET/POST)
-- **Timeline API:** https://pl.porwoll.tech/api/timelines (GET, öffentlich, tenant required)
-- **Workflows API:** https://pl.porwoll.tech/api/workflows (GET, öffentlich, tenant required)
-- **Data Retention API:** https://pl.porwoll.tech/api/retention (GET/POST, Super-Admin erforderlich)
-- **YouTube Analytics:** https://pl.porwoll.tech/admin/youtube-analytics (Admin View, Auth erforderlich)
-- **Community Inbox:** https://pl.porwoll.tech/admin/community/inbox (Admin View, Auth erforderlich)
-- **Community Analytics:** https://pl.porwoll.tech/admin/community/analytics (Admin View, Auth erforderlich)
-- **Community Sync:** https://pl.porwoll.tech/api/community/sync (POST: Trigger, GET: Status)
-- **Community Stats:** https://pl.porwoll.tech/api/community/stats (GET, Auth erforderlich)
-- **Meta OAuth:** https://pl.porwoll.tech/api/auth/meta (GET, startet OAuth-Flow)
-- **YouTube Thumbnail Bulk:** https://pl.porwoll.tech/api/youtube/thumbnails/bulk (POST, Super-Admin)
-
-## Security-Features
-
-### Proxy-Vertrauen (TRUST_PROXY)
-**WICHTIG:** Wenn die App hinter einem Reverse-Proxy läuft (Caddy, Nginx, etc.),
-muss `TRUST_PROXY=true` gesetzt sein:
-
-```env
-TRUST_PROXY=true
-```
-
-Ohne diese Einstellung:
-- Werden `X-Forwarded-For` und `X-Real-IP` Header ignoriert
-- Können Angreifer IP-basierte Sicherheitsmaßnahmen nicht umgehen
-- Aber: Rate-Limiting und IP-Allowlists funktionieren nicht korrekt
-
-### Rate-Limiting
-Zentraler Rate-Limiter mit vordefinierten Limits:
-- `publicApi`: 60 Requests/Minute
-- `auth`: 5 Requests/15 Minuten (Login)
-- `email`: 10 Requests/Minute
-- `search`: 30 Requests/Minute
-- `form`: 5 Requests/10 Minuten
-
-**Hinweis:** Rate-Limiting basiert auf Client-IP. Bei `TRUST_PROXY=false` wird
-`direct-connection` als IP verwendet, was alle Clients zusammenfasst.
-
-### CSRF-Schutz
-- Double Submit Cookie Pattern
-- Origin-Header-Validierung
-- Token-Endpoint: `GET /api/csrf-token`
-- Admin-Panel hat eigenen CSRF-Schutz
-- **CSRF_SECRET oder PAYLOAD_SECRET ist in Production PFLICHT**
-- Server startet nicht ohne Secret in Production
-
-### IP-Allowlist
-- Konfigurierbar via `SEND_EMAIL_ALLOWED_IPS`, `ADMIN_ALLOWED_IPS`
-- Unterstützt IPs, CIDRs (`192.168.1.0/24`) und Wildcards (`10.10.*.*`)
-- Globale Blocklist via `BLOCKED_IPS`
-- **Warnung:** Leere Allowlists erlauben standardmäßig alle IPs
-
-### Data-Masking
-- Automatische Maskierung sensibler Daten in Logs
-- Erkennt Passwörter, Tokens, API-Keys, SMTP-Credentials
-- Safe-Logger-Factory für konsistentes Logging
-
-## E-Mail-System
-
-Multi-Tenant E-Mail-System mit tenant-spezifischer SMTP-Konfiguration:
-
-**Architektur:**
-- Globaler SMTP als Fallback (via .env)
-- Tenant-spezifische SMTP in Tenants Collection
-- Transporter-Caching mit automatischer Invalidierung
-- EmailLogs Collection für Audit-Trail
-
-**Tenant E-Mail-Konfiguration:**
-```
-Tenants → email → fromAddress, fromName, replyTo
- → email → useCustomSmtp (Checkbox)
- → email → smtp → host, port, secure, user, pass
-```
-
-**API-Endpoint `/api/send-email`:**
-```bash
-curl -X POST https://pl.porwoll.tech/api/send-email \
- -H "Content-Type: application/json" \
- -H "Cookie: payload-token=..." \
- -d '{
- "to": "empfaenger@example.com",
- "subject": "Betreff",
- "html": "
Inhalt
",
- "tenantId": 1
- }'
-```
-
-**Sicherheit:**
-- Authentifizierung erforderlich
-- Tenant-Zugriffskontrolle (User muss Tenant-Mitglied sein)
-- Rate-Limiting: 10 E-Mails/Minute pro User
-- SMTP-Passwort nie in API-Responses
-
-### Newsletter Double Opt-In
-
-DSGVO-konformes Newsletter-System mit Double Opt-In:
-
-**Flow:**
-1. User meldet sich an → Status: `pending`, Token wird generiert
-2. Double Opt-In E-Mail wird automatisch gesendet
-3. User klickt Bestätigungs-Link → Status: `confirmed`
-4. Willkommens-E-Mail wird gesendet
-5. Abmeldung jederzeit über Link in E-Mails möglich
-
-**API-Endpoints:**
-
-```bash
-# Newsletter-Anmeldung
-curl -X POST https://pl.porwoll.tech/api/newsletter/subscribe \
- -H "Content-Type: application/json" \
- -d '{
- "email": "user@example.com",
- "firstName": "Max",
- "tenantId": 1,
- "source": "footer"
- }'
-
-# Bestätigung (via Link aus E-Mail)
-GET https://pl.porwoll.tech/api/newsletter/confirm?token=
-
-# Abmeldung (via Link aus E-Mail)
-GET https://pl.porwoll.tech/api/newsletter/unsubscribe?token=
-```
-
-**Features:**
-- Automatischer E-Mail-Versand bei Anmeldung
-- Token-Ablauf nach 48 Stunden
-- Willkommens-E-Mail nach Bestätigung
-- Abmelde-Bestätigung per E-Mail
-- Rate-Limiting: 5 Anmeldungen/10 Minuten pro IP
-- Erneute Anmeldung nach Abmeldung möglich
-
-## BullMQ Job Queue
-
-Das System verwendet BullMQ für asynchrone Job-Verarbeitung mit Redis als Backend.
-
-### PM2 Worker
-
-Der Queue-Worker läuft als separater PM2-Prozess:
-
-```bash
-# Worker-Status prüfen
-pm2 status
-pm2 logs queue-worker
-
-# Worker neustarten
-pm2 restart queue-worker
-```
-
-### Email Queue
-
-E-Mails können asynchron über die Queue versendet werden:
-
-```typescript
-import { queueEmail } from '@/lib/queue'
-
-await queueEmail({
- tenantId: 1,
- to: 'empfaenger@example.com',
- subject: 'Betreff',
- html: 'Inhalt
',
- source: 'form-submission'
-})
-```
-
-### PDF Queue
-
-PDF-Generierung erfolgt über Playwright (HTML/URL zu PDF):
-
-**API-Endpoint `/api/generate-pdf`:**
-```bash
-# PDF aus HTML generieren
-curl -X POST https://pl.porwoll.tech/api/generate-pdf \
- -H "Content-Type: application/json" \
- -H "Cookie: payload-token=..." \
- -d '{
- "source": "html",
- "html": "Test
Inhalt
",
- "filename": "test.pdf"
- }'
-
-# Job-Status abfragen
-curl "https://pl.porwoll.tech/api/generate-pdf?jobId=abc123" \
- -H "Cookie: payload-token=..."
-```
-
-**Programmatisch:**
-```typescript
-import { queuePdfFromHtml, queuePdfFromUrl, getPdfJobStatus } from '@/lib/queue'
-
-// HTML zu PDF
-const job = await queuePdfFromHtml('Test
', { filename: 'test.pdf' })
-
-// URL zu PDF
-const job2 = await queuePdfFromUrl('https://example.com', { format: 'A4' })
-
-// Status abfragen
-const status = await getPdfJobStatus(job.id)
-```
-
-### Worker-Konfiguration
-
-Über `ecosystem.config.cjs`:
-- `QUEUE_EMAIL_CONCURRENCY`: Parallele E-Mail-Jobs (default: 3)
-- `QUEUE_PDF_CONCURRENCY`: Parallele PDF-Jobs (default: 2)
-- `QUEUE_RETENTION_CONCURRENCY`: Parallele Retention-Jobs (default: 1)
-- `QUEUE_DEFAULT_RETRY`: Retry-Versuche (default: 3)
-- `QUEUE_REDIS_DB`: Redis-Datenbank für Queue (default: 1)
-
-## Data Retention
-
-Automatische Datenbereinigung für DSGVO-Compliance und Speicheroptimierung.
-
-### Retention Policies
-
-| Collection | Retention | Umgebungsvariable | Beschreibung |
-|------------|-----------|-------------------|--------------|
-| email-logs | 90 Tage | `RETENTION_EMAIL_LOGS_DAYS` | E-Mail-Protokolle |
-| audit-logs | 90 Tage | `RETENTION_AUDIT_LOGS_DAYS` | Audit-Trail |
-| consent-logs | 3 Jahre | `RETENTION_CONSENT_LOGS_DAYS` | DSGVO: expiresAt-basiert |
-| media (orphans) | 30 Tage | `RETENTION_MEDIA_ORPHAN_MIN_AGE_DAYS` | Unreferenzierte Medien |
-
-### Automatischer Scheduler
-
-Retention-Jobs laufen täglich um 03:00 Uhr (konfigurierbar via `RETENTION_CRON_SCHEDULE`).
-
-```bash
-# Umgebungsvariablen in .env
-RETENTION_EMAIL_LOGS_DAYS=90
-RETENTION_AUDIT_LOGS_DAYS=90
-RETENTION_CONSENT_LOGS_DAYS=1095
-RETENTION_MEDIA_ORPHAN_MIN_AGE_DAYS=30
-RETENTION_CRON_SCHEDULE="0 3 * * *"
-
-# Worker aktivieren/deaktivieren
-QUEUE_ENABLE_RETENTION=true
-QUEUE_ENABLE_RETENTION_SCHEDULER=true
-```
-
-### API-Endpoint `/api/retention`
-
-**GET - Konfiguration abrufen:**
-```bash
-curl https://pl.porwoll.tech/api/retention \
- -H "Cookie: payload-token=..."
-```
-
-**GET - Job-Status abfragen:**
-```bash
-curl "https://pl.porwoll.tech/api/retention?jobId=abc123" \
- -H "Cookie: payload-token=..."
-```
-
-**POST - Manuellen Job auslösen:**
-```bash
-# Vollständige Retention (alle Policies + Media-Orphans)
-curl -X POST https://pl.porwoll.tech/api/retention \
- -H "Content-Type: application/json" \
- -H "Cookie: payload-token=..." \
- -d '{"type": "full"}'
-
-# Einzelne Collection bereinigen
-curl -X POST https://pl.porwoll.tech/api/retention \
- -H "Content-Type: application/json" \
- -H "Cookie: payload-token=..." \
- -d '{"type": "collection", "collection": "email-logs"}'
-
-# Nur Media-Orphans bereinigen
-curl -X POST https://pl.porwoll.tech/api/retention \
- -H "Content-Type: application/json" \
- -H "Cookie: payload-token=..." \
- -d '{"type": "media-orphans"}'
-```
-
-### Architektur
-
-```
-Scheduler (Cron)
- ↓
-Retention Queue (BullMQ)
- ↓
-Retention Worker
- ↓
-┌─────────────────┬─────────────────┬─────────────────┐
-│ Email-Logs │ Audit-Logs │ Consent-Logs │
-│ (createdAt) │ (createdAt) │ (expiresAt) │
-└─────────────────┴─────────────────┴─────────────────┘
- ↓
-Media-Orphan-Cleanup
- ↓
-Cleanup-Ergebnis (Logs)
-```
-
-### Dateien
-
-- `src/lib/retention/retention-config.ts` - Zentrale Konfiguration
-- `src/lib/retention/cleanup-service.ts` - Lösch-Logik
-- `src/lib/queue/jobs/retention-job.ts` - Job-Definition
-- `src/lib/queue/workers/retention-worker.ts` - Worker
-- `src/app/(payload)/api/retention/route.ts` - API-Endpoint
-
-## Redis Caching
-
-Redis wird für API-Response-Caching und E-Mail-Transporter-Caching verwendet:
-
-```typescript
-import { redis } from '@/lib/redis'
-
-// Cache setzen (TTL in Sekunden)
-await redis.set('key', JSON.stringify(data), 'EX', 60)
-
-// Cache lesen
-const cached = await redis.get('key')
-
-// Pattern-basierte Invalidierung
-await redis.keys('posts:*').then(keys => keys.length && redis.del(...keys))
-```
-
-## Backup-System
-
-Automatisches tägliches PostgreSQL-Backup mit lokalem Speicher und S3-Offsite-Backup.
-
-**Setup auf neuem Server:**
-```bash
-cd /home/payload/payload-cms/scripts/backup
-./setup-backup.sh
-```
-
-**Konfigurationsdateien (nicht im Repo):**
-- `~/.pgpass` - PostgreSQL-Credentials (chmod 600)
-- `~/.s3cfg` - S3-Credentials (chmod 600)
-
-**Backup-Speicherorte:**
-| Ort | Pfad | Retention |
-|-----|------|-----------|
-| Lokal | `/home/payload/backups/postgres/` | 30 Tage |
-| S3 | `s3://c2s/backups/postgres/` | 30 Tage |
-
-**Cron-Job:** Täglich um 03:00 Uhr
-
-**Manuelles Backup:**
-```bash
-/home/payload/backups/postgres/backup-db.sh --verbose
-```
-
-**Restore aus Backup:**
-```bash
-# Lokal
-gunzip -c /home/payload/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz | \
- psql -h 10.10.181.101 -U payload -d payload_db
-
-# Aus S3
-s3cmd get s3://c2s/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz
-gunzip -c payload_db_*.sql.gz | psql -h 10.10.181.101 -U payload -d payload_db
-```
-
-Dokumentation: `scripts/backup/README.md`
-
-## Datenbank-Direktzugriff
-
-```bash
-# Verwende ./scripts/db-direct.sh psql oder:
-PGPASSWORD="$DB_PASSWORD" psql -h 10.10.181.101 -U payload -d payload_db
-
-# Nützliche Queries
-SELECT * FROM tenants;
-SELECT * FROM users_tenants;
-SELECT * FROM email_logs ORDER BY created_at DESC LIMIT 10;
-SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 10;
-\dt -- Alle Tabellen
-```
-
-## Blocks Übersicht (43 Blocks)
-
-### Core Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| HeroBlock | hero-block | Einzelner Hero mit Bild, Headline, CTA |
-| HeroSliderBlock | hero-slider-block | Hero-Slider mit mehreren Slides |
-| ImageSliderBlock | image-slider-block | Bildergalerie/Karussell |
-| TextBlock | text-block | Textinhalt mit Rich-Text |
-| ImageTextBlock | image-text-block | Bild + Text nebeneinander |
-| CardGridBlock | card-grid-block | Karten-Raster |
-| QuoteBlock | quote-block | Zitat |
-| CTABlock | cta-block | Call-to-Action |
-| ContactFormBlock | contact-form-block | Kontaktformular |
-| TimelineBlock | timeline-block | Timeline-Darstellung |
-| DividerBlock | divider-block | Trennlinie |
-| VideoBlock | video-block | Video einbetten |
-
-### Content Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| PostsListBlock | posts-list-block | Beitrags-Liste |
-| TestimonialsBlock | testimonials-block | Kundenbewertungen |
-| NewsletterBlock | newsletter-block | Newsletter-Anmeldung |
-| ProcessStepsBlock | process-steps-block | Prozess-Schritte |
-| FAQBlock | faq-block | FAQ-Akkordeon |
-| TeamBlock | team-block | Team-Mitglieder |
-| ServicesBlock | services-block | Leistungen |
-
-### Blogging Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| AuthorBioBlock | author-bio-block | Autoren-Biografie |
-| RelatedPostsBlock | related-posts-block | Verwandte Beiträge |
-| ShareButtonsBlock | share-buttons-block | Social Share Buttons |
-| TableOfContentsBlock | table-of-contents-block | Inhaltsverzeichnis |
-
-### Team Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| TeamFilterBlock | team-filter-block | Team mit Filter-Funktion |
-| OrgChartBlock | org-chart-block | Organigramm |
-
-### Feature Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| LocationsBlock | locations-block | Standorte/Filialen |
-| LogoGridBlock | logo-grid-block | Partner/Kunden-Logos |
-| StatsBlock | stats-block | Statistiken/Zahlen |
-| JobsBlock | jobs-block | Stellenangebote |
-| DownloadsBlock | downloads-block | Download-Bereich |
-| MapBlock | map-block | Karten-Einbindung |
-
-### Interactive Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| EventsBlock | events-block | Veranstaltungen |
-| PricingBlock | pricing-block | Preistabellen |
-| TabsBlock | tabs-block | Tab-Navigation |
-| AccordionBlock | accordion-block | Akkordeon/Aufklappbar |
-| ComparisonBlock | comparison-block | Vergleichstabelle |
-
-### Tenant-specific Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| BeforeAfterBlock | before-after-block | Vorher/Nachher Bildvergleich (porwoll.de) |
-
-### BlogWoman Blocks
-| Block | Slug | Beschreibung |
-|-------|------|--------------|
-| FavoritesBlock | favorites-block | Affiliate-Produkte Grid/Liste/Karussell |
-| SeriesBlock | series-block | YouTube-Serien Übersicht |
-| SeriesDetailBlock | series-detail-block | Serien-Einzelseite mit Hero |
-| VideoEmbedBlock | video-embed-block | YouTube/Vimeo Embed mit Privacy Mode |
-| FeaturedContentBlock | featured-content-block | Kuratierte Mixed-Content Sammlung |
-| ScriptSectionBlock | script-section-block | YouTube-Script Abschnitte |
-
-### HeroSliderBlock Features
-
-Vollwertiger Hero-Slider mit:
-
-**Slides (Array, 1-10):**
-- Hintergrundbild (Desktop + optional Mobil)
-- Headline + Subline (lokalisiert)
-- Text-Ausrichtung (links/zentriert/rechts)
-- Vertikale Position (oben/mitte/unten)
-- Overlay (Farbe, Deckkraft, Gradient)
-- Primärer + Sekundärer CTA-Button
-- Textfarbe (weiß/dunkel/primär)
-
-**Animationen:**
-- Typen: fade, slide, zoom, flip, none
-- Konfigurierbare Dauer (300-1200ms)
-
-**Autoplay:**
-- Intervall (3-10 Sekunden)
-- Pause bei Hover
-- Pause bei Interaktion
-
-**Navigation:**
-- Pfeile (verschiedene Stile, Positionen)
-- Dots (Punkte, Striche, Nummern, Thumbnails, Fortschritt)
-- Touch-Swipe
-- Tastaturnavigation
-
-**Layout:**
-- Höhe (Vollbild bis kompakt)
-- Separate Mobile-Höhe
-- Content-Breite
-
-## Collections Übersicht (55+ Collections)
-
-### Core Collections
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Users | users | Benutzer mit isSuperAdmin Flag |
-| Tenants | tenants | Mandanten mit E-Mail-Konfiguration |
-| Media | media | Medien mit 11 responsive Image Sizes |
-| Pages | pages | Seiten mit Blocks |
-
-### Content Collections
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Posts | posts | Blog/News/Presse mit Kategorien |
-| Categories | categories | Kategorien für Posts |
-| Tags | tags | Tags für Posts (Blogging) |
-| Authors | authors | Autoren für Posts |
-| Testimonials | testimonials | Kundenbewertungen |
-| FAQs | faqs | Häufig gestellte Fragen (FAQ) |
-| SocialLinks | social-links | Social Media Links |
-
-### Team & Services
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Team | team | Team-Mitglieder und Mitarbeiter |
-| ServiceCategories | service-categories | Kategorien für Leistungen |
-| Services | services | Leistungen und Dienstleistungen |
-| Jobs | jobs | Stellenangebote |
-
-### Portfolio & Media
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Portfolios | portfolios | Portfolio-Galerien (Fotografie) |
-| PortfolioCategories | portfolio-categories | Kategorien für Portfolios |
-| Videos | videos | Video-Bibliothek mit YouTube/Vimeo/Uploads |
-| VideoCategories | video-categories | Kategorien für Videos |
-
-### Products (E-Commerce)
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Products | products | Produkte |
-| ProductCategories | product-categories | Produkt-Kategorien |
-
-### Feature Collections
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Locations | locations | Standorte/Filialen |
-| Partners | partners | Partner/Kunden |
-| Downloads | downloads | Download-Dateien |
-| Events | events | Veranstaltungen |
-| Timelines | timelines | Chronologische Events (Geschichte, Meilensteine) |
-| Workflows | workflows | Komplexe Prozesse mit Phasen und Schritten |
-
-### Formulare & Newsletter
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Forms | forms | Formular-Builder (Plugin) |
-| FormSubmissions | form-submissions | Formular-Einsendungen mit CRM-Workflow |
-| NewsletterSubscribers | newsletter-subscribers | Newsletter mit Double Opt-In |
-
-### Consent & Privacy (DSGVO)
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| CookieConfigurations | cookie-configurations | Cookie-Banner Konfiguration |
-| CookieInventory | cookie-inventory | Cookie-Inventar |
-| ConsentLogs | consent-logs | Consent-Protokollierung (WORM) |
-| PrivacyPolicySettings | privacy-policy-settings | Datenschutz-Einstellungen |
-
-### Tenant-specific Collections
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Bookings | bookings | Fotografie-Buchungen (porwoll.de) |
-| Certifications | certifications | Zertifizierungen (C2S) |
-| Projects | projects | Game-Development-Projekte (gunshin.de) |
-
-### BlogWoman Collections
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| Favorites | favorites | Affiliate-Produkte mit Kategorien und Badges |
-| Series | series | YouTube-Serien mit Branding (Logo, Farben) |
-
-### YouTube & Community Management
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| YouTubeChannels | youtube-channels | Multi-Kanal-Verwaltung mit OAuth |
-| YouTubeContent | youtube-content | Videos + Shorts mit Kommentaren |
-| YtSeries | yt-series | Serien mit Branding (Logo, Farben, Playlist) |
-| YtNotifications | yt-notifications | Handlungsbedarf-System |
-| YtScriptTemplates | yt-script-templates | Skript-Vorlagen für Videos |
-| YtBatches | yt-batches | Video-Batches für Produktions-Planung |
-| YtChecklistTemplates | yt-checklist-templates | Checklisten-Vorlagen für Video-Produktion |
-| YtMonthlyGoals | yt-monthly-goals | Monatliche YouTube-Ziele |
-| YtTasks | yt-tasks | YouTube-Aufgaben-Verwaltung |
-| SocialAccounts | social-accounts | Meta/Social OAuth-Verbindungen |
-| SocialPlatforms | social-platforms | Plattform-Konfigurationen |
-| CommunityInteractions | community-interactions | Kommentare & Interaktionen |
-| CommunityRules | community-rules | Automatische Antwort-Regeln |
-| CommunityTemplates | community-templates | Antwort-Vorlagen |
-| ReportSchedules | report-schedules | Geplante Community-Reports |
-
-### System Collections
-| Collection | Slug | Beschreibung |
-|------------|------|--------------|
-| EmailLogs | email-logs | E-Mail-Protokollierung |
-| AuditLogs | audit-logs | Security Audit Trail |
-| SiteSettings | site-settings | Website-Einstellungen (pro Tenant) |
-| Navigations | navigations | Navigationsmenüs (pro Tenant) |
-| Redirects | redirects | URL-Weiterleitungen (Plugin) |
-
-## Timeline Collection
-
-Dedizierte Collection für komplexe chronologische Darstellungen:
-
-**Timeline-Typen:**
-- `history` - Unternehmensgeschichte
-- `milestones` - Projektmeilensteine
-- `releases` - Produkt-Releases
-- `career` - Karriere/Lebenslauf
-- `events` - Ereignisse
-- `process` - Prozess/Ablauf
-
-**Event-Features:**
-- Flexible Datumsformate (Jahr, Monat+Jahr, vollständig, Zeitraum, Freitext)
-- Kategorien (Meilenstein, Gründung, Produkt, Team, Auszeichnung, etc.)
-- Wichtigkeitsstufen (Highlight, Normal, Minor)
-- Bilder und Galerien
-- Links und Metadaten
-- Rich-Text-Beschreibungen
-
-**Display-Optionen:**
-- Layouts: vertikal, alternierend, horizontal, kompakt
-- Sortierung: aufsteigend/absteigend
-- Gruppierung nach Jahr
-- Verschiedene Marker-Stile
-
-**Prozess-spezifische Felder (type=process):**
-- `stepNumber` - Explizite Schritt-Nummerierung
-- `duration` - Dauer (z.B. "2-3 Tage")
-- `responsible` - Verantwortliche Person/Rolle
-- `actionRequired` - Wer muss aktiv werden (customer, internal, both, automatic)
-- `deliverables` - Ergebnisse/Dokumente des Schritts
-
-**API-Endpoint:**
-```bash
-# Liste aller Timelines eines Tenants
-curl "https://pl.porwoll.tech/api/timelines?tenant=1"
-
-# Nach Typ filtern
-curl "https://pl.porwoll.tech/api/timelines?tenant=1&type=history"
-
-# Einzelne Timeline
-curl "https://pl.porwoll.tech/api/timelines?tenant=1&slug=company-history"
-
-# Mit Sprache
-curl "https://pl.porwoll.tech/api/timelines?tenant=1&locale=en"
-```
-
-## Workflows Collection
-
-Komplexe Prozess- und Workflow-Darstellungen mit Phasen, Abhängigkeiten und Status-Tracking.
-
-**Workflow-Typen:**
-- `project` - Projektabläufe
-- `business` - Geschäftsprozesse
-- `approval` - Genehmigungs-Workflows
-- `onboarding` - Mitarbeiter-/Kundeneinführung
-- `support` - Support/Service-Prozesse
-- `development` - Entwicklungsprozesse
-- `marketing` - Marketing-Workflows
-- `other` - Sonstige
-
-**Eigenschaften:**
-- `estimatedDuration` - Geschätzte Gesamtdauer
-- `complexity` - simple, medium, complex, very_complex
-- `isIterative` - Kann wiederholt werden
-- `allowParallelPhases` - Parallele Phasen möglich
-
-**Display-Optionen:**
-- Layouts: vertical, horizontal, flowchart, kanban, gantt
-- Farbschema: phase, status, priority, brand
-- Optionale Anzeige: Nummern, Zeiten, Verantwortliche, Fortschritt
-
-**Phasen-Struktur:**
-```
-Workflow
-└── Phasen (Array)
- ├── name, description, icon, color
- ├── estimatedDuration, responsible
- ├── deliverables (Array)
- └── Schritte (Array)
- ├── name, description, stepType, priority
- ├── estimatedDuration, responsible
- ├── dependencies (dependsOnSteps, canRunParallel, isBlocking)
- ├── conditions (für Entscheidungen)
- ├── checklist (Array)
- ├── resources (Dokumente, Links, Tools)
- └── outputs (Ergebnisse)
-```
-
-**API-Endpoint:**
-```bash
-# Liste aller Workflows eines Tenants
-curl "https://pl.porwoll.tech/api/workflows?tenant=1"
-
-# Nach Typ filtern
-curl "https://pl.porwoll.tech/api/workflows?tenant=1&type=project"
-
-# Nach Komplexität filtern
-curl "https://pl.porwoll.tech/api/workflows?tenant=1&complexity=medium"
-
-# Einzelner Workflow
-curl "https://pl.porwoll.tech/api/workflows?tenant=1&slug=web-project"
-
-# Mit Sprache
-curl "https://pl.porwoll.tech/api/workflows?tenant=1&locale=en"
-```
-
-**Validierung:**
-- `tenant` - Pflichtparameter (Tenant-Isolation)
-- `type` - Validiert gegen erlaubte Typen (400 bei Fehler)
-- `complexity` - Validiert gegen erlaubte Werte (400 bei Fehler)
-- `locale` - de (default) oder en
-
-## FormSubmissions CRM-Workflow
-
-Die FormSubmissions Collection wurde zu einem leichtgewichtigen CRM erweitert:
-
-**Status-Workflow:**
-- 🆕 Neu → 👀 Gelesen → 🔄 In Bearbeitung → ⏳ Warten → ✅ Erledigt → 🗑️ Archiviert
-
-**Features:**
-- Priorität (Hoch/Normal/Niedrig)
-- Zuständigkeits-Zuweisung an User
-- Interne Notizen mit Auto-Autor und Zeitstempel
-- Antwort-Tracking (Methode, Zeitstempel, Zusammenfassung)
-- Tags zur Kategorisierung
-- Auto-Markierung als gelesen beim ersten Öffnen
-
-**Dateien:**
-- `src/collections/FormSubmissionsOverrides.ts` - Feld-Definitionen
-- `src/hooks/formSubmissionHooks.ts` - Automatisierungen
-
-## Community Management System
-
-Plattformübergreifendes Community Management für YouTube, Facebook und Instagram mit einer einheitlichen Inbox, AI-Analyse und automatischer Moderation.
-
-### Architektur
-
-```
- ┌─────────────────────────────────────────┐
- │ Admin UI │
- │ ┌─────────────┐ ┌──────────────────┐ │
- │ │ Community │ │ Community │ │
- │ │ Inbox │ │ Analytics │ │
- │ └──────┬──────┘ └────────┬─────────┘ │
- └─────────┼──────────────────┼────────────┘
- │ │
- ┌─────────▼──────────────────▼────────────┐
- │ /api/community/* │
- │ sync, sync-status, stats, reply, │
- │ generate-reply, export, stream │
- └─────────────────┬───────────────────────┘
- │
- ┌─────────────────▼───────────────────────┐
- │ UnifiedSyncService │
- │ ┌──────────┬───────────┬────────────┐ │
- │ │ YouTube │ Facebook │ Instagram │ │
- │ │ Sync │ Sync │ Sync │ │
- │ └────┬─────┴─────┬─────┴──────┬─────┘ │
- └───────┼───────────┼────────────┼────────┘
- │ │ │
- ┌───────▼───────────▼────────────▼────────┐
- │ CommunityInteractions │
- │ (einheitliche Collection für alle │
- │ Plattform-Kommentare) │
- └─────────────────────────────────────────┘
-```
-
-### Admin UI
-
-**Community Inbox** (`/admin/community/inbox`):
-- Einheitliche Ansicht aller Kommentare (YouTube + Facebook + Instagram)
-- Filter nach Plattform, Status, Priorität, Sentiment, Flags
-- AI-generierte Antwort-Vorschläge (Claude)
-- Direkte Antwort-Funktion
-- Echtzeit-Updates via SSE (`/api/community/stream`)
-- Export als CSV/JSON
-- Sync-Button (triggert alle Plattformen)
-
-**Community Analytics** (`/admin/community/analytics`):
-- KPI-Cards (Gesamt, Heute, Unbeantwortet)
-- Sentiment-Trend-Chart
-- Topic-Cloud
-- Response-Metriken
-- Kanal-Vergleich
-- Top-Content nach Engagement
-
-### Meta (Facebook + Instagram) Integration
-
-**OAuth-Flow:**
-```
-1. Admin öffnet /api/auth/meta?socialAccountId=X&accountType=both
-2. Redirect zu Facebook OAuth (12 Scopes)
-3. Callback: Short-Lived → Long-Lived Token (60 Tage)
-4. Facebook Pages + Instagram Business Accounts werden geladen
-5. Token + Account-Daten in SocialAccounts gespeichert
-```
-
-**Unterstützte Scopes:**
-- Facebook: `pages_show_list`, `pages_read_engagement`, `pages_manage_posts`, `pages_read_user_content`, `pages_manage_engagement`, `pages_messaging`
-- Instagram: `instagram_basic`, `instagram_manage_comments`, `instagram_manage_messages`, `instagram_content_publish`
-
-**API-Clients:**
-
-| Client | Datei | Funktionen |
-|--------|-------|------------|
-| MetaBaseClient | `src/lib/integrations/meta/MetaBaseClient.ts` | HTTP-Basis, Pagination, Retry, Token-Management |
-| FacebookClient | `src/lib/integrations/meta/FacebookClient.ts` | Posts, Kommentare, Messenger, Insights |
-| InstagramClient | `src/lib/integrations/meta/InstagramClient.ts` | Media, Kommentare, Mentions, DMs, Insights |
-
-**Sync-Services:**
-
-| Service | Datei | Beschreibung |
-|---------|-------|--------------|
-| FacebookSyncService | `src/lib/integrations/meta/FacebookSyncService.ts` | Synct Page-Kommentare + Replies |
-| InstagramSyncService | `src/lib/integrations/meta/InstagramSyncService.ts` | Synct Media-Kommentare + Mentions |
-| UnifiedSyncService | `src/lib/jobs/UnifiedSyncService.ts` | Orchestriert YouTube + Facebook + Instagram |
-
-**Sync-Ablauf (pro Account):**
-1. SocialAccount laden + Platform verifizieren
-2. Token validieren
-3. Posts/Media abrufen (mit Datum-Filter)
-4. Kommentare pro Post synchronisieren
-5. AI-Analyse via Claude (Sentiment, Topics, Flags)
-6. In CommunityInteractions speichern (dedupliziert via `externalId`)
-7. Account-Stats aktualisieren
-
-### Sync-Trigger
-
-| Trigger | Endpoint | Plattformen |
-|---------|----------|-------------|
-| Cron (alle 15 Min) | `/api/cron/community-sync` | Alle aktiven Accounts |
-| Manuell (Inbox-Button) | `/api/community/sync` (POST) | Alle (optional filterbar) |
-| YouTube-spezifisch | `/api/cron/youtube-sync` | Nur YouTube |
-
-### Community API-Endpoints
-
-| Endpoint | Methode | Beschreibung |
-|----------|---------|--------------|
-| `/api/community/sync` | POST | Manueller Sync (alle Plattformen) |
-| `/api/community/sync` | GET | Sync-Status |
-| `/api/community/sync-status` | GET | Detaillierter Status mit Account-Stats |
-| `/api/community/stats` | GET | Interaktions-Statistiken |
-| `/api/community/reply` | POST | Antwort senden |
-| `/api/community/generate-reply` | POST | AI-Antwort generieren (Claude) |
-| `/api/community/export` | GET | Daten-Export (CSV/JSON) |
-| `/api/community/stream` | GET | SSE-Stream für Echtzeit-Updates |
-| `/api/community/sync-comments` | POST | Kommentar-Sync (Legacy) |
-| `/api/community/analytics/*` | GET | Analytics-Daten (6 Endpoints) |
-| `/api/auth/meta` | GET | Meta OAuth starten |
-| `/api/auth/meta/callback` | GET | Meta OAuth Callback |
-
-### CommunityRules (Automatisierung)
-
-Regel-basierte Automatisierung für eingehende Kommentare:
-
-**Trigger-Typen:** `keyword`, `sentiment`, `question_detected`, `medical_detected`, `influencer` (>10k Follower), `all_new`, `contains_link`, `contains_email`
-
-**Aktionen:** `set_priority`, `assign_to`, `set_flag`, `suggest_template`, `send_notification`, `flag_medical`, `escalate`, `mark_spam`, `set_deadline`
-
-### Wichtige Dateien
-
-```
-src/lib/integrations/meta/
-├── MetaBaseClient.ts # HTTP-Basis mit Retry + Pagination
-├── FacebookClient.ts # Facebook Graph API Client
-├── InstagramClient.ts # Instagram Graph API Client
-├── FacebookSyncService.ts # Facebook Kommentar-Sync
-├── InstagramSyncService.ts # Instagram Kommentar-Sync
-├── oauth.ts # Meta OAuth 2.0 Flow
-└── index.ts # Re-Exports
-
-src/lib/jobs/
-├── UnifiedSyncService.ts # Orchestriert alle Plattform-Syncs
-├── syncAllComments.ts # YouTube-spezifischer Sync (Legacy)
-└── JobLogger.ts # Strukturiertes Logging
-
-src/app/(payload)/api/
-├── auth/meta/ # OAuth Start + Callback
-├── community/ # 14 Community-Endpoints
-└── cron/community-sync/ # Cron-Trigger für Unified Sync
-```
+| Bereich | URL |
+|---------|-----|
+| Admin Panel | https://pl.porwoll.tech/admin |
+| API | https://pl.porwoll.tech/api |
+| Swagger UI | https://pl.porwoll.tech/api/docs |
+| Production | https://cms.c2sgmbh.de |
+
+→ Vollständige Endpoint-Liste: `docs/anleitungen/API_ANLEITUNG.md`
+
+## Security Kurzübersicht
+
+- **Rate-Limiting:** publicApi(60/min), auth(5/15min), email(10/min), search(30/min), form(5/10min)
+- **CSRF:** Double Submit Cookie + Origin-Validierung, Token: `GET /api/csrf-token`
+- **IP-Allowlist:** `SEND_EMAIL_ALLOWED_IPS`, `ADMIN_ALLOWED_IPS`, `BLOCKED_IPS` (IPs, CIDRs, Wildcards)
+- **Data-Masking:** Automatisch in Logs (Passwörter, Tokens, API-Keys)
+
+→ Details: `docs/anleitungen/SECURITY.md`
+
+## Subsysteme (Kurzübersicht)
+
+| System | Schlüsseldateien | Details |
+|--------|-----------------|---------|
+| E-Mail (Multi-Tenant SMTP) | `src/lib/email/` | `docs/CLAUDE_REFERENCE.md` |
+| Newsletter (Double Opt-In) | `src/lib/email/newsletter-service.ts` | `docs/CLAUDE_REFERENCE.md` |
+| BullMQ Queue | `src/lib/queue/`, `ecosystem.config.cjs` | `docs/CLAUDE_REFERENCE.md` |
+| Data Retention (DSGVO) | `src/lib/retention/` | `docs/CLAUDE_REFERENCE.md` |
+| PDF-Generierung | `src/lib/pdf/`, API: `/api/generate-pdf` | `docs/CLAUDE_REFERENCE.md` |
+| Redis Caching | `src/lib/redis.ts` | `docs/CLAUDE_REFERENCE.md` |
+| Backup | `scripts/backup/` | `scripts/backup/README.md` |
+| Community Management | `src/lib/integrations/meta/`, `src/lib/jobs/` | `docs/CLAUDE_REFERENCE.md` |
+| FormSubmissions CRM | `src/collections/FormSubmissionsOverrides.ts` | `docs/CLAUDE_REFERENCE.md` |
+
+## Collections (55+)
+
+| Slug | Beschreibung | Gruppe |
+|------|--------------|--------|
+| users | Benutzer (isSuperAdmin) | Core |
+| tenants | Mandanten + E-Mail-Config | Core |
+| media | Medien (11 responsive Sizes) | Core |
+| pages | Seiten mit Blocks | Core |
+| posts | Blog/News/Presse | Content |
+| categories | Post-Kategorien | Content |
+| tags | Post-Tags | Content |
+| authors | Post-Autoren | Content |
+| testimonials | Kundenbewertungen | Content |
+| faqs | FAQ | Content |
+| social-links | Social Media Links | Content |
+| team | Team-Mitglieder | Team |
+| service-categories | Leistungs-Kategorien | Team |
+| services | Leistungen | Team |
+| jobs | Stellenangebote | Team |
+| portfolios | Portfolio-Galerien | Portfolio |
+| portfolio-categories | Portfolio-Kategorien | Portfolio |
+| videos | Video-Bibliothek | Media |
+| video-categories | Video-Kategorien | Media |
+| products | Produkte | E-Commerce |
+| product-categories | Produkt-Kategorien | E-Commerce |
+| locations | Standorte/Filialen | Feature |
+| partners | Partner/Kunden | Feature |
+| downloads | Download-Dateien | Feature |
+| events | Veranstaltungen | Feature |
+| timelines | Chronologische Events | Feature |
+| workflows | Prozesse mit Phasen | Feature |
+| forms | Formular-Builder (Plugin) | Formulare |
+| form-submissions | CRM-Workflow | Formulare |
+| newsletter-subscribers | Double Opt-In | Newsletter |
+| cookie-configurations | Cookie-Banner | DSGVO |
+| cookie-inventory | Cookie-Inventar | DSGVO |
+| consent-logs | Consent-Protokoll (WORM) | DSGVO |
+| privacy-policy-settings | Datenschutz | DSGVO |
+| bookings | Fotografie-Buchungen (porwoll) | Tenant |
+| certifications | Zertifizierungen (c2s) | Tenant |
+| projects | Game-Dev-Projekte (gunshin) | Tenant |
+| favorites | Affiliate-Produkte | BlogWoman |
+| series | YouTube-Serien (Branding) | BlogWoman |
+| youtube-channels | Multi-Kanal + OAuth | YouTube |
+| youtube-content | Videos + Shorts | YouTube |
+| yt-series | Serien + Playlist | YouTube |
+| yt-notifications | Handlungsbedarf | YouTube |
+| yt-script-templates | Skript-Vorlagen | YouTube |
+| yt-batches | Produktions-Batches | YouTube |
+| yt-checklist-templates | Checklisten | YouTube |
+| yt-monthly-goals | Monatsziele | YouTube |
+| yt-tasks | Aufgaben | YouTube |
+| social-accounts | Meta OAuth | Community |
+| social-platforms | Plattform-Config | Community |
+| community-interactions | Kommentare (alle Plattformen) | Community |
+| community-rules | Auto-Antwort-Regeln | Community |
+| community-templates | Antwort-Vorlagen | Community |
+| report-schedules | Geplante Reports | Community |
+| email-logs | E-Mail-Protokoll | System |
+| audit-logs | Security Audit Trail | System |
+| site-settings | Website-Einstellungen (pro Tenant) | System |
+| navigations | Navigationsmenüs (pro Tenant) | System |
+| redirects | URL-Weiterleitungen (Plugin) | System |
+
+## Blocks (43)
+
+| Slug | Beschreibung | Gruppe |
+|------|--------------|--------|
+| hero-block | Hero mit Bild, Headline, CTA | Core |
+| hero-slider-block | Hero-Slider (Slides, Animationen, Autoplay) | Core |
+| image-slider-block | Bildergalerie/Karussell | Core |
+| text-block | Rich-Text Inhalt | Core |
+| image-text-block | Bild + Text nebeneinander | Core |
+| card-grid-block | Karten-Raster | Core |
+| quote-block | Zitat | Core |
+| cta-block | Call-to-Action | Core |
+| contact-form-block | Kontaktformular | Core |
+| timeline-block | Timeline-Darstellung | Core |
+| divider-block | Trennlinie | Core |
+| video-block | Video einbetten | Core |
+| posts-list-block | Beitrags-Liste | Content |
+| testimonials-block | Kundenbewertungen | Content |
+| newsletter-block | Newsletter-Anmeldung | Content |
+| process-steps-block | Prozess-Schritte | Content |
+| faq-block | FAQ-Akkordeon | Content |
+| team-block | Team-Mitglieder | Content |
+| services-block | Leistungen | Content |
+| author-bio-block | Autoren-Biografie | Blogging |
+| related-posts-block | Verwandte Beiträge | Blogging |
+| share-buttons-block | Social Share Buttons | Blogging |
+| table-of-contents-block | Inhaltsverzeichnis | Blogging |
+| team-filter-block | Team mit Filter | Team |
+| org-chart-block | Organigramm | Team |
+| locations-block | Standorte/Filialen | Feature |
+| logo-grid-block | Partner-Logos | Feature |
+| stats-block | Statistiken/Zahlen | Feature |
+| jobs-block | Stellenangebote | Feature |
+| downloads-block | Download-Bereich | Feature |
+| map-block | Karten-Einbindung | Feature |
+| events-block | Veranstaltungen | Interactive |
+| pricing-block | Preistabellen | Interactive |
+| tabs-block | Tab-Navigation | Interactive |
+| accordion-block | Akkordeon | Interactive |
+| comparison-block | Vergleichstabelle | Interactive |
+| before-after-block | Vorher/Nachher (porwoll) | Tenant |
+| favorites-block | Affiliate-Produkte | BlogWoman |
+| series-block | YouTube-Serien | BlogWoman |
+| series-detail-block | Serien-Einzelseite | BlogWoman |
+| video-embed-block | YouTube/Vimeo Embed | BlogWoman |
+| featured-content-block | Kuratierte Inhalte | BlogWoman |
+| script-section-block | Script-Abschnitte | BlogWoman |
## Globals
-> **Hinweis:** SiteSettings, Navigations und PrivacyPolicySettings wurden zu tenant-spezifischen Collections umgewandelt (siehe Collections Übersicht).
-
| Global | Slug | Beschreibung |
|--------|------|--------------|
| SEOSettings | seo-settings | Globale SEO-Einstellungen (systemweit) |
-## Test Suite
+> SiteSettings, Navigations, PrivacyPolicySettings sind tenant-spezifische Collections.
-```bash
-# Alle Tests ausführen
-pnpm test
-
-# Security Tests
-pnpm test:security
-
-# Coverage Report
-pnpm test:coverage
-```
-
-**Test Coverage Thresholds:**
-- Lines: 35%
-- Functions: 50%
-- Branches: 65%
-
-## Scheduled Cron Jobs (Vercel)
-
-Automatische Hintergrund-Jobs via Vercel Cron (`vercel.json`):
+## Cron Jobs
| Endpoint | Schedule | Beschreibung |
|----------|----------|--------------|
-| `/api/cron/community-sync` | `*/15 * * * *` (alle 15 Min) | Synchronisiert Kommentare von YouTube, Facebook, Instagram |
-| `/api/cron/token-refresh` | `0 6,18 * * *` (6:00 + 18:00 UTC) | Erneuert ablaufende OAuth-Tokens automatisch |
-| `/api/cron/send-reports` | `0 * * * *` (stündlich) | Versendet fällige Community-Reports per E-Mail |
+| `/api/cron/community-sync` | alle 15 Min | Kommentar-Sync (YouTube, Facebook, Instagram) |
+| `/api/cron/token-refresh` | 6:00 + 18:00 UTC | OAuth-Token-Erneuerung |
+| `/api/cron/send-reports` | stündlich | Community-Reports per E-Mail |
-**Authentifizierung:**
-Alle Cron-Endpoints erfordern `Authorization: Bearer $CRON_SECRET` Header.
+Auth: `Authorization: Bearer $CRON_SECRET`
-**Manueller Trigger:**
-```bash
-# Community Sync manuell auslösen
-curl -X POST "https://your-domain/api/cron/community-sync" \
- -H "Authorization: Bearer $CRON_SECRET" \
- -H "Content-Type: application/json" \
- -d '{"platforms": ["youtube", "facebook"]}'
+## CI/CD
-# Token Refresh manuell auslösen (Dry-Run)
-curl "https://your-domain/api/cron/token-refresh?dryRun=true" \
- -H "Authorization: Bearer $CRON_SECRET"
+| Workflow | Trigger | Beschreibung |
+|----------|---------|--------------|
+| `ci.yml` | Push/PR auf main/develop | Lint, Typecheck, Test, Build, E2E |
+| `security.yml` | Push/PR | Gitleaks, pnpm audit, CodeQL |
+| `deploy-staging.yml` | Push auf develop | Auto-Deploy auf pl.porwoll.tech |
+| `deploy-production.yml` | Manual dispatch | Deploy auf cms.c2sgmbh.de (mit Backup + Rollback) |
-# Token Refresh Status prüfen
-curl -I "https://your-domain/api/cron/token-refresh" \
- -H "Authorization: Bearer $CRON_SECRET"
-```
+→ Details: `docs/DEPLOYMENT.md`, `docs/DEPLOYMENT_STRATEGY.md`
-**Monitoring:**
-- HEAD-Requests geben Status-Header zurück (`X-Sync-Running`, `X-Last-Run`, etc.)
-- Bei laufendem Job: HTTP 423 (Locked)
-- Fehlerhafte Tokens werden als Benachrichtigungen in `yt-notifications` gespeichert
+## Umgebungsvariablen
-## CI/CD Pipeline
+Wichtigste Variablen (vollständige Liste in `.env`):
-GitHub Actions Workflows in `.github/workflows/`:
+| Variable | Beschreibung | Pflicht |
+|----------|--------------|---------|
+| `DATABASE_URI` | PostgreSQL via PgBouncer (127.0.0.1:6432) | Ja |
+| `PAYLOAD_SECRET` | Payload Encryption Secret | Ja |
+| `TRUST_PROXY` | `true` hinter Reverse-Proxy | Ja |
+| `CSRF_SECRET` | CSRF-Token Secret (oder PAYLOAD_SECRET) | Prod |
+| `CRON_SECRET` | Auth für Cron-Endpoints | Ja |
+| `REDIS_URL` | Redis Cache (localhost:6379) | Optional |
+| `META_APP_ID/SECRET` | Facebook/Instagram OAuth | Für Community |
+| `GOOGLE_CLIENT_ID/SECRET` | YouTube OAuth | Für YouTube |
-### ci.yml (Main CI Pipeline)
-Läuft bei Push/PR auf `main` und `develop`:
-
-| Job | Beschreibung |
-|-----|--------------|
-| **lint** | ESLint (flat config, 0 errors) |
-| **typecheck** | TypeScript Compiler (`tsc --noEmit`, 4GB heap) |
-| **test** | Unit & Integration Tests (Vitest) |
-| **build** | Next.js Production Build |
-| **e2e** | Playwright E2E Tests |
-
-**Lokale Ausführung:**
-```bash
-pnpm lint # ESLint (0 errors, warnings only)
-pnpm typecheck # TypeScript Check (4GB heap for 55+ collections)
-pnpm format:check # Prettier Check
-pnpm format # Prettier Auto-Fix
-pnpm test # Alle Tests
-pnpm build # Production Build
-```
-
-### security.yml (Security Scanning)
-- **Gitleaks**: Secret Scanning
-- **pnpm audit**: Dependency Vulnerabilities
-- **CodeQL**: Static Analysis (SAST)
-- **Security Tests**: Unit & Integration Tests für Security-Module
-
-### deploy-staging.yml (Staging Deployment)
-Automatisches Deployment auf Staging-Server bei Push auf `develop`:
-
-| Trigger | Aktion |
-|---------|--------|
-| Push auf `develop` | Automatisches Deployment |
-| `workflow_dispatch` | Manuelles Deployment (optional: skip_tests) |
-
-**Deployment-Ziel:**
-- **URL:** https://pl.porwoll.tech
-- **Server:** 37.24.237.181 (sv-payload)
-
-**Ablauf:**
-1. Pre-deployment Checks (Lint, Tests)
-2. SSH-Verbindung zum Staging-Server
-3. Git Pull + Dependencies installieren
-4. Migrations ausführen
-5. Build + PM2 Restart
-6. Health Check
-
-**Manuelles Staging-Deployment:**
-```bash
-# Auf dem Staging-Server (pl.porwoll.tech)
-./scripts/deploy-staging.sh
-
-# Mit Optionen
-./scripts/deploy-staging.sh --skip-build # Nur Code-Update
-./scripts/deploy-staging.sh --skip-migrations # Ohne Migrationen
-```
-
-**GitHub Secret erforderlich:**
-- `STAGING_SSH_KEY` - SSH Private Key für `payload@37.24.237.181`
-
-### deploy-production.yml (Production Deployment)
-Manuelles Deployment auf Production-Server (Hetzner 3) bei workflow_dispatch:
-
-| Feature | Beschreibung |
-|---------|--------------|
-| Pre-flight Checks | Überprüft Branch-Status und Migrationen |
-| Pre-deployment Tests | Optional: ESLint, Unit Tests, Build |
-| Database Backup | Automatisches Backup vor Deployment |
-| Health Check | Admin Panel (200) + API (< 500) |
-| Post-deployment Verification | Admin + API Health Check |
-| Auto-Rollback | Bei fehlgeschlagenem Health Check |
-
-**Manuelles Production-Deployment:**
-```bash
-# Via GitHub Actions (empfohlen)
-gh workflow run deploy-production.yml
-
-# Auf dem Production-Server (Hetzner 3)
-ssh payload@162.55.85.18
-./scripts/deploy-production.sh
-
-# Mit Optionen
-./scripts/deploy-production.sh -y # Ohne Bestätigung
-./scripts/deploy-production.sh --skip-backup # Ohne Backup
-./scripts/deploy-production.sh --rollback # Rollback zur vorherigen Version
-./scripts/deploy-production.sh --dry-run # Zeigt was passieren würde
-```
-
-**GitHub Secrets erforderlich:**
-- `STAGING_SSH_KEY` - SSH Private Key für sv-payload
-- `PRODUCTION_SSH_KEY` - SSH Private Key für Hetzner 3
+Credentials in `~/.pgpass` (chmod 600), nie Klartext in `.env`.
## Dokumentation
-### Hauptdokumentation
-- `CLAUDE.md` - Diese Datei (Projekt-Übersicht für AI-Assistenten)
-- `docs/INFRASTRUCTURE.md` - Infrastruktur-Übersicht (Dev + Prod)
+### Projekt-Docs
+- `docs/INFRASTRUCTURE.md` - Infrastruktur (Dev + Prod, PgBouncer, Server)
- `docs/DEPLOYMENT.md` - Deployment-Prozess & Checklisten
-- `docs/DEPLOYMENT_STRATEGY.md` - Vollständige Deployment-Strategie (Dev → Prod)
-- `docs/PROJECT_STATUS.md` - Aktueller Projektstatus & Roadmap
-- `docs/STAGING-DEPLOYMENT.md` - Staging Deployment Workflow
+- `docs/DEPLOYMENT_STRATEGY.md` - Vollständige Deployment-Strategie
+- `docs/PROJECT_STATUS.md` - Projektstatus & Roadmap
+- `docs/CLAUDE_REFERENCE.md` - **Detaillierte Subsystem-Referenz** (E-Mail, Queue, Retention, Community, etc.)
### Anleitungen
-- `docs/anleitungen/TODO.md` - Task-Liste & Changelog
+- `docs/anleitungen/API_ANLEITUNG.md` - API-Dokumentation (alle Endpoints + curl-Beispiele)
- `docs/anleitungen/SECURITY.md` - Sicherheitsrichtlinien
- `docs/anleitungen/FRONTEND.md` - Frontend-Entwicklung (sv-frontend)
-- `docs/anleitungen/API_ANLEITUNG.md` - API-Dokumentation
-- `docs/anleitungen/framework-monitoring.md` - Framework-Updates beobachten
+- `docs/anleitungen/TODO.md` - Task-Liste & Changelog
### Scripts & Backup
- `scripts/backup/README.md` - Backup-System Dokumentation
-*Letzte Aktualisierung: 14.02.2026 (YouTube Thumbnail-Download, Bulk-Endpoint, Channel-Image-Hook)*
+*Letzte Aktualisierung: 14.02.2026*
diff --git a/docs/CLAUDE_REFERENCE.md b/docs/CLAUDE_REFERENCE.md
new file mode 100644
index 0000000..64c2b3c
--- /dev/null
+++ b/docs/CLAUDE_REFERENCE.md
@@ -0,0 +1,428 @@
+# Payload CMS - Detaillierte Subsystem-Referenz
+
+> Diese Datei enthält detaillierte Dokumentation zu den Subsystemen des Projekts.
+> Kurzübersicht und Schlüsseldateien: siehe `CLAUDE.md`.
+
+## E-Mail-System
+
+Multi-Tenant E-Mail-System mit tenant-spezifischer SMTP-Konfiguration.
+
+**Architektur:**
+- Globaler SMTP als Fallback (via .env)
+- Tenant-spezifische SMTP in Tenants Collection
+- Transporter-Caching mit automatischer Invalidierung
+- EmailLogs Collection für Audit-Trail
+
+**Tenant E-Mail-Konfiguration:**
+```
+Tenants → email → fromAddress, fromName, replyTo
+ → email → useCustomSmtp (Checkbox)
+ → email → smtp → host, port, secure, user, pass
+```
+
+**API-Endpoint `/api/send-email`:**
+```bash
+curl -X POST https://pl.porwoll.tech/api/send-email \
+ -H "Content-Type: application/json" \
+ -H "Cookie: payload-token=..." \
+ -d '{
+ "to": "empfaenger@example.com",
+ "subject": "Betreff",
+ "html": "Inhalt
",
+ "tenantId": 1
+ }'
+```
+
+**Sicherheit:**
+- Authentifizierung erforderlich
+- Tenant-Zugriffskontrolle (User muss Tenant-Mitglied sein)
+- Rate-Limiting: 10 E-Mails/Minute pro User
+- SMTP-Passwort nie in API-Responses
+
+**Dateien:**
+- `src/lib/email/tenant-email-service.ts` - Haupt-Service
+- `src/lib/email/payload-email-adapter.ts` - Payload-Integration
+- `src/hooks/invalidateEmailCache.ts` - Cache-Invalidierung
+
+## Newsletter (Double Opt-In)
+
+DSGVO-konformes Newsletter-System mit Double Opt-In.
+
+**Flow:**
+1. User meldet sich an → Status: `pending`, Token wird generiert
+2. Double Opt-In E-Mail wird automatisch gesendet
+3. User klickt Bestätigungs-Link → Status: `confirmed`
+4. Willkommens-E-Mail wird gesendet
+5. Abmeldung jederzeit über Link in E-Mails möglich
+
+**API-Endpoints:**
+```bash
+# Anmeldung
+POST /api/newsletter/subscribe
+{"email": "...", "firstName": "...", "tenantId": 1, "source": "footer"}
+
+# Bestätigung (via Link aus E-Mail)
+GET /api/newsletter/confirm?token=
+
+# Abmeldung (via Link aus E-Mail)
+GET /api/newsletter/unsubscribe?token=
+```
+
+**Features:**
+- Token-Ablauf nach 48 Stunden
+- Rate-Limiting: 5 Anmeldungen/10 Minuten pro IP
+- Erneute Anmeldung nach Abmeldung möglich
+
+**Dateien:**
+- `src/lib/email/newsletter-service.ts` - Service-Logik
+- `src/lib/email/newsletter-templates.ts` - E-Mail-Templates
+- `src/hooks/sendNewsletterConfirmation.ts` - Hook
+
+## BullMQ Job Queue
+
+Asynchrone Job-Verarbeitung mit Redis als Backend.
+
+**Queue-Worker:** Läuft als separater PM2-Prozess (`pm2 logs queue-worker`).
+
+### Email Queue
+
+```typescript
+import { queueEmail } from '@/lib/queue'
+
+await queueEmail({
+ tenantId: 1,
+ to: 'empfaenger@example.com',
+ subject: 'Betreff',
+ html: 'Inhalt
',
+ source: 'form-submission'
+})
+```
+
+### PDF Queue
+
+```bash
+# PDF aus HTML generieren
+POST /api/generate-pdf
+{"source": "html", "html": "Test
", "filename": "test.pdf"}
+
+# Job-Status abfragen
+GET /api/generate-pdf?jobId=abc123
+```
+
+```typescript
+import { queuePdfFromHtml, queuePdfFromUrl, getPdfJobStatus } from '@/lib/queue'
+
+const job = await queuePdfFromHtml('Test
', { filename: 'test.pdf' })
+const job2 = await queuePdfFromUrl('https://example.com', { format: 'A4' })
+const status = await getPdfJobStatus(job.id)
+```
+
+### Worker-Konfiguration
+
+Über `ecosystem.config.cjs`:
+- `QUEUE_EMAIL_CONCURRENCY`: Parallele E-Mail-Jobs (default: 3)
+- `QUEUE_PDF_CONCURRENCY`: Parallele PDF-Jobs (default: 2)
+- `QUEUE_RETENTION_CONCURRENCY`: Parallele Retention-Jobs (default: 1)
+- `QUEUE_DEFAULT_RETRY`: Retry-Versuche (default: 3)
+- `QUEUE_REDIS_DB`: Redis-Datenbank für Queue (default: 1)
+
+**Dateien:**
+- `src/lib/queue/queue-service.ts` - Zentrale Queue-Verwaltung
+- `src/lib/queue/jobs/email-job.ts` - E-Mail-Job
+- `src/lib/queue/jobs/pdf-job.ts` - PDF-Job
+- `src/lib/queue/workers/email-worker.ts` - E-Mail-Worker
+- `src/lib/queue/workers/pdf-worker.ts` - PDF-Worker
+- `scripts/run-queue-worker.ts` - Worker-Starter
+
+## Data Retention
+
+Automatische Datenbereinigung für DSGVO-Compliance und Speicheroptimierung.
+
+### Retention Policies
+
+| Collection | Retention | Umgebungsvariable |
+|------------|-----------|-------------------|
+| email-logs | 90 Tage | `RETENTION_EMAIL_LOGS_DAYS` |
+| audit-logs | 90 Tage | `RETENTION_AUDIT_LOGS_DAYS` |
+| consent-logs | 3 Jahre | `RETENTION_CONSENT_LOGS_DAYS` |
+| media (orphans) | 30 Tage | `RETENTION_MEDIA_ORPHAN_MIN_AGE_DAYS` |
+
+Scheduler: Täglich 03:00 Uhr (`RETENTION_CRON_SCHEDULE`).
+
+### API-Endpoint `/api/retention`
+
+```bash
+# Konfiguration abrufen
+GET /api/retention
+
+# Job-Status
+GET /api/retention?jobId=abc123
+
+# Manueller Job
+POST /api/retention
+{"type": "full"} # Alle Policies
+{"type": "collection", "collection": "email-logs"} # Einzelne Collection
+{"type": "media-orphans"} # Nur Media-Orphans
+```
+
+**Architektur:**
+```
+Scheduler (Cron) → Retention Queue (BullMQ) → Retention Worker
+ → Email-Logs (createdAt) + Audit-Logs (createdAt) + Consent-Logs (expiresAt)
+ → Media-Orphan-Cleanup
+```
+
+**Dateien:**
+- `src/lib/retention/retention-config.ts` - Zentrale Konfiguration
+- `src/lib/retention/cleanup-service.ts` - Lösch-Logik
+- `src/lib/queue/jobs/retention-job.ts` - Job-Definition
+- `src/lib/queue/workers/retention-worker.ts` - Worker
+- `src/app/(payload)/api/retention/route.ts` - API-Endpoint
+
+## Redis Caching
+
+```typescript
+import { redis } from '@/lib/redis'
+
+await redis.set('key', JSON.stringify(data), 'EX', 60) // TTL in Sekunden
+const cached = await redis.get('key')
+await redis.keys('posts:*').then(keys => keys.length && redis.del(...keys)) // Pattern-Invalidierung
+```
+
+## FormSubmissions CRM
+
+Die FormSubmissions Collection wurde zu einem leichtgewichtigen CRM erweitert.
+
+**Status-Workflow:** Neu → Gelesen → In Bearbeitung → Warten → Erledigt → Archiviert
+
+**Features:**
+- Priorität (Hoch/Normal/Niedrig)
+- Zuständigkeits-Zuweisung an User
+- Interne Notizen mit Auto-Autor und Zeitstempel
+- Antwort-Tracking (Methode, Zeitstempel, Zusammenfassung)
+- Tags zur Kategorisierung
+- Auto-Markierung als gelesen beim ersten Öffnen
+
+**Dateien:**
+- `src/collections/FormSubmissionsOverrides.ts` - Feld-Definitionen
+- `src/hooks/formSubmissionHooks.ts` - Automatisierungen
+
+## Community Management System
+
+Plattformübergreifendes Community Management für YouTube, Facebook und Instagram.
+
+### Architektur
+
+```
+Admin UI (Inbox + Analytics)
+ → /api/community/* (sync, stats, reply, generate-reply, export, stream)
+ → UnifiedSyncService
+ → YouTube Sync + Facebook Sync + Instagram Sync
+ → CommunityInteractions (einheitliche Collection)
+```
+
+### Admin UI
+
+**Community Inbox** (`/admin/community/inbox`):
+- Einheitliche Ansicht aller Kommentare (YouTube + Facebook + Instagram)
+- Filter nach Plattform, Status, Priorität, Sentiment, Flags
+- AI-generierte Antwort-Vorschläge (Claude)
+- Echtzeit-Updates via SSE (`/api/community/stream`)
+- Export als CSV/JSON
+
+**Community Analytics** (`/admin/community/analytics`):
+- KPI-Cards, Sentiment-Trend, Topic-Cloud, Response-Metriken, Kanal-Vergleich
+
+### Meta (Facebook + Instagram) Integration
+
+**OAuth-Flow:**
+1. Admin öffnet `/api/auth/meta?socialAccountId=X&accountType=both`
+2. Redirect zu Facebook OAuth (12 Scopes)
+3. Callback: Short-Lived → Long-Lived Token (60 Tage)
+4. Facebook Pages + Instagram Business Accounts werden geladen
+5. Token + Account-Daten in SocialAccounts gespeichert
+
+**Scopes:**
+- Facebook: `pages_show_list`, `pages_read_engagement`, `pages_manage_posts`, `pages_read_user_content`, `pages_manage_engagement`, `pages_messaging`
+- Instagram: `instagram_basic`, `instagram_manage_comments`, `instagram_manage_messages`, `instagram_content_publish`
+
+### API-Endpoints
+
+| Endpoint | Methode | Beschreibung |
+|----------|---------|--------------|
+| `/api/community/sync` | POST | Manueller Sync (alle Plattformen) |
+| `/api/community/sync` | GET | Sync-Status |
+| `/api/community/sync-status` | GET | Detaillierter Status mit Account-Stats |
+| `/api/community/stats` | GET | Interaktions-Statistiken |
+| `/api/community/reply` | POST | Antwort senden |
+| `/api/community/generate-reply` | POST | AI-Antwort generieren (Claude) |
+| `/api/community/export` | GET | Daten-Export (CSV/JSON) |
+| `/api/community/stream` | GET | SSE-Stream für Echtzeit-Updates |
+| `/api/community/analytics/*` | GET | Analytics-Daten (6 Endpoints) |
+| `/api/auth/meta` | GET | Meta OAuth starten |
+| `/api/auth/meta/callback` | GET | Meta OAuth Callback |
+
+### Sync-Trigger
+
+| Trigger | Endpoint | Plattformen |
+|---------|----------|-------------|
+| Cron (alle 15 Min) | `/api/cron/community-sync` | Alle aktiven Accounts |
+| Manuell (Inbox-Button) | `/api/community/sync` (POST) | Alle (optional filterbar) |
+| YouTube-spezifisch | `/api/cron/youtube-sync` | Nur YouTube |
+
+### CommunityRules (Automatisierung)
+
+**Trigger-Typen:** `keyword`, `sentiment`, `question_detected`, `medical_detected`, `influencer` (>10k Follower), `all_new`, `contains_link`, `contains_email`
+
+**Aktionen:** `set_priority`, `assign_to`, `set_flag`, `suggest_template`, `send_notification`, `flag_medical`, `escalate`, `mark_spam`, `set_deadline`
+
+### Wichtige Dateien
+
+```
+src/lib/integrations/meta/
+├── MetaBaseClient.ts # HTTP-Basis mit Retry + Pagination
+├── FacebookClient.ts # Facebook Graph API Client
+├── InstagramClient.ts # Instagram Graph API Client
+├── FacebookSyncService.ts # Facebook Kommentar-Sync
+├── InstagramSyncService.ts # Instagram Kommentar-Sync
+├── oauth.ts # Meta OAuth 2.0 Flow
+└── index.ts # Re-Exports
+
+src/lib/jobs/
+├── UnifiedSyncService.ts # Orchestriert alle Plattform-Syncs
+├── syncAllComments.ts # YouTube-spezifischer Sync (Legacy)
+└── JobLogger.ts # Strukturiertes Logging
+
+src/app/(payload)/api/
+├── auth/meta/ # OAuth Start + Callback
+├── community/ # Community-Endpoints
+└── cron/community-sync/ # Cron-Trigger
+```
+
+## Timeline Collection
+
+Dedizierte Collection für chronologische Darstellungen.
+
+**Typen:** `history`, `milestones`, `releases`, `career`, `events`, `process`
+
+**Event-Features:** Flexible Datumsformate, Kategorien, Wichtigkeitsstufen, Bilder, Links, Rich-Text
+
+**Display-Optionen:** Layouts (vertikal, alternierend, horizontal, kompakt), Sortierung, Gruppierung nach Jahr
+
+**Prozess-spezifische Felder (type=process):**
+- `stepNumber`, `duration`, `responsible`, `actionRequired`, `deliverables`
+
+**API:** `GET /api/timelines?tenant=1[&type=history][&slug=...][&locale=en]`
+
+## Workflows Collection
+
+Komplexe Prozess-Darstellungen mit Phasen, Abhängigkeiten und Status-Tracking.
+
+**Typen:** `project`, `business`, `approval`, `onboarding`, `support`, `development`, `marketing`, `other`
+
+**Phasen-Struktur:**
+```
+Workflow → Phasen (Array)
+ → name, description, icon, color, estimatedDuration, responsible, deliverables
+ → Schritte (Array)
+ → name, description, stepType, priority, dependencies, conditions, checklist, resources, outputs
+```
+
+**Display:** Layouts (vertical, horizontal, flowchart, kanban, gantt), Farbschema (phase, status, priority, brand)
+
+**API:** `GET /api/workflows?tenant=1[&type=project][&complexity=medium][&slug=...][&locale=en]`
+
+## HeroSliderBlock Features
+
+**Slides (1-10):** Hintergrundbild (Desktop + Mobil), Headline + Subline (lokalisiert), Text-Ausrichtung, Overlay (Farbe, Deckkraft, Gradient), 2 CTA-Buttons
+
+**Animationen:** fade, slide, zoom, flip, none (300-1200ms)
+
+**Autoplay:** Intervall 3-10s, Pause bei Hover/Interaktion
+
+**Navigation:** Pfeile (verschiedene Stile), Dots (Punkte, Striche, Nummern, Thumbnails, Fortschritt), Touch-Swipe, Tastatur
+
+**Layout:** Höhe (Vollbild bis kompakt), Mobile-Höhe, Content-Breite
+
+## CI/CD Pipeline Details
+
+### ci.yml (Main CI Pipeline)
+Läuft bei Push/PR auf `main` und `develop`:
+- **lint:** ESLint (flat config, 0 errors)
+- **typecheck:** TypeScript Compiler (`tsc --noEmit`, 4GB heap)
+- **test:** Unit & Integration Tests (Vitest)
+- **build:** Next.js Production Build
+- **e2e:** Playwright E2E Tests
+
+### security.yml
+Gitleaks (Secret Scanning), pnpm audit, CodeQL (SAST), Security Tests
+
+### deploy-staging.yml
+- Trigger: Push auf `develop` oder manual dispatch
+- Ablauf: Pre-checks → SSH → Git Pull → Dependencies → Migrations → Build → PM2 Restart → Health Check
+- Secret: `STAGING_SSH_KEY`
+
+```bash
+# Manuelles Staging-Deployment
+./scripts/deploy-staging.sh
+./scripts/deploy-staging.sh --skip-build
+./scripts/deploy-staging.sh --skip-migrations
+```
+
+### deploy-production.yml
+- Trigger: Manual dispatch
+- Features: Pre-flight Checks, Database Backup, Health Check, Auto-Rollback
+- Secrets: `STAGING_SSH_KEY`, `PRODUCTION_SSH_KEY`
+
+```bash
+gh workflow run deploy-production.yml # Via GitHub Actions
+./scripts/deploy-production.sh # Auf Server
+./scripts/deploy-production.sh --rollback # Rollback
+./scripts/deploy-production.sh --dry-run # Dry-Run
+```
+
+## PgBouncer Connection Pooling
+
+Läuft auf dem App-Server (127.0.0.1:6432), pooled Verbindungen zu PostgreSQL (10.10.181.101:5432).
+
+**Konfiguration:** `/etc/pgbouncer/pgbouncer.ini`
+
+| Parameter | Wert |
+|-----------|------|
+| pool_mode | transaction |
+| default_pool_size | 20 |
+| min_pool_size | 5 |
+| reserve_pool_size | 5 |
+| max_db_connections | 50 |
+| max_client_conn | 200 |
+
+**TLS:** `server_tls_sslmode = require` (TLS 1.3)
+
+```bash
+# Statistiken
+PGPASSWORD="$DB_PASSWORD" psql -h 127.0.0.1 -p 6432 -U payload -d pgbouncer -c "SHOW POOLS;"
+
+# Direkte Verbindung für Migrationen (umgeht PgBouncer)
+./scripts/db-direct.sh migrate
+./scripts/db-direct.sh psql
+```
+
+## Cron Jobs (Details)
+
+Alle erfordern `Authorization: Bearer $CRON_SECRET`.
+
+```bash
+# Community Sync manuell
+curl -X POST "https://your-domain/api/cron/community-sync" \
+ -H "Authorization: Bearer $CRON_SECRET" \
+ -d '{"platforms": ["youtube", "facebook"]}'
+
+# Token Refresh (Dry-Run)
+curl "https://your-domain/api/cron/token-refresh?dryRun=true" \
+ -H "Authorization: Bearer $CRON_SECRET"
+```
+
+**Monitoring:**
+- HEAD-Requests: Status-Header (`X-Sync-Running`, `X-Last-Run`)
+- Bei laufendem Job: HTTP 423 (Locked)
+- Fehlerhafte Tokens → `yt-notifications`