# Payload CMS Multi-Tenant Project ## Projektübersicht Multi-Tenant CMS für 4 Websites unter einer Payload CMS 3.x Instanz: - porwoll.de - complexcaresolutions.de - gunshin.de - zweitmein.ng ## Tech Stack - **CMS:** Payload CMS 3.x - **Framework:** Next.js 15.4.7 - **Sprache:** TypeScript - **Datenbank:** PostgreSQL 17 (separater Server) - **Connection Pool:** PgBouncer 1.24.1 (Transaction-Mode) - **Reverse Proxy:** Caddy 2.10.2 mit Let's Encrypt - **Process Manager:** PM2 - **Package Manager:** pnpm - **Cache:** Redis (optional, mit In-Memory-Fallback) - **Job Queue:** BullMQ (Redis-basiert) ## Architektur ``` Internet → 37.24.237.181 → Caddy (443) → Payload (3000) ↓ PgBouncer (6432) ↓ PostgreSQL (10.10.181.101:5432) ``` | Server | IP | Funktion | | --------------------- | ------------- | ---------- | | sv-payload (LXC 700) | 10.10.181.100 | App Server | | sv-postgres (LXC 701) | 10.10.181.101 | Datenbank | ## Wichtige Pfade ``` /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.c2sgmbh.de NEXT_PUBLIC_SERVER_URL=https://pl.c2sgmbh.de 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 SEND_EMAIL_ALLOWED_IPS= # Optional: Komma-separierte IPs/CIDRs BLOCKED_IPS= # Optional: Global geblockte IPs ``` ## 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` ## Wichtige Befehle ```bash # Entwicklung pnpm dev # Production Build pnpm build # Migrationen pnpm payload migrate:create pnpm payload migrate # ImportMap nach Plugin-Änderungen pnpm payload generate:importmap # PM2 pm2 status pm2 logs payload pm2 logs queue-worker pm2 restart payload 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 # Datenbank prüfen # Verwende ./scripts/db-direct.sh psql oder: PGPASSWORD="$DB_PASSWORD" psql -h 10.10.181.101 -U payload -d payload_db # Backup /home/payload/backups/postgres/backup-db.sh --verbose # Manuelles Backup scripts/backup/setup-backup.sh # Backup-System einrichten ``` ## Workflow nach Code-Änderungen 1. Code ändern 2. `pnpm build` 3. `pm2 restart payload` 4. Testen unter https://pl.c2sgmbh.de/admin ## Bekannte Besonderheiten - **ES Modules:** package.json hat `"type": "module"`, daher PM2 Config als `.cjs` - **Plugin ImportMap:** Nach Plugin-Änderungen `pnpm payload generate:importmap` ausführen - **User-Tenant-Zuweisung:** Neue User müssen manuell Tenants zugewiesen bekommen - **Admin Login:** Custom Route mit Audit-Logging, unterstützt JSON und `_payload` FormData ## 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: ```bash pm2 stop payload # Speicher freigeben 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 (i18n) Das System unterstützt Deutsch (default) und Englisch: - **Admin UI:** `@payloadcms/translations` für DE/EN - **Content:** Localization mit Fallback auf Deutsch - **Datenbank:** 36 `_locales` Tabellen für lokalisierte Felder - **API:** `?locale=de` oder `?locale=en` Parameter - **Frontend:** Routing über `/[locale]/...` ```bash # Locales in der Datenbank prüfen # Verwende ./scripts/db-direct.sh psql oder: PGPASSWORD="$DB_PASSWORD" psql -h 10.10.181.101 -U payload -d payload_db -c "\dt *_locales" ``` ## URLs - **Admin Panel:** https://pl.c2sgmbh.de/admin - **API:** https://pl.c2sgmbh.de/api - **API-Dokumentation (Swagger UI):** https://pl.c2sgmbh.de/api/docs - **OpenAPI JSON:** https://pl.c2sgmbh.de/api/openapi.json - **E-Mail API:** https://pl.c2sgmbh.de/api/send-email (POST, Auth erforderlich) - **Test-E-Mail:** https://pl.c2sgmbh.de/api/test-email (POST, Admin erforderlich) - **E-Mail Stats:** https://pl.c2sgmbh.de/api/email-logs/stats (GET, Auth erforderlich) - **PDF-Generierung:** https://pl.c2sgmbh.de/api/generate-pdf (POST/GET, Auth erforderlich) - **Newsletter Anmeldung:** https://pl.c2sgmbh.de/api/newsletter/subscribe (POST, öffentlich) - **Newsletter Bestätigung:** https://pl.c2sgmbh.de/api/newsletter/confirm (GET/POST) - **Newsletter Abmeldung:** https://pl.c2sgmbh.de/api/newsletter/unsubscribe (GET/POST) - **Timeline API:** https://pl.c2sgmbh.de/api/timelines (GET, öffentlich, tenant required) - **Workflows API:** https://pl.c2sgmbh.de/api/workflows (GET, öffentlich, tenant required) ## Security-Features ### 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 ### CSRF-Schutz - Double Submit Cookie Pattern - Origin-Header-Validierung - Token-Endpoint: `GET /api/csrf-token` - Admin-Panel hat eigenen CSRF-Schutz ### IP-Allowlist - Konfigurierbar via `SEND_EMAIL_ALLOWED_IPS` - Unterstützt IPs, CIDRs (`192.168.1.0/24`) und Wildcards (`10.10.*.*`) - Globale Blocklist via `BLOCKED_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.c2sgmbh.de/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.c2sgmbh.de/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.c2sgmbh.de/api/newsletter/confirm?token= # Abmeldung (via Link aus E-Mail) GET https://pl.c2sgmbh.de/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.c2sgmbh.de/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.c2sgmbh.de/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_DEFAULT_RETRY`: Retry-Versuche (default: 3) - `QUEUE_REDIS_DB`: Redis-Datenbank für Queue (default: 1) ## 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 | Block | Slug | Beschreibung | |-------|------|--------------| | HeroBlock | hero-block | Einzelner Hero mit Bild, Headline, CTA | | HeroSliderBlock | hero-slider-block | Hero-Slider mit mehreren Slides | | 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 | | 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 | | BeforeAfterBlock | before-after-block | Vorher/Nachher Bildvergleich (porwoll.de) | ### 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 | 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 | | Posts | posts | Blog/News/Presse mit Kategorien | | Categories | categories | Kategorien für Posts | | Portfolios | portfolios | Portfolio-Galerien (Fotografie) | | PortfolioCategories | portfolio-categories | Kategorien für Portfolios | | Testimonials | testimonials | Kundenbewertungen | | FAQs | faqs | Häufig gestellte Fragen (FAQ) | | Team | team | Team-Mitglieder und Mitarbeiter | | ServiceCategories | service-categories | Kategorien für Leistungen | | Services | services | Leistungen und Dienstleistungen | | NewsletterSubscribers | newsletter-subscribers | Newsletter mit Double Opt-In | | SocialLinks | social-links | Social Media Links | | Forms | forms | Formular-Builder | | FormSubmissions | form-submissions | Formular-Einsendungen mit Status-Workflow | | EmailLogs | email-logs | E-Mail-Protokollierung | | AuditLogs | audit-logs | Security Audit Trail | | CookieConfigurations | cookie-configurations | Cookie-Banner Konfiguration | | CookieInventory | cookie-inventory | Cookie-Inventar | | ConsentLogs | consent-logs | Consent-Protokollierung | | Timelines | timelines | Chronologische Events (Geschichte, Meilensteine) | | Workflows | workflows | Komplexe Prozesse mit Phasen und Schritten | | Bookings | bookings | Fotografie-Buchungen (porwoll.de) | | Certifications | certifications | Zertifizierungen (C2S) | | Projects | projects | Game-Development-Projekte (gunshin.de) | ## 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.c2sgmbh.de/api/timelines?tenant=1" # Nach Typ filtern curl "https://pl.c2sgmbh.de/api/timelines?tenant=1&type=history" # Einzelne Timeline curl "https://pl.c2sgmbh.de/api/timelines?tenant=1&slug=company-history" # Mit Sprache curl "https://pl.c2sgmbh.de/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.c2sgmbh.de/api/workflows?tenant=1" # Nach Typ filtern curl "https://pl.c2sgmbh.de/api/workflows?tenant=1&type=project" # Nach Komplexität filtern curl "https://pl.c2sgmbh.de/api/workflows?tenant=1&complexity=medium" # Einzelner Workflow curl "https://pl.c2sgmbh.de/api/workflows?tenant=1&slug=web-project" # Mit Sprache curl "https://pl.c2sgmbh.de/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 ## Globals | Global | Slug | Beschreibung | |--------|------|--------------| | SiteSettings | site-settings | Allgemeine Website-Einstellungen | | Navigation | navigation | Navigationsmenü | | SEOSettings | seo-settings | SEO-Einstellungen | | PrivacyPolicySettings | privacy-policy-settings | Datenschutz-Einstellungen | ## Test Suite ```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% ## CI/CD Pipeline GitHub Actions Workflows in `.github/workflows/`: ### ci.yml (Main CI Pipeline) Läuft bei Push/PR auf `main` und `develop`: | Job | Beschreibung | |-----|--------------| | **lint** | ESLint + Prettier Check | | **typecheck** | TypeScript Compiler (`tsc --noEmit`) | | **test** | Unit & Integration Tests (Vitest) | | **build** | Next.js Production Build | | **e2e** | Playwright E2E Tests | **Lokale Ausführung:** ```bash pnpm lint # ESLint pnpm typecheck # TypeScript Check 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.c2sgmbh.de - **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.c2sgmbh.de) ./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` ## Dokumentation - `CLAUDE.md` - Diese Datei (Projekt-Übersicht) - `docs/INFRASTRUCTURE.md` - Server-Architektur & Deployment - `docs/anleitungen/TODO.md` - Task-Liste & Roadmap - `docs/anleitungen/SECURITY.md` - Sicherheitsrichtlinien - `scripts/backup/README.md` - Backup-System Dokumentation *Letzte Aktualisierung: 14.12.2025*