cms.c2sgmbh/docs/INFRASTRUCTURE.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

8.1 KiB

Payload CMS Multi-Tenant Infrastructure

Übersicht

Diese Dokumentation beschreibt die Infrastruktur eines Payload CMS 3.x Multi-Tenant-Systems für den Betrieb mehrerer Websites unter einer zentralen CMS-Instanz.

Architektur

┌─────────────────────────────────────────────────────────────────┐
│                        INTERNET                                  │
│                            │                                     │
│                   37.24.237.181 (Public IP)                     │
│                            │                                     │
│                      NAT (Proxmox)                              │
│                    Port 80, 443                                 │
└────────────────────────────┼────────────────────────────────────┘
                             │
┌────────────────────────────┼────────────────────────────────────┐
│                      VLAN 181                                    │
│                   10.10.181.0/24                                 │
│                            │                                     │
│    ┌───────────────────────┴───────────────────────┐            │
│    │                                               │            │
│    ▼                                               ▼            │
│ ┌─────────────────────┐                 ┌─────────────────────┐ │
│ │   LXC 700           │                 │   LXC 701           │ │
│ │   sv-payload        │                 │   sv-postgres       │ │
│ │   10.10.181.100     │────────────────▶│   10.10.181.101     │ │
│ │                     │   Port 5432     │                     │ │
│ │   - Caddy (80/443)  │                 │   - PostgreSQL 17   │ │
│ │   - Node.js 22      │                 │                     │ │
│ │   - Payload CMS     │                 │                     │ │
│ │   - PM2             │                 │                     │ │
│ └─────────────────────┘                 └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Server-Details

LXC 700 - sv-payload (Application Server)

Eigenschaft Wert
IP 10.10.181.100
Öffentlich 37.24.237.181 (via NAT)
OS Debian 13 (Trixie)
CPU 4 Cores
RAM 4 GB
Disk 40 GB
Domain pl.c2sgmbh.de

Installierte Software:

  • Node.js 22 LTS (via NodeSource)
  • pnpm (Package Manager)
  • Caddy 2.10.2 (Reverse Proxy mit automatischem SSL)
  • PM2 (Process Manager)
  • Payload CMS 3.x mit Next.js 15.4.7

Dienste:

  • Caddy läuft als systemd service auf Port 80/443
  • Payload läuft via PM2 auf Port 3000

LXC 701 - sv-postgres (Database Server)

Eigenschaft Wert
IP 10.10.181.101
Öffentlich Nein (nur intern)
OS Debian 13 (Trixie)
CPU 2 Cores
RAM 2 GB
Disk 20 GB

Datenbank:

  • PostgreSQL 17
  • Database: payload_db
  • User: payload
  • Passwort: Finden55
  • Nur erreichbar von 10.10.181.100

Verzeichnisstruktur auf sv-payload

/home/payload/
├── payload-cms/           # Hauptanwendung
│   ├── src/
│   │   ├── collections/
│   │   │   ├── Users.ts
│   │   │   ├── Media.ts
│   │   │   └── Tenants.ts
│   │   ├── payload.config.ts
│   │   └── payload-types.ts
│   ├── .env               # Umgebungsvariablen
│   ├── ecosystem.config.cjs  # PM2 Konfiguration
│   ├── package.json
│   └── .next/             # Next.js Build Output
├── logs/
│   ├── error-0.log
│   └── out-0.log
└── ecosystem.config.cjs   # PM2 Config (Symlink)

Konfigurationsdateien

.env (/home/payload/payload-cms/.env)

DATABASE_URI=postgresql://payload:Finden55@10.10.181.101:5432/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

Caddyfile (/etc/caddy/Caddyfile)

{
    email deine-email@c2sgmbh.de
}

pl.c2sgmbh.de {
    reverse_proxy localhost:3000
    
    request_body {
        max_size 100MB
    }
    
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        -Server
    }
    
    encode gzip zstd
}

PM2 Konfiguration (/home/payload/payload-cms/ecosystem.config.cjs)

module.exports = {
  apps: [{
    name: 'payload',
    cwd: '/home/payload/payload-cms',
    script: 'pnpm',
    args: 'start',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    instances: 1,
    autorestart: true,
    max_memory_restart: '1G',
    error_file: '/home/payload/logs/error.log',
    out_file: '/home/payload/logs/out.log'
  }]
}

Multi-Tenant Konzept

Das System verwendet @payloadcms/plugin-multi-tenant für die Mandantenfähigkeit.

Tenants (Mandanten)

Jeder Tenant repräsentiert eine separate Website:

Tenant Slug Domains
porwoll.de porwoll porwoll.de, www.porwoll.de
Complex Care Solutions GmbH c2s complexcaresolutions.de
Gunshin gunshin gunshin.de
Zweitmeinung zweitmeinung zweitmein.ng

Datenisolation

  • Jeder Content (Media, Pages, Posts etc.) gehört zu genau einem Tenant
  • User werden Tenants zugewiesen und sehen nur deren Inhalte
  • Die Domain-Erkennung erfolgt automatisch durch das Plugin

Datenbank-Tabellen

tenants           - Mandanten-Stammdaten
tenants_domains   - Domain-Zuordnungen
users_tenants     - User-Mandanten-Beziehung (N:M)

Netzwerk & Firewall

UFW Regeln auf sv-payload

22/tcp    ALLOW  10.10.181.0/24   # SSH aus VLAN
80/tcp    ALLOW  Anywhere         # HTTP (ACME)
443/tcp   ALLOW  Anywhere         # HTTPS

UFW Regeln auf sv-postgres

22/tcp    ALLOW  10.10.181.0/24   # SSH aus VLAN
5432/tcp  ALLOW  10.10.181.100    # PostgreSQL nur von Payload

DSGVO-Konformität

Die Architektur wurde bewusst ohne Cloudflare designed:

  • Keine US-Dienste im Datenpfad für Admin-Zugriffe
  • Direkte öffentliche IP statt Proxy
  • Keine Auftragsverarbeiter-Verträge für CDN nötig
  • Redakteur-IPs und Sessions bleiben in DE

Wichtige Befehle

Payload Management

# Als payload User
su - payload
cd ~/payload-cms

# Entwicklung
pnpm dev

# Build für Production
pnpm build

# Migrationen
pnpm payload migrate:create
pnpm payload migrate

# ImportMap generieren (nach Plugin-Änderungen)
pnpm payload generate:importmap

PM2 Management

pm2 status
pm2 logs payload
pm2 restart payload
pm2 stop payload
pm2 start ecosystem.config.cjs

Caddy Management

sudo systemctl status caddy
sudo systemctl restart caddy
sudo caddy validate --config /etc/caddy/Caddyfile

Datenbank

# Von sv-payload aus
PGPASSWORD=Finden55 psql -h 10.10.181.101 -U payload -d payload_db

# Tabellen anzeigen
\dt

# Tenants abfragen
SELECT * FROM tenants;
SELECT * FROM users_tenants;

Zugriff