cms.c2sgmbh/docs/PROMPT_PRIVACY_POLICY_PAYLOAD.md
Martin Porwoll a88e4f60d0 test: add E2E and integration tests with documentation
Tests:
- Update frontend.e2e.spec.ts with locale testing
- Add search.e2e.spec.ts for search functionality
- Add i18n.int.spec.ts for localization tests
- Add search.int.spec.ts for search integration
- Update playwright.config.ts

Documentation:
- Add CLAUDE.md with project instructions
- Add docs/ directory with detailed documentation
- Add scripts/ for utility scripts

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 08:19:52 +00:00

11 KiB

PROMPT: Datenschutzerklärung Integration - Payload Backend

Kontext

Du arbeitest auf dem Server sv-payload (10.10.181.100) im Verzeichnis /home/payload/payload-cms.

Die Datenschutzerklärungen werden extern vom Datenschutzbeauftragten über Alfright gepflegt und sollen per iframe eingebunden werden. Die Konfiguration (Tenant-Key, Styling) wird pro Mandant in Payload CMS verwaltet.

Aufgabe

Erweitere das System um eine PrivacyPolicySettings Collection für die Verwaltung der externen Datenschutzerklärung pro Tenant.


Schritt 1: Collection erstellen

Erstelle src/collections/PrivacyPolicySettings.ts:

// src/collections/PrivacyPolicySettings.ts

import type { CollectionConfig } from 'payload'
import { tenantScopedPublicRead, authenticatedOnly } from '../lib/tenantAccess'

/**
 * PrivacyPolicySettings Collection
 * 
 * Konfiguration für externe Datenschutzerklärung (Alfright) pro Tenant.
 * Öffentlich lesbar (für Frontend), aber tenant-isoliert.
 */
