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

457 lines
11 KiB
Markdown

# 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`:
```typescript
// 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`:
```typescript
// 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
```bash
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
```bash
# 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
```typescript
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
}
}
```