Extract detailed subsystem documentation into docs/CLAUDE_REFERENCE.md. CLAUDE.md is loaded into every AI conversation - reducing it by 73% saves ~38KB of context window tokens per session while keeping all essential info. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
14 KiB
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:
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": "<p>Inhalt</p>",
"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-Servicesrc/lib/email/payload-email-adapter.ts- Payload-Integrationsrc/hooks/invalidateEmailCache.ts- Cache-Invalidierung
Newsletter (Double Opt-In)
DSGVO-konformes Newsletter-System mit Double Opt-In.
Flow:
- User meldet sich an → Status:
pending, Token wird generiert - Double Opt-In E-Mail wird automatisch gesendet
- User klickt Bestätigungs-Link → Status:
confirmed - Willkommens-E-Mail wird gesendet
- Abmeldung jederzeit über Link in E-Mails möglich
API-Endpoints:
# Anmeldung
POST /api/newsletter/subscribe
{"email": "...", "firstName": "...", "tenantId": 1, "source": "footer"}
# Bestätigung (via Link aus E-Mail)
GET /api/newsletter/confirm?token=<uuid>
# Abmeldung (via Link aus E-Mail)
GET /api/newsletter/unsubscribe?token=<uuid>
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-Logiksrc/lib/email/newsletter-templates.ts- E-Mail-Templatessrc/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
import { queueEmail } from '@/lib/queue'
await queueEmail({
tenantId: 1,
to: 'empfaenger@example.com',
subject: 'Betreff',
html: '<p>Inhalt</p>',
source: 'form-submission'
})
PDF Queue
# PDF aus HTML generieren
POST /api/generate-pdf
{"source": "html", "html": "<h1>Test</h1>", "filename": "test.pdf"}
# Job-Status abfragen
GET /api/generate-pdf?jobId=abc123
import { queuePdfFromHtml, queuePdfFromUrl, getPdfJobStatus } from '@/lib/queue'
const job = await queuePdfFromHtml('<h1>Test</h1>', { 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-Verwaltungsrc/lib/queue/jobs/email-job.ts- E-Mail-Jobsrc/lib/queue/jobs/pdf-job.ts- PDF-Jobsrc/lib/queue/workers/email-worker.ts- E-Mail-Workersrc/lib/queue/workers/pdf-worker.ts- PDF-Workerscripts/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
# 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 Konfigurationsrc/lib/retention/cleanup-service.ts- Lösch-Logiksrc/lib/queue/jobs/retention-job.ts- Job-Definitionsrc/lib/queue/workers/retention-worker.ts- Workersrc/app/(payload)/api/retention/route.ts- API-Endpoint
Redis Caching
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-Definitionensrc/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:
- Admin öffnet
/api/auth/meta?socialAccountId=X&accountType=both - Redirect zu Facebook OAuth (12 Scopes)
- Callback: Short-Lived → Long-Lived Token (60 Tage)
- Facebook Pages + Instagram Business Accounts werden geladen
- 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
developoder manual dispatch - Ablauf: Pre-checks → SSH → Git Pull → Dependencies → Migrations → Build → PM2 Restart → Health Check
- Secret:
STAGING_SSH_KEY
# 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
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)
# 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.
# 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