mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 20:54:11 +00:00
Add comprehensive YouTube feature documentation covering 9 collections, 12 custom API endpoints, 3 cron jobs, admin views, services, hooks, and access control across CLAUDE.md, CLAUDE_REFERENCE.md, and API_ANLEITUNG.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
406 lines
16 KiB
Markdown
406 lines
16 KiB
Markdown
# Payload CMS Multi-Tenant Project
|
|
|
|
## Projektübersicht
|
|
|
|
Multi-Tenant CMS für 3 aktive Websites unter einer Payload CMS 3.x Instanz:
|
|
|
|
- porwoll.de
|
|
- complexcaresolutions.de (c2s)
|
|
- gunshin.de
|
|
|
|
## Tech Stack
|
|
|
|
- **CMS:** Payload CMS 3.76.1
|
|
- **Framework:** Next.js 16.2.0-canary.41
|
|
- **React:** 19.2.3
|
|
- **Sprache:** TypeScript
|
|
- **Runtime:** Node.js 22.x
|
|
- **Datenbank:** PostgreSQL 17.6 (separater Server)
|
|
- **Connection Pool:** PgBouncer 1.24.1 (Transaction-Mode)
|
|
- **Reverse Proxy:** Caddy 2.9.x (Dev) / Nginx (Prod)
|
|
- **Process Manager:** PM2
|
|
- **Package Manager:** pnpm
|
|
- **Cache:** Redis 7.x (optional, In-Memory-Fallback)
|
|
- **Job Queue:** BullMQ (Redis-basiert)
|
|
- **Analytics:** Umami 3.x
|
|
|
|
## Architektur
|
|
|
|
**Development:** `Internet → Cloudflare → Caddy (sv-caddy) → sv-payload:3000 → PgBouncer:6432 → PostgreSQL (sv-postgres:5432)`
|
|
|
|
| Hostname | IP | Service |
|
|
|----------|-----|---------|
|
|
| sv-caddy | 10.10.181.99 | Caddy Reverse Proxy |
|
|
| sv-payload | 10.10.181.100 | Payload CMS + Redis |
|
|
| sv-postgres | 10.10.181.101 | PostgreSQL 17 |
|
|
| sv-frontend | 10.10.181.104 | Multi-Frontend Dev (9 Projekte) |
|
|
|
|
**Production (Hetzner 3):** `cms.c2sgmbh.de:3001` (Payload), `analytics.c2sgmbh.de:3000` (Umami)
|
|
|
|
→ Details: `docs/INFRASTRUCTURE.md`
|
|
|
|
## Multi-Tenant
|
|
|
|
Verwendet `@payloadcms/plugin-multi-tenant`.
|
|
|
|
| ID | Name | Slug |
|
|
|----|------|------|
|
|
| 1 | porwoll.de | porwoll |
|
|
| 4 | Complex Care Solutions GmbH | c2s |
|
|
| 5 | Gunshin | gunshin |
|
|
|
|
User-Tenant-Zuweisung: Tabelle `users_tenants`
|
|
|
|
## Wichtige Pfade
|
|
|
|
```
|
|
/home/payload/payload-cms/
|
|
├── src/
|
|
│ ├── payload.config.ts # Haupt-Konfiguration
|
|
│ ├── collections/ # Alle Collections (55+)
|
|
│ ├── app/(payload)/api/ # Custom API Routes
|
|
│ ├── lib/
|
|
│ │ ├── email/ # E-Mail-System (tenant-spezifisch)
|
|
│ │ ├── security/ # Rate-Limiter, CSRF, IP-Allowlist
|
|
│ │ ├── queue/ # BullMQ Jobs & Workers
|
|
│ │ ├── pdf/ # PDF-Generierung
|
|
│ │ ├── retention/ # Data Retention (DSGVO)
|
|
│ │ ├── integrations/meta/ # Facebook + Instagram API
|
|
│ │ ├── jobs/ # UnifiedSyncService, JobLogger
|
|
│ │ ├── search.ts # Volltextsuche
|
|
│ │ └── redis.ts # Redis Cache Client
|
|
│ └── hooks/ # Collection Hooks
|
|
├── tests/ # Unit & Integration Tests
|
|
├── scripts/
|
|
│ ├── db-direct.sh # Direkte DB-Verbindung (umgeht PgBouncer)
|
|
│ ├── sync-schema.sh # Schema-Sync nach Collection-Änderungen
|
|
│ └── backup/ # Backup-System (→ scripts/backup/README.md)
|
|
├── .env # Umgebungsvariablen
|
|
├── ecosystem.config.cjs # PM2 Config
|
|
└── .github/workflows/ # CI/CD Pipelines
|
|
```
|
|
|
|
## Wichtige Befehle
|
|
|
|
```bash
|
|
# Entwicklung
|
|
pnpm dev
|
|
pnpm build
|
|
|
|
# Migrationen
|
|
pnpm payload migrate:create
|
|
pnpm payload migrate
|
|
|
|
# Schema-Sync (wichtig nach Collection-Änderungen!)
|
|
./scripts/sync-schema.sh --dry-run # Zeigt Änderungen
|
|
./scripts/sync-schema.sh # Führt Sync aus
|
|
|
|
# ImportMap nach Plugin-Änderungen
|
|
pnpm payload generate:importmap
|
|
|
|
# PM2
|
|
pm2 status | pm2 logs payload | pm2 restart payload
|
|
pm2 logs queue-worker | 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
|
|
|
|
# Lint & Format
|
|
pnpm lint # ESLint
|
|
pnpm typecheck # TypeScript Check (4GB heap)
|
|
pnpm format:check # Prettier Check
|
|
pnpm format # Prettier Auto-Fix
|
|
|
|
# Direkte DB-Verbindung (umgeht PgBouncer für Migrationen)
|
|
./scripts/db-direct.sh migrate
|
|
./scripts/db-direct.sh psql
|
|
|
|
# Backup
|
|
/home/payload/backups/postgres/backup-db.sh --verbose
|
|
```
|
|
|
|
## Git Workflow
|
|
|
|
**Regel:** Immer auf `develop` entwickeln, nach Freigabe nach `main` mergen.
|
|
|
|
| Branch | Zweck | Deployment |
|
|
|--------|-------|------------|
|
|
| `develop` | Aktive Entwicklung | Staging (pl.porwoll.tech) |
|
|
| `main` | Stabile Version | Production (cms.c2sgmbh.de) |
|
|
| `feature/*` | Feature-Branches | PR nach develop |
|
|
|
|
**Commit-Konventionen:** `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`
|
|
|
|
**Workflow nach Code-Änderungen:**
|
|
1. Code ändern (auf `develop`)
|
|
2. `pnpm build` → `pm2 restart payload`
|
|
3. Bei Collection-Änderungen zusätzlich: `pnpm payload migrate:create`
|
|
|
|
## KRITISCH: Neue Collections hinzufügen
|
|
|
|
Payload CMS verwendet `payload_locked_documents_rels` für Document-Locks. Diese Tabelle benötigt eine `{collection}_id` Spalte für JEDE Collection. Ohne → RSC-Fehler nach Login:
|
|
|
|
```
|
|
column payload_locked_documents_rels.{collection}_id does not exist
|
|
```
|
|
|
|
**Migration MUSS enthalten:**
|
|
```sql
|
|
ALTER TABLE "payload_locked_documents_rels"
|
|
ADD COLUMN IF NOT EXISTS "{collection}_id" integer
|
|
REFERENCES {collection}(id) ON DELETE CASCADE;
|
|
|
|
CREATE INDEX IF NOT EXISTS "payload_locked_documents_rels_{collection}_idx"
|
|
ON "payload_locked_documents_rels" ("{collection}_id");
|
|
```
|
|
|
|
Beispiel: `src/migrations/20260109_020000_add_blogwoman_collections.ts`
|
|
|
|
**Array-Felder:** Collections mit Arrays benötigen zusätzliche `{collection}_{array_field}` Tabellen.
|
|
|
|
## Bekannte Besonderheiten & Gotchas
|
|
|
|
- **ES Modules:** `"type": "module"` in package.json → PM2 Config als `.cjs`
|
|
- **Plugin ImportMap:** Nach Plugin-Änderungen `pnpm payload generate:importmap`
|
|
- **User-Tenant-Zuweisung:** Neue User müssen manuell Tenants zugewiesen bekommen
|
|
- **Admin Login:** Custom Route mit Audit-Logging (`src/app/(payload)/api/users/login/route.ts`)
|
|
- **Queue Worker:** PM2 nutzt `node_modules/tsx/dist/cli.mjs` direkt (nicht `npx`), `exec_mode: 'fork'`
|
|
- **PgBouncer:** Transaction-Mode kann Migrationen stören → `./scripts/db-direct.sh`
|
|
- **TRUST_PROXY=true:** PFLICHT hinter Reverse-Proxy, sonst funktionieren Rate-Limiting und IP-Allowlists nicht
|
|
- **CSRF_SECRET:** PFLICHT in Production (oder PAYLOAD_SECRET) - Server startet nicht ohne
|
|
|
|
## Build-Konfiguration
|
|
|
|
- `package.json`: `--max-old-space-size=2048` (2GB Heap-Limit)
|
|
- `next.config.mjs`: `experimental.cpus: 1`, `workerThreads: false`
|
|
|
|
**Server hat 8GB RAM ohne Swap.** Bei laufendem VS Code kann Build OOM werden:
|
|
```bash
|
|
pm2 stop payload
|
|
NODE_OPTIONS="--no-deprecation --max-old-space-size=1024" ./node_modules/.bin/next build
|
|
pm2 start payload
|
|
```
|
|
|
|
## Mehrsprachigkeit
|
|
|
|
Deutsch (default) + Englisch. API: `?locale=de|en`. DB: `_locales` Tabellen.
|
|
|
|
## URLs
|
|
|
|
| Bereich | URL |
|
|
|---------|-----|
|
|
| Admin Panel | https://pl.porwoll.tech/admin |
|
|
| API | https://pl.porwoll.tech/api |
|
|
| Swagger UI | https://pl.porwoll.tech/api/docs |
|
|
| Production | https://cms.c2sgmbh.de |
|
|
|
|
→ Vollständige Endpoint-Liste: `docs/anleitungen/API_ANLEITUNG.md`
|
|
|
|
## Security Kurzübersicht
|
|
|
|
- **Rate-Limiting:** publicApi(60/min), auth(5/15min), email(10/min), search(30/min), form(5/10min)
|
|
- **CSRF:** Double Submit Cookie + Origin-Validierung, Token: `GET /api/csrf-token`
|
|
- **IP-Allowlist:** `SEND_EMAIL_ALLOWED_IPS`, `ADMIN_ALLOWED_IPS`, `BLOCKED_IPS` (IPs, CIDRs, Wildcards)
|
|
- **Data-Masking:** Automatisch in Logs (Passwörter, Tokens, API-Keys)
|
|
|
|
→ Details: `docs/anleitungen/SECURITY.md`
|
|
|
|
## Subsysteme (Kurzübersicht)
|
|
|
|
| System | Schlüsseldateien | Details |
|
|
|--------|-----------------|---------|
|
|
| E-Mail (Multi-Tenant SMTP) | `src/lib/email/` | `docs/CLAUDE_REFERENCE.md` |
|
|
| Newsletter (Double Opt-In) | `src/lib/email/newsletter-service.ts` | `docs/CLAUDE_REFERENCE.md` |
|
|
| BullMQ Queue | `src/lib/queue/`, `ecosystem.config.cjs` | `docs/CLAUDE_REFERENCE.md` |
|
|
| Data Retention (DSGVO) | `src/lib/retention/` | `docs/CLAUDE_REFERENCE.md` |
|
|
| PDF-Generierung | `src/lib/pdf/`, API: `/api/generate-pdf` | `docs/CLAUDE_REFERENCE.md` |
|
|
| Redis Caching | `src/lib/redis.ts` | `docs/CLAUDE_REFERENCE.md` |
|
|
| Backup | `scripts/backup/` | `scripts/backup/README.md` |
|
|
| Community Management | `src/lib/integrations/meta/`, `src/lib/jobs/` | `docs/CLAUDE_REFERENCE.md` |
|
|
| YouTube Operations Hub | `src/lib/youtube/`, API: `/api/youtube/*` | `docs/CLAUDE_REFERENCE.md` |
|
|
| FormSubmissions CRM | `src/collections/FormSubmissionsOverrides.ts` | `docs/CLAUDE_REFERENCE.md` |
|
|
|
|
## Collections (55+)
|
|
|
|
| Slug | Beschreibung | Gruppe |
|
|
|------|--------------|--------|
|
|
| users | Benutzer (isSuperAdmin) | Core |
|
|
| tenants | Mandanten + E-Mail-Config | Core |
|
|
| media | Medien (11 responsive Sizes) | Core |
|
|
| pages | Seiten mit Blocks | Core |
|
|
| posts | Blog/News/Presse | Content |
|
|
| categories | Post-Kategorien | Content |
|
|
| tags | Post-Tags | Content |
|
|
| authors | Post-Autoren | Content |
|
|
| testimonials | Kundenbewertungen | Content |
|
|
| faqs | FAQ | Content |
|
|
| social-links | Social Media Links | Content |
|
|
| team | Team-Mitglieder | Team |
|
|
| service-categories | Leistungs-Kategorien | Team |
|
|
| services | Leistungen | Team |
|
|
| jobs | Stellenangebote | Team |
|
|
| portfolios | Portfolio-Galerien | Portfolio |
|
|
| portfolio-categories | Portfolio-Kategorien | Portfolio |
|
|
| videos | Video-Bibliothek | Media |
|
|
| video-categories | Video-Kategorien | Media |
|
|
| products | Produkte | E-Commerce |
|
|
| product-categories | Produkt-Kategorien | E-Commerce |
|
|
| locations | Standorte/Filialen | Feature |
|
|
| partners | Partner/Kunden | Feature |
|
|
| downloads | Download-Dateien | Feature |
|
|
| events | Veranstaltungen | Feature |
|
|
| timelines | Chronologische Events | Feature |
|
|
| workflows | Prozesse mit Phasen | Feature |
|
|
| forms | Formular-Builder (Plugin) | Formulare |
|
|
| form-submissions | CRM-Workflow | Formulare |
|
|
| newsletter-subscribers | Double Opt-In | Newsletter |
|
|
| cookie-configurations | Cookie-Banner | DSGVO |
|
|
| cookie-inventory | Cookie-Inventar | DSGVO |
|
|
| consent-logs | Consent-Protokoll (WORM) | DSGVO |
|
|
| privacy-policy-settings | Datenschutz | DSGVO |
|
|
| bookings | Fotografie-Buchungen (porwoll) | Tenant |
|
|
| certifications | Zertifizierungen (c2s) | Tenant |
|
|
| projects | Game-Dev-Projekte (gunshin) | Tenant |
|
|
| favorites | Affiliate-Produkte | BlogWoman |
|
|
| series | YouTube-Serien (Branding) | BlogWoman |
|
|
| youtube-channels | Multi-Kanal + OAuth | YouTube |
|
|
| youtube-content | Videos + Shorts | YouTube |
|
|
| yt-series | Serien + Playlist | YouTube |
|
|
| yt-notifications | Handlungsbedarf | YouTube |
|
|
| yt-script-templates | Skript-Vorlagen | YouTube |
|
|
| yt-batches | Produktions-Batches | YouTube |
|
|
| yt-checklist-templates | Checklisten | YouTube |
|
|
| yt-monthly-goals | Monatsziele | YouTube |
|
|
| yt-tasks | Aufgaben | YouTube |
|
|
| social-accounts | Meta OAuth | Community |
|
|
| social-platforms | Plattform-Config | Community |
|
|
| community-interactions | Kommentare (alle Plattformen) | Community |
|
|
| community-rules | Auto-Antwort-Regeln | Community |
|
|
| community-templates | Antwort-Vorlagen | Community |
|
|
| report-schedules | Geplante Reports | Community |
|
|
| email-logs | E-Mail-Protokoll | System |
|
|
| audit-logs | Security Audit Trail | System |
|
|
| site-settings | Website-Einstellungen (pro Tenant) | System |
|
|
| navigations | Navigationsmenüs (pro Tenant) | System |
|
|
| redirects | URL-Weiterleitungen (Plugin) | System |
|
|
|
|
## Blocks (43)
|
|
|
|
| Slug | Beschreibung | Gruppe |
|
|
|------|--------------|--------|
|
|
| hero-block | Hero mit Bild, Headline, CTA | Core |
|
|
| hero-slider-block | Hero-Slider (Slides, Animationen, Autoplay) | Core |
|
|
| image-slider-block | Bildergalerie/Karussell | Core |
|
|
| text-block | Rich-Text Inhalt | Core |
|
|
| image-text-block | Bild + Text nebeneinander | Core |
|
|
| card-grid-block | Karten-Raster | Core |
|
|
| quote-block | Zitat | Core |
|
|
| cta-block | Call-to-Action | Core |
|
|
| contact-form-block | Kontaktformular | Core |
|
|
| timeline-block | Timeline-Darstellung | Core |
|
|
| divider-block | Trennlinie | Core |
|
|
| video-block | Video einbetten | Core |
|
|
| posts-list-block | Beitrags-Liste | Content |
|
|
| testimonials-block | Kundenbewertungen | Content |
|
|
| newsletter-block | Newsletter-Anmeldung | Content |
|
|
| process-steps-block | Prozess-Schritte | Content |
|
|
| faq-block | FAQ-Akkordeon | Content |
|
|
| team-block | Team-Mitglieder | Content |
|
|
| services-block | Leistungen | Content |
|
|
| author-bio-block | Autoren-Biografie | Blogging |
|
|
| related-posts-block | Verwandte Beiträge | Blogging |
|
|
| share-buttons-block | Social Share Buttons | Blogging |
|
|
| table-of-contents-block | Inhaltsverzeichnis | Blogging |
|
|
| team-filter-block | Team mit Filter | Team |
|
|
| org-chart-block | Organigramm | Team |
|
|
| locations-block | Standorte/Filialen | Feature |
|
|
| logo-grid-block | Partner-Logos | Feature |
|
|
| stats-block | Statistiken/Zahlen | Feature |
|
|
| jobs-block | Stellenangebote | Feature |
|
|
| downloads-block | Download-Bereich | Feature |
|
|
| map-block | Karten-Einbindung | Feature |
|
|
| events-block | Veranstaltungen | Interactive |
|
|
| pricing-block | Preistabellen | Interactive |
|
|
| tabs-block | Tab-Navigation | Interactive |
|
|
| accordion-block | Akkordeon | Interactive |
|
|
| comparison-block | Vergleichstabelle | Interactive |
|
|
| before-after-block | Vorher/Nachher (porwoll) | Tenant |
|
|
| favorites-block | Affiliate-Produkte | BlogWoman |
|
|
| series-block | YouTube-Serien | BlogWoman |
|
|
| series-detail-block | Serien-Einzelseite | BlogWoman |
|
|
| video-embed-block | YouTube/Vimeo Embed | BlogWoman |
|
|
| featured-content-block | Kuratierte Inhalte | BlogWoman |
|
|
| script-section-block | Script-Abschnitte | BlogWoman |
|
|
|
|
## Globals
|
|
|
|
| Global | Slug | Beschreibung |
|
|
|--------|------|--------------|
|
|
| SEOSettings | seo-settings | Globale SEO-Einstellungen (systemweit) |
|
|
|
|
> SiteSettings, Navigations, PrivacyPolicySettings sind tenant-spezifische Collections.
|
|
|
|
## Cron Jobs
|
|
|
|
| Endpoint | Schedule | Beschreibung |
|
|
|----------|----------|--------------|
|
|
| `/api/cron/community-sync` | alle 15 Min | Kommentar-Sync (YouTube, Facebook, Instagram) |
|
|
| `/api/cron/token-refresh` | 6:00 + 18:00 UTC | OAuth-Token-Erneuerung |
|
|
| `/api/cron/send-reports` | stündlich | Community-Reports per E-Mail |
|
|
| `/api/cron/youtube-sync` | alle 15 Min | YouTube-Kommentar-Sync |
|
|
| `/api/cron/youtube-channel-sync` | täglich 04:00 UTC | Kanal-Statistiken (Abos, Views) |
|
|
| `/api/cron/youtube-metrics-sync` | alle 6 Stunden | Video-Performance-Metriken |
|
|
|
|
Auth: `Authorization: Bearer $CRON_SECRET`
|
|
|
|
## CI/CD
|
|
|
|
| Workflow | Trigger | Beschreibung |
|
|
|----------|---------|--------------|
|
|
| `ci.yml` | Push/PR auf main/develop | Lint, Typecheck, Test, Build, E2E |
|
|
| `security.yml` | Push/PR | Gitleaks, pnpm audit, CodeQL |
|
|
| `deploy-staging.yml` | Push auf develop | Auto-Deploy auf pl.porwoll.tech |
|
|
| `deploy-production.yml` | Manual dispatch | Deploy auf cms.c2sgmbh.de (mit Backup + Rollback) |
|
|
|
|
→ Details: `docs/DEPLOYMENT.md`, `docs/DEPLOYMENT_STRATEGY.md`
|
|
|
|
## Umgebungsvariablen
|
|
|
|
Wichtigste Variablen (vollständige Liste in `.env`):
|
|
|
|
| Variable | Beschreibung | Pflicht |
|
|
|----------|--------------|---------|
|
|
| `DATABASE_URI` | PostgreSQL via PgBouncer (127.0.0.1:6432) | Ja |
|
|
| `PAYLOAD_SECRET` | Payload Encryption Secret | Ja |
|
|
| `TRUST_PROXY` | `true` hinter Reverse-Proxy | Ja |
|
|
| `CSRF_SECRET` | CSRF-Token Secret (oder PAYLOAD_SECRET) | Prod |
|
|
| `CRON_SECRET` | Auth für Cron-Endpoints | Ja |
|
|
| `REDIS_PASSWORD` | Redis Authentifizierung | Ja |
|
|
| `REDIS_URL` | Redis Cache (localhost:6379) | Optional |
|
|
| `META_APP_ID/SECRET` | Facebook/Instagram OAuth | Für Community |
|
|
| `GOOGLE_CLIENT_ID/SECRET` | YouTube OAuth | Für YouTube |
|
|
|
|
Credentials in `~/.pgpass` (chmod 600), nie Klartext in `.env`.
|
|
|
|
## Dokumentation
|
|
|
|
### Projekt-Docs
|
|
- `docs/INFRASTRUCTURE.md` - Infrastruktur (Dev + Prod, PgBouncer, Server)
|
|
- `docs/DEPLOYMENT.md` - Deployment-Prozess & Checklisten
|
|
- `docs/DEPLOYMENT_STRATEGY.md` - Vollständige Deployment-Strategie
|
|
- `docs/PROJECT_STATUS.md` - Projektstatus & Roadmap
|
|
- `docs/CLAUDE_REFERENCE.md` - **Detaillierte Subsystem-Referenz** (E-Mail, Queue, Retention, Community, etc.)
|
|
|
|
### Anleitungen
|
|
- `docs/anleitungen/API_ANLEITUNG.md` - API-Dokumentation (alle Endpoints + curl-Beispiele)
|
|
- `docs/anleitungen/SECURITY.md` - Sicherheitsrichtlinien
|
|
- `docs/anleitungen/FRONTEND.md` - Frontend-Entwicklung (sv-frontend)
|
|
- `docs/anleitungen/TODO.md` - Task-Liste & Changelog
|
|
|
|
### Scripts & Backup
|
|
- `scripts/backup/README.md` - Backup-System Dokumentation
|
|
|
|
*Letzte Aktualisierung: 14.02.2026*
|