export const PrivacyPolicySettings: CollectionConfig = {
  slug: 'privacy-policy-settings',
  admin: {
    useAsTitle: 'title',
    group: 'Consent Management',
    description: 'Externe Datenschutzerklärung Konfiguration (Alfright)',
  },
  access: {
    read: tenantScopedPublicRead,
    create: authenticatedOnly,
    update: authenticatedOnly,
    delete: authenticatedOnly,
  },
  fields: [
    {
      name: 'tenant',
      type: 'relationship',
      relationTo: 'tenants',
      required: true,
      unique: true,
      admin: {
        description: 'Jeder Tenant kann nur eine Konfiguration haben',
      },
    },
    {
      name: 'title',
      type: 'text',
      required: true,
      defaultValue: 'Datenschutzerklärung',
      admin: {
        description: 'Interner Titel zur Identifikation',
      },
    },
    {
      name: 'provider',
      type: 'select',
      required: true,
      defaultValue: 'alfright',
      options: [
        { label: 'Alfright (extern via iframe)', value: 'alfright' },
        { label: 'Eigener Text (nicht implementiert)', value: 'internal' },
      ],
      admin: {
        description: 'Quelle der Datenschutzerklärung',
      },
    },
    
    // Alfright Konfiguration
    {
      name: 'alfright',
      type: 'group',
      label: 'Alfright Konfiguration',
      admin: {
        condition: (data) => data?.provider === 'alfright',
        description: 'Einstellungen für die Alfright Integration',
      },
      fields: [
        {
          name: 'tenantId',
          type: 'text',
          required: true,
          defaultValue: 'alfright_schutzteam',
          admin: {
            description: 'Alfright Tenant-ID (aus dem iframe-Code)',
          },
        },
        {
          name: 'apiKey',
          type: 'text',
          required: true,
          admin: {
            description: 'Alfright API-Key / Dokument-ID (aus dem iframe-Code, z.B. "9f315103c43245bcb0806dd56c2be757")',
          },
        },
        {
          name: 'language',
          type: 'select',
          required: true,
          defaultValue: 'de-de',
          options: [
            { label: 'Deutsch (Deutschland)', value: 'de-de' },
            { label: 'Deutsch (Österreich)', value: 'de-at' },
            { label: 'Deutsch (Schweiz)', value: 'de-ch' },
            { label: 'Englisch (UK)', value: 'en-gb' },
            { label: 'Englisch (US)', value: 'en-us' },
          ],
          admin: {
            description: 'Sprache der Datenschutzerklärung',
          },
        },
        {
          name: 'iframeHeight',
          type: 'number',
          required: true,
          defaultValue: 4000,
          min: 500,
          max: 10000,
          admin: {
            description: 'Höhe des iframes in Pixeln (empfohlen: 3000-5000)',
          },
        },
      ],
    },

    // Styling (passend zum Website-Theme)
    {
      name: 'styling',
      type: 'group',
      label: 'Styling',
      admin: {
        condition: (data) => data?.provider === 'alfright',
        description: 'Farben und Schriften an das Website-Design anpassen',
      },
      fields: [
        {
          name: 'headerColor',
          type: 'text',
          required: true,
          defaultValue: '#ca8a04',
          admin: {
            description: 'Farbe der Überschriften (Hex-Code, z.B. #ca8a04 für Gold)',
          },
        },
        {
          name: 'headerFont',
          type: 'text',
          required: true,
          defaultValue: 'Inter, sans-serif',
          admin: {
            description: 'Schriftart der Überschriften',
          },
        },
        {
          name: 'headerSize',
          type: 'text',
          required: true,
          defaultValue: '24px',
          admin: {
            description: 'Schriftgröße der Hauptüberschriften',
          },
        },
        {
          name: 'subheaderSize',
          type: 'text',
          required: true,
          defaultValue: '18px',
          admin: {
            description: 'Schriftgröße der Unterüberschriften',
          },
        },
        {
          name: 'fontColor',
          type: 'text',
          required: true,
          defaultValue: '#f3f4f6',
          admin: {
            description: 'Textfarbe (Hex-Code, z.B. #f3f4f6 für hellen Text)',
          },
        },
        {
          name: 'textFont',
          type: 'text',
          required: true,
          defaultValue: 'Inter, sans-serif',
          admin: {
            description: 'Schriftart für Fließtext',
          },
        },
        {
          name: 'textSize',
          type: 'text',
          required: true,
          defaultValue: '16px',
          admin: {
            description: 'Schriftgröße für Fließtext',
          },
        },
        {
          name: 'linkColor',
          type: 'text',
          required: true,
          defaultValue: '#ca8a04',
          admin: {
            description: 'Linkfarbe (Hex-Code)',
          },
        },
        {
          name: 'backgroundColor',
          type: 'text',
          required: true,
          defaultValue: '#111827',
          admin: {
            description: 'Hintergrundfarbe (Hex-Code, z.B. #111827 für Dark Theme)',
          },
        },
      ],
    },

    // Cookie-Tabelle Option
    {
      name: 'showCookieTable',
      type: 'checkbox',
      defaultValue: true,
      admin: {
        description: 'Cookie-Tabelle aus CookieInventory unterhalb der Datenschutzerklärung anzeigen',
      },
    },
    {
      name: 'cookieTableTitle',
      type: 'text',
      defaultValue: 'Übersicht der verwendeten Cookies',
      admin: {
        condition: (data) => data?.showCookieTable,
        description: 'Überschrift für die Cookie-Tabelle',
      },
    },
    {
      name: 'cookieTableDescription',
      type: 'textarea',
      defaultValue: 'Ergänzend zur Datenschutzerklärung finden Sie hier eine detaillierte Übersicht aller auf dieser Website eingesetzten Cookies. Sie können Ihre Cookie-Einstellungen jederzeit über den Link "Cookie-Einstellungen" im Footer anpassen.',
      admin: {
        condition: (data) => data?.showCookieTable,
        description: 'Einleitungstext für die Cookie-Tabelle',
      },
    },

    // SEO
    {
      name: 'seo',
      type: 'group',
      label: 'SEO',
      fields: [
        {
          name: 'metaTitle',
          type: 'text',
          defaultValue: 'Datenschutzerklärung',
          admin: {
            description: 'Meta-Titel für die Seite',
          },
        },
        {
          name: 'metaDescription',
          type: 'textarea',
          defaultValue: 'Informationen zum Datenschutz und zur Verarbeitung Ihrer personenbezogenen Daten.',
          admin: {
            description: 'Meta-Beschreibung für Suchmaschinen',
          },
        },
      ],
    },
  ],
}

Schritt 2: Collection in Payload Config registrieren

Aktualisiere src/payload.config.ts:

// Import hinzufügen (bei den anderen Collection-Imports)
import { PrivacyPolicySettings } from './collections/PrivacyPolicySettings'

// In collections Array hinzufügen
collections: [
  Users,
  Media,
  Tenants,
  Pages,
  Posts,
  Categories,
  SocialLinks,
  CookieConfigurations,
  CookieInventory,
  ConsentLogs,
  PrivacyPolicySettings,  // NEU
],

// In multiTenantPlugin collections hinzufügen
plugins: [
  multiTenantPlugin({
    tenantsSlug: 'tenants',
    collections: {
      // ... bestehende Collections ...
      'privacy-policy-settings': {},  // NEU
    },
  }),
],

Schritt 3: Build und Migration

cd /home/payload/payload-cms

# TypeScript Types generieren
pnpm payload generate:types

# Migration erstellen
pnpm payload migrate:create

# Migration ausführen
pnpm payload migrate

# Build
pnpm build

# PM2 neu starten
pm2 restart payload

Schritt 4: Initiale Daten anlegen

Im Admin Panel unter Consent Management → Privacy Policy Settings → Create:

Für porwoll.de (Tenant 1):

Feld Wert
Tenant porwoll.de
Title Datenschutzerklärung porwoll.de
Provider Alfright (extern via iframe)

Alfright Konfiguration:

Feld Wert
Tenant ID alfright_schutzteam
API Key 9f315103c43245bcb0806dd56c2be757
Language Deutsch (Deutschland)
iframe Height 4000

Styling (Dark Theme):

Feld Wert
Header Color #ca8a04
Header Font Inter, sans-serif
Header Size 24px
Subheader Size 18px
Font Color #f3f4f6
Text Font Inter, sans-serif
Text Size 16px
Link Color #ca8a04
Background Color #111827

Cookie-Tabelle:

Feld Wert
Show Cookie Table Aktiviert
Cookie Table Title Übersicht der verwendeten Cookies

SEO:

Feld Wert
Meta Title Datenschutzerklärung | porwoll.de
Meta Description Informationen zum Datenschutz und zur Verarbeitung Ihrer personenbezogenen Daten auf porwoll.de

Schritt 5: API-Test

# Privacy Policy Settings abrufen (mit Host-Header)
curl -s -H "Host: porwoll.de" "http://localhost:3000/api/privacy-policy-settings" | jq

# Ohne Host-Header (sollte verweigert werden)
curl -s "http://localhost:3000/api/privacy-policy-settings" | jq

Zusammenfassung

Datei Aktion
src/collections/PrivacyPolicySettings.ts NEU erstellt
src/payload.config.ts Collection registriert
src/payload-types.ts Automatisch generiert

API-Endpoint

Endpoint Methode Auth Beschreibung
/api/privacy-policy-settings GET Public (tenant-scoped) Datenschutz-Konfiguration

Datenmodell

interface PrivacyPolicySettings {
  id: number
  tenant: Tenant
  title: string
  provider: 'alfright' | 'internal'
  alfright: {
    tenantId: string
    apiKey: string
    language: string
    iframeHeight: number
  }
  styling: {
    headerColor: string
    headerFont: string
    headerSize: string
    subheaderSize: string
    fontColor: string
    textFont: string
    textSize: string
    linkColor: string
    backgroundColor: string
  }
  showCookieTable: boolean
  cookieTableTitle: string
  cookieTableDescription: string
  seo: {
    metaTitle: string
    metaDescription: string
  }
}