From 9f7a9ad558305bf341dc60011e3a8fa72dc4a8e6 Mon Sep 17 00:00:00 2001 From: Martin Porwoll Date: Sun, 15 Feb 2026 22:49:38 +0000 Subject: [PATCH] docs: update infrastructure, project status, and frontend docs Add Multi-Server Orchestration (Phase 1-8) to all docs: - INFRASTRUCTURE.md: Hetzner 1/2 production servers, SSH infrastructure, payload-contracts, deployment workflows, port-forwarding - PROJECT_STATUS.md: Orchestration changelog, production URLs, SSH commands - FRONTEND.md: payload-contracts usage, CI/CD pipelines, staging/production deploy, work order system, ESLint config, updated tenant IDs Co-Authored-By: Claude Opus 4.6 --- docs/INFRASTRUCTURE.md | 285 +++++++++++++++--- docs/PROJECT_STATUS.md | 115 +++++-- docs/anleitungen/FRONTEND.md | 568 ++++++++++++++++------------------- 3 files changed, 580 insertions(+), 388 deletions(-) diff --git a/docs/INFRASTRUCTURE.md b/docs/INFRASTRUCTURE.md index de8dd7f..309fb30 100644 --- a/docs/INFRASTRUCTURE.md +++ b/docs/INFRASTRUCTURE.md @@ -1,6 +1,6 @@ # Infrastruktur Dokumentation -*Letzte Aktualisierung: 13. Februar 2026* +*Letzte Aktualisierung: 15. Februar 2026* ## Gesamtübersicht @@ -21,6 +21,7 @@ │ │ 37.24.237.179 │ cloud.complexcaresolutions.de → 10.10.179.100 │ │ │ │ 37.24.237.180 │ zh3.de (Nginx PM) → 10.10.180.100 │ │ │ │ 37.24.237.181 │ porwoll.tech (Caddy) → 10.10.181.99 │ │ +│ │ │ :2204 → sv-frontend (10.10.181.104:22) [GitHub Actions] │ │ │ │ 37.24.237.182 │ FREI (Reserve) │ │ │ │ │ │ │ └──────────────────────────────────┬──────────────────────────────────────────┘ │ @@ -31,15 +32,27 @@ │ └── porwoll.org (intern DNS only) │ │ │ │ HETZNER (Extern) │ -│ ├── 78.46.87.137 (Hetzner 1 - zweitmeinu.ng) │ -│ ├── 94.130.141.114 (Hetzner 2 - Porwoll) │ -│ └── 162.55.85.18 (Hetzner 3 - Payload Prod) │ +│ ├── 78.46.87.137 (Hetzner 1) — blogwoman.de, ccs.de, zweitmeinu.ng │ +│ ├── 94.130.141.114 (Hetzner 2) — porwoll.de, caroline-porwoll.* │ +│ └── 162.55.85.18 (Hetzner 3) — CMS + Analytics (Payload Prod) │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ ``` --- +## Server-Übersicht + +| Server | IP | Verwaltung | Zweck | Sites | +|--------|-----|-----------|-------|-------| +| **sv-payload** | 10.10.181.100 | LXC (Proxmox) | CMS Development | pl.porwoll.tech | +| **sv-frontend** | 10.10.181.104 | LXC (Proxmox) | Frontend Development | *-dev.porwoll.tech | +| **Hetzner 1** | 78.46.87.137 | Plesk | Frontend Production | blogwoman.de, ccs.de, zweitmeinu.ng | +| **Hetzner 2** | 94.130.141.114 | Plesk | Frontend Production | porwoll.de, caroline-porwoll.* | +| **Hetzner 3** | 162.55.85.18 | Manuell (SSH) | CMS + Analytics Prod | cms.c2sgmbh.de, analytics.c2sgmbh.de | + +--- + ## Öffentliche IP-Adressen | IP | Verwendung | Ziel (intern) | @@ -48,6 +61,7 @@ | 37.24.237.179 | cloud.complexcaresolutions.de | 10.10.179.100 (Nextcloud) | | 37.24.237.180 | zh3.de (via Cloudflare) | 10.10.180.100 (Nginx PM) | | 37.24.237.181 | porwoll.tech (Cloudflare) | 10.10.181.99 (Caddy) | +| 37.24.237.181:2204 | GitHub Actions SSH Deploy | 10.10.181.104:22 (sv-frontend) | | 37.24.237.182 | FREI (Reserve) | - | --- @@ -85,23 +99,23 @@ - Node.js 22.x - pnpm - Next.js 16.2.0-canary.41 -- Claude Code (aktuell) +- Claude Code 2.1.37 - Codex CLI (aktuell) - Gemini CLI (aktuell) ### Projekte & Ports -| Port | Service | Repository | URL | -|------|---------|------------|-----| -| 3000 | frontend-porwoll | frontend.porwoll.de | porwoll-dev.porwoll.tech | -| 3001 | frontend-blogwoman | frontend.blogwoman.de | blogwoman-dev.porwoll.tech | -| 3002 | frontend-caroline-com | frontend.caroline-porwoll.com | caroline-com-dev.porwoll.tech | -| 3003 | frontend-caroline-de | frontend.caroline-porwoll.de | caroline-de-dev.porwoll.tech | -| 3004 | frontend-ccs | frontend.complexcaresolutions.de | ccs-dev.porwoll.tech | -| 3005 | frontend-gunshin | frontend.gunshin.de | gunshin-dev.porwoll.tech | -| 3006 | frontend-sensual | frontend.sensualmoment.de | sensual-dev.porwoll.tech | -| 3007 | frontend-zweitmeinu | frontend.zweitmeinu.ng | zweitmeinu-dev.porwoll.tech | -| 3008 | frontend-zytoskandal | frontend.zytoskandal.de | zytoskandal-dev.porwoll.tech | +| Port | Service | Repository | Staging URL | Production | +|------|---------|------------|-------------|------------| +| 3000 | frontend-porwoll | frontend.porwoll.de | porwoll-dev.porwoll.tech | **porwoll.de** ✅ | +| 3001 | frontend-blogwoman | frontend.blogwoman.de | blogwoman-dev.porwoll.tech | **blogwoman.de** ✅ | +| 3002 | frontend-caroline-com | frontend.caroline-porwoll.com | caroline-com-dev.porwoll.tech | - | +| 3003 | frontend-caroline-de | frontend.caroline-porwoll.de | caroline-de-dev.porwoll.tech | - | +| 3004 | frontend-ccs | frontend.complexcaresolutions.de | ccs-dev.porwoll.tech | - | +| 3005 | frontend-gunshin | frontend.gunshin.de | gunshin-dev.porwoll.tech | - | +| 3006 | frontend-sensual | frontend.sensualmoment.de | sensual-dev.porwoll.tech | - | +| 3007 | frontend-zweitmeinu | frontend.zweitmeinu.ng | zweitmeinu-dev.porwoll.tech | - | +| 3008 | frontend-zytoskandal | frontend.zytoskandal.de | zytoskandal-dev.porwoll.tech | - | ### Service-Verwaltung @@ -136,24 +150,137 @@ systemctl status frontend-* --- -## GitHub Organisation: complexcaresolutions +## SSH-Infrastruktur -| Repository | Beschreibung | Visibility | -|------------|--------------|------------| -| cms.c2sgmbh | Payload CMS Backend | Internal | -| frontend.porwoll.de | porwoll.de Frontend | Internal | -| frontend.blogwoman.de | blogwoman.de Frontend | Internal | -| frontend.caroline-porwoll.com | caroline-porwoll.com Frontend | Internal | -| frontend.caroline-porwoll.de | caroline-porwoll.de Frontend | Internal | -| frontend.complexcaresolutions.de | CCS Website Frontend | Internal | -| frontend.gunshin.de | gunshin.de Frontend | Internal | -| frontend.sensualmoment.de | sensualmoment.de Frontend | Internal | -| frontend.zweitmeinu.ng | zweitmeinu.ng Frontend | Internal | -| frontend.zytoskandal.de | zytoskandal.de Frontend | Internal | +### Verbindungen von sv-payload + +| Ziel | Host-Alias | User | Key | Zweck | +|------|-----------|------|-----|-------| +| sv-frontend (10.10.181.104) | `sv-frontend` | frontend | `~/.ssh/frontend_deploy` | Entwicklung, Work Orders | +| Hetzner 1 (78.46.87.137) | `hetzner1` | root | `~/.ssh/plesk_deploy` | Production Troubleshooting | +| Hetzner 2 (94.130.141.114) | `hetzner2` | root | `~/.ssh/plesk_deploy` | Production Troubleshooting | + +### SSH-Config (`/home/payload/.ssh/config`) + +``` +Host sv-frontend frontend + HostName 10.10.181.104 + User frontend + IdentityFile ~/.ssh/frontend_deploy + IdentitiesOnly yes + +Host hetzner1 plesk1 + HostName 78.46.87.137 + User root + IdentityFile ~/.ssh/plesk_deploy + IdentitiesOnly yes + StrictHostKeyChecking accept-new + +Host hetzner2 plesk2 + HostName 94.130.141.114 + User root + IdentityFile ~/.ssh/plesk_deploy + IdentitiesOnly yes + StrictHostKeyChecking accept-new +``` + +### Port-Forwarding (GitHub Actions → sv-frontend) + +GitHub Actions kann sv-frontend nicht direkt erreichen (internes Netz). Lösung: UDM Pro SE Port-Forward. + +``` +GitHub Actions → 37.24.237.181:2204 → UDM Pro SE → 10.10.181.104:22 (sv-frontend) +``` + +Die SSH-Credentials sind als Repository-Secrets gespeichert (`SSH_HOST`, `SSH_PORT`, `SSH_USER`, `SSH_PRIVATE_KEY`). --- -## Hetzner 3 - Payload Production +## GitHub Organisation: complexcaresolutions + +| Repository | Beschreibung | Visibility | Production | +|------------|--------------|------------|------------| +| cms.c2sgmbh | Payload CMS Backend | Internal | cms.c2sgmbh.de | +| **payload-contracts** | **Shared Types + API Client** | **Internal** | — | +| frontend.porwoll.de | porwoll.de Frontend | Internal | **porwoll.de** ✅ | +| frontend.blogwoman.de | blogwoman.de Frontend | Internal | **blogwoman.de** ✅ | +| frontend.caroline-porwoll.com | caroline-porwoll.com Frontend | Internal | - | +| frontend.caroline-porwoll.de | caroline-porwoll.de Frontend | Internal | - | +| frontend.complexcaresolutions.de | CCS Website Frontend | Internal | - | +| frontend.gunshin.de | gunshin.de Frontend | Internal | - | +| frontend.sensualmoment.de | sensualmoment.de Frontend | Internal | - | +| frontend.zweitmeinu.ng | zweitmeinu.ng Frontend | Internal | - | +| frontend.zytoskandal.de | zytoskandal.de Frontend | Internal | - | + +### payload-contracts + +Shared TypeScript-Package (`@c2s/payload-contracts`) als Git-Dependency für alle Frontends. + +``` +CMS (payload-cms) Contracts (payload-contracts) Frontends +━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━ +payload-types.ts ──extract-types──→ src/types/payload-types.ts + src/types/collections.ts ←──── import { Page, Post } + src/api-client/ ←──── import { createPayloadClient } + src/blocks/registry.tsx ←──── import { createBlockRenderer } +``` + +--- + +## Hetzner 1 - Frontend Production (blogwoman.de) + +- **IP:** 78.46.87.137 +- **Verwaltung:** Plesk +- **SSH:** `ssh hetzner1` (von sv-payload) +- **Web-Server:** nginx-only + Phusion Passenger 6.1.0 +- **Node.js:** 22.x + +### Sites + +| Domain | Status | Repository | Deploy | +|--------|--------|------------|--------| +| blogwoman.de | ✅ Live | frontend.blogwoman.de | GitHub Webhook → Plesk Git Pull | +| complexcaresolutions.de | ⏸️ Geplant | frontend.complexcaresolutions.de | - | +| zweitmeinu.ng | ⏸️ Geplant | frontend.zweitmeinu.ng | - | + +### Deployment + +- **Methode:** Plesk Git-Integration mit GitHub Webhook +- **Webhook:** `complexcaresolutions.de:8443` (SSL-Cert ist für diese Domain) +- **Branch:** `main` (Push → Auto-Pull → Passenger Restart) +- **Document Root:** `/var/www/vhosts/blogwoman.de/httpdocs/` + +### Konfiguration (nginx-only) + +Plesk muss auf **nginx-only** (nicht nginx→Apache) konfiguriert sein, da Apache ErrorDocument-Directives Next.js 404-Handling stören und Redirect-Loops verursachen. + +--- + +## Hetzner 2 - Frontend Production (porwoll.de) + +- **IP:** 94.130.141.114 +- **Verwaltung:** Plesk +- **SSH:** `ssh hetzner2` (von sv-payload) +- **Web-Server:** nginx-only + Phusion Passenger 6.1.0 +- **Node.js:** 22.x + +### Sites + +| Domain | Status | Repository | Deploy | +|--------|--------|------------|--------| +| porwoll.de | ✅ Live | frontend.porwoll.de | GitHub Webhook → Plesk Git Pull | +| caroline-porwoll.com | ⏸️ Geplant | frontend.caroline-porwoll.com | - | +| caroline-porwoll.de | ⏸️ Geplant | frontend.caroline-porwoll.de | - | + +### Deployment + +- **Methode:** Plesk Git-Integration mit GitHub Webhook +- **Branch:** `main` (Push → Auto-Pull → Passenger Restart) +- **Document Root:** `/var/www/vhosts/porwoll.de/httpdocs/` + +--- + +## Hetzner 3 - CMS + Analytics Production - **IP:** 162.55.85.18 - **Domain:** cms.c2sgmbh.de @@ -185,16 +312,58 @@ systemctl status frontend-* --- -## Development Workflow +## Deployment-Workflow + +### CMS (Payload) ``` -DEVELOPMENT STAGING PRODUCTION -sv-frontend → sv-payload → Hetzner 03 -porwoll.tech pl.porwoll.tech cms.c2sgmbh.de - develop branch main branch +sv-payload (develop) → GitHub CI → sv-payload (main) → Hetzner 3 (deploy.sh) ``` -**AI Tools:** Claude Code, Codex CLI, Gemini CLI, VS Code Remote-SSH +### Frontends + +``` +sv-frontend (develop) GitHub Plesk (Hetzner 1/2) +━━━━━━━━━━━━━━━━━━━━ ━━━━━━ ━━━━━━━━━━━━━━━━━━━ + +1. Entwicklung CI: Lint + Build + (Claude Code) ──push──→ ✅ auf develop + │ +2. Staging-Test │ + (*-dev.porwoll.tech) │ + │ +3. Merge develop → main ──push──→ CI: Lint + Build + ✅ auf main + │ + Webhook ─────────→ 4. Plesk Git Pull + 5. pnpm install + 6. pnpm build + 7. Passenger Restart + 8. Site live ✅ +``` + +### Staging-Deploy (GitHub Actions) + +Push auf `develop` → GitHub Actions → SSH via Port-Forward → `pnpm install && pnpm build` auf sv-frontend. + +### Work-Order-Workflow (neue Blocks/Collections) + +``` +sv-payload sv-frontend +━━━━━━━━━━ ━━━━━━━━━━━ +1. CMS Block/Collection ändern +2. pnpm payload generate:types +3. cd ~/payload-contracts && pnpm extract +4. ./scripts/create-work-order.sh "Titel" +5. git commit && git push + 6. git pull (payload-contracts) + 7. Claude Code mit Work Order starten + 8. Block implementieren + 9. pnpm build (Verify) + 10. git commit && git push +11. Ergebnis verifizieren +12. Work Order → completed/ verschieben +``` --- @@ -213,30 +382,46 @@ porwoll.tech pl.porwoll.tech cms.c2sgmbh.de ### Production (Hetzner) -| Service | URL | -|---------|-----| -| Payload Admin | https://cms.c2sgmbh.de/admin | -| Payload API | https://cms.c2sgmbh.de/api | -| Umami Analytics | https://analytics.c2sgmbh.de | +| Service | URL | Server | +|---------|-----|--------| +| Payload Admin | https://cms.c2sgmbh.de/admin | Hetzner 3 | +| Payload API | https://cms.c2sgmbh.de/api | Hetzner 3 | +| Umami Analytics | https://analytics.c2sgmbh.de | Hetzner 3 | +| blogwoman.de | https://blogwoman.de | Hetzner 1 | +| porwoll.de | https://porwoll.de | Hetzner 2 | --- ## Quick Reference ```bash -# Frontend-Server -ssh frontend@10.10.181.104 +# --- Development --- +ssh frontend@10.10.181.104 # sv-frontend +ssh root@10.10.181.99 # sv-caddy +systemctl reload caddy # Caddy Caddyfile neu laden -# Hetzner 3 Production -ssh payload@162.55.85.18 +# --- CMS Production --- +ssh payload@162.55.85.18 # Hetzner 3 +pm2 logs payload # CMS Logs -# Caddy neu laden -ssh root@10.10.181.99 "systemctl reload caddy" +# --- Frontend Production --- +ssh hetzner1 # Hetzner 1 (blogwoman.de) +ssh hetzner2 # Hetzner 2 (porwoll.de) -# Frontend Service starten -systemctl start frontend-porwoll +# Git-Status auf Production prüfen +ssh hetzner1 "cd /var/www/vhosts/blogwoman.de/httpdocs && git log --oneline -3" +ssh hetzner2 "cd /var/www/vhosts/porwoll.de/httpdocs && git log --oneline -3" + +# Passenger-Status +ssh hetzner1 "passenger-status" +ssh hetzner2 "passenger-status" + +# --- Work Orders --- +cd ~/payload-contracts +./scripts/create-work-order.sh "Titel" --extract +./scripts/execute-work-order.sh work-orders/YYYY-MM-DD-slug.md ``` --- -*Dokumentation: Martin Porwoll | Complex Care Solutions GmbH | 13.02.2026* +*Dokumentation: Martin Porwoll | Complex Care Solutions GmbH | 15.02.2026* diff --git a/docs/PROJECT_STATUS.md b/docs/PROJECT_STATUS.md index 89850ff..c04bdfe 100644 --- a/docs/PROJECT_STATUS.md +++ b/docs/PROJECT_STATUS.md @@ -12,6 +12,8 @@ Die komplette Entwicklungsinfrastruktur ist eingerichtet und funktionsfähig: - Analytics (Umami) - **Community Management System** (YouTube, Facebook, Instagram) - **YouTube Operations Hub** (Multi-Kanal-Verwaltung) +- **Multi-Server Orchestration** (SSH, Contracts, CI/CD, Plesk Production) +- **2 Production-Sites live:** blogwoman.de + porwoll.de --- @@ -28,7 +30,7 @@ Die komplette Entwicklungsinfrastruktur ist eingerichtet und funktionsfähig: | 703 | sv-analytics | 10.10.181.103 | Umami Analytics | ✅ Running | | 704 | sv-frontend | 10.10.181.104 | Multi-Project Next.js | ✅ Running | -### Hetzner 3 (Production) +### Hetzner 3 (CMS Production) - [x] Debian 13 Installation - [x] PostgreSQL 17 mit payload_db und umami_db @@ -41,6 +43,14 @@ Die komplette Entwicklungsinfrastruktur ist eingerichtet und funktionsfähig: - [x] Backup-Scripts (täglich) - [x] CVE-2025-55182 Hotfix +### Hetzner 1 + 2 (Frontend Production) + +- [x] Hetzner 1 (78.46.87.137): blogwoman.de — Plesk, nginx-only, Passenger 6.1.0, Node 22 +- [x] Hetzner 2 (94.130.141.114): porwoll.de — Plesk, nginx-only, Passenger 6.1.0, Node 22 +- [x] GitHub Webhooks für Auto-Deploy bei Push auf main +- [x] SSH-Zugriff von sv-payload (root, key: plesk_deploy) +- [x] Env-Vars pro Domain (Tenant-spezifisch) + ### Caddy Reverse Proxy (sv-caddy) - [x] Caddy 2.9.x mit Cloudflare DNS Plugin @@ -124,13 +134,35 @@ Die komplette Entwicklungsinfrastruktur ist eingerichtet und funktionsfähig: - [x] SSH-Zugriff mit Key - [x] VS Code Remote-SSH kompatibel +### Multi-Server Orchestration (Phase 1-8) + +- [x] **SSH-Infrastruktur:** sv-payload → sv-frontend, Hetzner 1/2 (root) +- [x] **payload-contracts Repo:** Shared types, API client, block registry + - Type-Extraction aus CMS payload-types.ts + - `createPayloadClient()` mit Tenant-Isolation + - `createBlockRenderer()` mit discriminated unions +- [x] **Work-Order-System:** Git-basierte Koordination CMS → Frontends + - Template + Scripts (`create-work-order.sh`, `execute-work-order.sh`) +- [x] **blogwoman.de Migration:** Contracts-Client + Bridge-Pattern +- [x] **porwoll.de Migration:** Direkte Contracts-Types, 9 Blocks +- [x] **Claude Code auf sv-frontend:** v2.1.37, CLAUDE.md in allen Repos +- [x] **Plesk Production Deployment:** + - Hetzner 1 (78.46.87.137): blogwoman.de — nginx-only + Passenger + - Hetzner 2 (94.130.141.114): porwoll.de — nginx-only + Passenger + - GitHub Webhooks für Auto-Deploy (Push main → Plesk Git Pull → Build) +- [x] **CI/CD GitHub Actions:** + - CI: Lint + Build auf push develop/main + - Staging Deploy: SSH via UDM Pro SE Port-Forward (37.24.237.181:2204) + - Production Deploy: Plesk Git-Integration (Webhook) + ### GitHub Repositories -Organisation: **complexcaresolutions** (Internal) +Organisation: **complexcaresolutions** (Public Frontend-Repos) -- [x] cms.c2sgmbh (Payload CMS) -- [x] frontend.porwoll.de -- [x] frontend.blogwoman.de +- [x] cms.c2sgmbh (Payload CMS) — Internal +- [x] payload-contracts (Shared Types + API Client) — Internal +- [x] frontend.porwoll.de — **Live auf porwoll.de** +- [x] frontend.blogwoman.de — **Live auf blogwoman.de** - [x] frontend.caroline-porwoll.com - [x] frontend.caroline-porwoll.de - [x] frontend.complexcaresolutions.de @@ -153,24 +185,34 @@ Organisation: **complexcaresolutions** (Internal) ## 🔜 Nächste Schritte -### Kurzfristig (diese Woche) +### Erledigt -1. [x] ~~Meta (Facebook/Instagram) Kommentar-Synchronisation fertigstellen~~ -2. [x] ~~YouTube Thumbnail-Download für Offline-Anzeige~~ +1. [x] ~~Meta (Facebook/Instagram) Kommentar-Synchronisation~~ +2. [x] ~~YouTube Thumbnail-Download~~ +3. [x] ~~Monitoring & Alerting Dashboard~~ +4. [x] ~~Multi-Server Orchestration (8 Phasen)~~ +5. [x] ~~porwoll.de Frontend (Live auf Plesk)~~ +6. [x] ~~blogwoman.de Frontend (Live auf Plesk)~~ +7. [x] ~~CI/CD Pipelines (GitHub Actions + Plesk Webhooks)~~ -### Mittelfristig (Februar/März 2026) +### Kurzfristig -3. [ ] porwoll.de Frontend-Entwicklung -4. [ ] blogwoman.de Frontend mit YouTube-Integration -5. [ ] Design-System (Tailwind + Shadcn/UI) -6. [ ] Frontend-Staging auf Hetzner 3 +8. [ ] porwoll.de: Fehlende Blocks implementieren (~6 Blocks via Work Orders) +9. [ ] blogwoman.de: Types-Bridge durch direkte Contracts-Imports ersetzen +10. [ ] blogwoman.de: YouTube-Serien-Integration vervollständigen -### Langfristig (Q1 2026) +### Mittelfristig (März/April 2026) -7. [ ] Alle 9 Frontends entwickeln -8. [ ] Migration von Plesk-Domains zu neuer Infra -9. [ ] AI-gestützte Kommentar-Moderation -10. [x] ~~Monitoring & Alerting Dashboard~~ +11. [ ] complexcaresolutions.de Frontend starten +12. [ ] caroline-porwoll.com/de Frontend starten +13. [ ] Cookie-Banner implementieren (DSGVO) +14. [ ] Weitere Frontends auf Plesk deployen + +### Langfristig (Q2 2026) + +15. [ ] Alle 9 Frontends entwickeln und deployen +16. [ ] AI-gestützte Kommentar-Moderation +17. [ ] Performance-Optimierung (ISR, Edge Caching) --- @@ -189,10 +231,12 @@ Organisation: **complexcaresolutions** (Internal) ### Production (Hetzner) -| Service | URL | Status | -|---------|-----|--------| -| Payload CMS | https://cms.c2sgmbh.de | ✅ | -| Umami Analytics | https://analytics.c2sgmbh.de | ✅ | +| Service | URL | Server | Status | +|---------|-----|--------|--------| +| Payload CMS | https://cms.c2sgmbh.de | Hetzner 3 | ✅ | +| Umami Analytics | https://analytics.c2sgmbh.de | Hetzner 3 | ✅ | +| blogwoman.de | https://blogwoman.de | Hetzner 1 | ✅ | +| porwoll.de | https://porwoll.de | Hetzner 2 | ✅ | --- @@ -214,7 +258,7 @@ codex # Codex CLI gemini # Gemini CLI ``` -### Hetzner 3 +### Hetzner 3 (CMS Production) ```bash # SSH Zugang @@ -227,11 +271,36 @@ ssh payload@162.55.85.18 pm2 logs payload ``` +### Hetzner 1 + 2 (Frontend Production) + +```bash +# SSH Zugang (von sv-payload) +ssh hetzner1 # 78.46.87.137 - blogwoman.de +ssh hetzner2 # 94.130.141.114 - porwoll.de + +# Logs +ssh hetzner1 "passenger-status" +ssh hetzner2 "passenger-status" + +# Git-Status prüfen +ssh hetzner1 "cd /var/www/vhosts/blogwoman.de/httpdocs && git log --oneline -3" +ssh hetzner2 "cd /var/www/vhosts/porwoll.de/httpdocs && git log --oneline -3" +``` + --- ## 📝 Änderungsprotokoll ### 15.02.2026 +- **Multi-Server Orchestration (Phase 1-8) abgeschlossen:** + - SSH-Infrastruktur: sv-payload → sv-frontend (key: frontend_deploy), Hetzner 1/2 (key: plesk_deploy) + - payload-contracts Repo: Shared types, API client, block registry (Git-Dependency) + - Work-Order-System: `create-work-order.sh` + `execute-work-order.sh` für CMS→Frontend-Koordination + - blogwoman.de: Migration auf Contracts-Client (Bridge-Pattern), live auf Hetzner 1 + - porwoll.de: Direkte Contracts-Types, 9 Blocks, live auf Hetzner 2 + - Plesk Production: nginx-only + Passenger 6.1.0, GitHub Webhooks (Auto-Deploy) + - CI/CD: Lint+Build CI, Staging-Deploy via SSH (UDM Pro SE Port-Forward 37.24.237.181:2204) + - Claude Code v2.1.37 auf sv-frontend mit CLAUDE.md in allen Repos - **Monitoring & Alerting Dashboard implementiert:** - 4 neue Collections: MonitoringSnapshots, MonitoringLogs, MonitoringAlertRules, MonitoringAlertHistory - Backend-Services: MonitoringService, PerformanceTracker, MonitoringLogger, AlertEvaluator, SnapshotCollector diff --git a/docs/anleitungen/FRONTEND.md b/docs/anleitungen/FRONTEND.md index b68b043..cce0e6f 100644 --- a/docs/anleitungen/FRONTEND.md +++ b/docs/anleitungen/FRONTEND.md @@ -2,12 +2,125 @@ > **Server:** sv-frontend (LXC 704) - 10.10.181.104 > **Backend API:** https://cms.c2sgmbh.de/api (Production) +> **Shared Types:** `@c2s/payload-contracts` (Git-Dependency) ## Übersicht -Das Frontend wird als separates Next.js-Projekt entwickelt und nutzt Payload CMS als Headless CMS über die REST-API. +Jedes Frontend ist ein separates Next.js-Projekt und nutzt Payload CMS als Headless CMS über die REST-API. Alle Frontends teilen sich TypeScript-Typen und den API-Client über das `payload-contracts` Package. -**Wichtig:** Die Frontend-Entwicklung verwendet die **Produktions-API und -Datenbank**, um mit echten Inhalten zu arbeiten. SEO-Einstellungen und Cookie-Consent-Konfigurationen werden ebenfalls aus der Produktionsumgebung geladen. +**Architektur:** +``` +CMS (payload-cms) payload-contracts Frontends (Next.js) +━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━ +Collections + Blocks → Shared Types → frontend.porwoll.de +payload-types.ts → API Client → frontend.blogwoman.de + Block Registry → (7 weitere) +``` + +--- + +## payload-contracts (Shared Package) + +Alle Frontends verwenden `@c2s/payload-contracts` als Git-Dependency für TypeScript-Typen, den API-Client und die Block-Registry. + +### Installation + +```json +// package.json +{ + "dependencies": { + "@c2s/payload-contracts": "github:complexcaresolutions/payload-contracts#main" + } +} +``` + +### Imports + +```typescript +// Types +import type { Page, Post, Media } from '@c2s/payload-contracts/types' +import type { Block, BlockByType } from '@c2s/payload-contracts/types' + +// API Client +import { createPayloadClient } from '@c2s/payload-contracts/api-client' + +// Block Renderer +import { createBlockRenderer } from '@c2s/payload-contracts/blocks' + +// Constants +import { TENANTS } from '@c2s/payload-contracts/constants' +``` + +### API Client erstellen + +```typescript +// src/lib/api.ts +import { createPayloadClient } from '@c2s/payload-contracts/api-client' + +export const api = createPayloadClient({ + baseUrl: process.env.NEXT_PUBLIC_PAYLOAD_URL!, + tenantId: Number(process.env.NEXT_PUBLIC_TENANT_ID), +}) + +// Verwendung +const page = await api.pages.getBySlug('home') +const posts = await api.posts.getAll({ limit: 10 }) +const nav = await api.navigation.get() +const settings = await api.settings.get() +``` + +### Block Renderer + +```typescript +// src/components/blocks/index.tsx +import { createBlockRenderer } from '@c2s/payload-contracts/blocks' +import { HeroBlock } from './HeroBlock' +import { TextBlock } from './TextBlock' +// ... weitere Block-Imports + +export const BlockRenderer = createBlockRenderer({ + 'hero-block': HeroBlock, + 'text-block': TextBlock, + // ... nur die Blocks registrieren, die das Frontend braucht +}) +``` + +### Block-Komponente implementieren + +```typescript +// src/components/blocks/HeroBlock.tsx +import type { BlockByType } from '@c2s/payload-contracts/types' + +type HeroBlockData = BlockByType<'hero-block'> + +interface HeroBlockProps { + block: HeroBlockData +} + +export function HeroBlock({ block }: HeroBlockProps) { + return ( +
+

{block.headline}

+ {block.subline &&

{block.subline}

} +
+ ) +} +``` + +### Types aktualisieren + +Wenn sich CMS-Collections oder Blocks ändern: + +```bash +# Auf sv-payload: +cd ~/payload-cms && pnpm payload generate:types +cd ~/payload-contracts && pnpm extract +git add -A && git commit -m "types: update from CMS" && git push + +# Auf sv-frontend (pro Projekt): +cd ~/frontend.porwoll.de +pnpm update @c2s/payload-contracts +``` --- @@ -29,15 +142,87 @@ NEXT_PUBLIC_TENANT_ID=4 NEXT_PUBLIC_TENANT_SLUG=c2s ``` +### Tenant-IDs + +| ID | Name | Slug | Domain | Status | +|----|------|------|--------|--------| +| 1 | porwoll.de | porwoll | porwoll.de | ✅ Live | +| 4 | Complex Care Solutions GmbH | c2s | complexcaresolutions.de | Geplant | +| 5 | Gunshin | gunshin | gunshin.de | Geplant | +| 9 | BlogWoman | blogwoman | blogwoman.de | ✅ Live | + ### Warum Production-Daten? -| Aspekt | Grund | -|--------|-------| -| **Content** | Echte Inhalte für realistische Entwicklung | -| **SEO** | Produktions-Meta-Tags und Structured Data | -| **Cookie-Consent** | Live Cookie-Konfigurationen (DSGVO-relevant) | -| **Media** | Produktions-Bilder mit allen Größen | -| **Consistency** | Keine Sync-Probleme zwischen Dev/Prod | +Die Frontend-Entwicklung verwendet die Produktions-API, um mit echten Inhalten zu arbeiten. SEO-Einstellungen und Cookie-Consent-Konfigurationen werden ebenfalls aus der Produktionsumgebung geladen. + +--- + +## CI/CD Pipeline + +### CI (Lint + Build) + +Jedes Frontend hat eine GitHub Actions CI-Pipeline, die bei Push auf `develop` und `main` läuft. + +```yaml +# .github/workflows/ci.yml +name: CI +on: + push: + branches: [develop, main] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: { node-version: 22, cache: pnpm } + - run: pnpm install --frozen-lockfile + - run: pnpm lint + - run: pnpm build +``` + +### Staging-Deploy (sv-frontend) + +Push auf `develop` → GitHub Actions → SSH via UDM Pro SE Port-Forward → Build auf sv-frontend. + +```yaml +# .github/workflows/deploy-staging.yml +# SSH-Credentials als Repository-Secrets: SSH_HOST, SSH_PORT, SSH_USER, SSH_PRIVATE_KEY +``` + +### Production-Deploy (Plesk) + +Push auf `main` → GitHub Webhook → Plesk Git Pull → `pnpm install && pnpm build` → Passenger Restart. + +Production-Deployment wird NICHT über GitHub Actions gesteuert, sondern über Plesk Git-Integration mit Webhooks. + +### Deployment-Flow + +``` +develop (sv-frontend) → CI ✅ → Staging-Test (*-dev.porwoll.tech) + │ + ▼ +main (merge) → CI ✅ → Webhook → Plesk → Production ✅ +``` + +--- + +## Work-Order-System + +Wenn ein neuer Block oder eine neue Collection im CMS erstellt wird, koordiniert das Work-Order-System die Frontend-Implementierung. + +### Ablauf + +1. **sv-payload:** CMS ändern → Types extrahieren → Work Order schreiben +2. **sv-frontend:** Work Order lesen → `pnpm update @c2s/payload-contracts` → Block implementieren + +### Referenz + +Vollständige Dokumentation im `payload-contracts` Repo: +- `work-orders/_template.md` — Vorlage +- `scripts/create-work-order.sh` — Work Order erstellen (auf sv-payload) +- `scripts/execute-work-order.sh` — Work Order ausführen (auf sv-frontend) --- @@ -51,80 +236,31 @@ NEXT_PUBLIC_TENANT_SLUG=c2s --- -## Offene Frontend-Tasks +## Frontend-Status -### Hohe Priorität +### Live -- [ ] **Block-Komponenten entwickeln** - - [ ] Hero Block - - [ ] Hero Slider Block - - [ ] Text Block - - [ ] Image Text Block - - [ ] Card Grid Block - - [ ] Quote Block - - [ ] CTA Block - - [ ] Contact Form Block - - [ ] Video Block - - [ ] Divider Block - - [ ] Timeline Block - - [ ] Posts List Block - - [ ] Testimonials Block - - [ ] Newsletter Block - - [ ] Process Steps Block - - [ ] FAQ Block - - [ ] Team Block - - [ ] Services Block +| Frontend | Production | Blocks | Contracts | +|----------|-----------|--------|-----------| +| porwoll.de | ✅ Hetzner 2 | 9 implementiert | Direkte Types | +| blogwoman.de | ✅ Hetzner 1 | Alle implementiert | Bridge-Pattern (lokale types.ts) | -- [ ] **Newsletter-Anmelde-Formular** - - API: `POST /api/newsletter/subscribe` - - Double Opt-In Flow bereits im Backend implementiert - - Felder: email, firstName (optional), tenantId, source +### Geplant -- [ ] **Cookie-Banner implementieren** - - Cookie Configurations aus Production-API laden - - Consent-Logs an Backend senden - - DSGVO-konform mit Opt-In +| Frontend | Server | Priorität | +|----------|--------|-----------| +| complexcaresolutions.de | Hetzner 1 | Hoch | +| caroline-porwoll.com | Hetzner 2 | Mittel | +| caroline-porwoll.de | Hetzner 2 | Mittel | +| gunshin.de | - | Niedrig | +| zweitmeinu.ng | Hetzner 1 | Niedrig | -### Mittlere Priorität +### Offene Tasks -- [ ] **Multi-Tenant Routing** - - Domain-basierte Tenant-Erkennung - - Locale-Routing (`/[locale]/...`) - - Unterstützte Locales: `de` (default), `en` - -- [ ] **SEO-Integration** - - Meta-Tags aus Pages/Posts (Production) - - Structured Data (JSON-LD) - - Sitemap: https://cms.c2sgmbh.de/sitemap.xml - -- [ ] **Suche implementieren** - - API: `GET /api/search?q=...&locale=de` - - Auto-Complete: `GET /api/search/suggestions?q=...` - - Rate-Limit: 30 Requests/Minute - -### Tenant-spezifische Features - -#### porwoll.de -- [ ] Portfolio-Galerie (Fotografie) -- [ ] Buchungsformular -- [ ] Before/After Bildvergleich - -#### complexcaresolutions.de (C2S) -- [ ] Team-Übersicht -- [ ] Leistungs-Seiten -- [ ] Zertifizierungen -- [ ] Karriere-Seite mit Stellenangeboten - -#### gunshin.de (Game Development) -- [ ] Projekt-Galerie - - API: `GET /api/projects?where[tenant][equals]=5` -- [ ] Portfolio-Seiten -- [ ] Referenzen-Slider - -#### zweitmein.ng -- [ ] FAQ-Sektion -- [ ] Preistabellen -- [ ] Kontaktformular +- [ ] porwoll.de: Fehlende Blocks implementieren (~6 via Work Orders) +- [ ] blogwoman.de: Bridge-Pattern durch direkte Contracts-Imports ersetzen +- [ ] Cookie-Banner implementieren (DSGVO) +- [ ] Newsletter-Formular-Komponente --- @@ -149,21 +285,7 @@ NEXT_PUBLIC_TENANT_SLUG=c2s | Favorites | `GET /api/favorites` | Affiliate-Produkte (BlogWoman) | | Series | `GET /api/series` | YouTube-Serien (BlogWoman) | -### Community Management (YouTube/Meta) - -| Collection | Endpoint | Beschreibung | -|------------|----------|--------------| -| YouTube Channels | `GET /api/youtube-channels` | Multi-Kanal-Verwaltung | -| YouTube Content | `GET /api/youtube-content` | Videos + Shorts mit Kommentaren | -| YT Series | `GET /api/yt-series` | Serien mit Branding (Logo, Farben) | -| YT Notifications | `GET /api/yt-notifications` | Handlungsbedarf-System | -| Social Platforms | `GET /api/social-platforms` | Plattform-Konfiguration | -| Social Accounts | `GET /api/social-accounts` | OAuth-Verbindungen | -| Community Interactions | `GET /api/community-interactions` | Kommentare/Nachrichten | - -### Site Settings & Navigation (Tenant-isolierte Collections) - -> **Hinweis:** SiteSettings und Navigations wurden zu tenant-spezifischen Collections umgewandelt. +### Site Settings & Navigation (Tenant-isoliert) | Collection | Endpoint | Beschreibung | |------------|----------|--------------| @@ -171,12 +293,6 @@ NEXT_PUBLIC_TENANT_SLUG=c2s | Navigation | `GET /api/navigations?where[tenant][equals]=4` | Menü-Struktur | | Privacy Policy | `GET /api/privacy-policy-settings?where[tenant][equals]=4` | Datenschutz | -### Globals (Systemweit) - -| Global | Endpoint | Beschreibung | -|--------|----------|--------------| -| SEO Settings | `GET /api/globals/seo-settings` | Default SEO (Production) | - ### Spezielle Endpoints | Endpoint | Methode | Beschreibung | @@ -184,8 +300,6 @@ NEXT_PUBLIC_TENANT_SLUG=c2s | `/api/search` | GET | Volltextsuche | | `/api/search/suggestions` | GET | Auto-Complete | | `/api/newsletter/subscribe` | POST | Newsletter-Anmeldung | -| `/api/timelines` | GET | Timeline-Daten | -| `/api/workflows` | GET | Workflow-Daten | --- @@ -194,24 +308,14 @@ NEXT_PUBLIC_TENANT_SLUG=c2s Alle Collection-Anfragen sollten nach Tenant gefiltert werden: ```typescript -// Beispiel: Posts für Tenant "c2s" (ID: 4) +// Mit payload-contracts API Client (empfohlen): +const posts = await api.posts.getAll({ limit: 10 }) +// → Tenant-Filter wird automatisch angewendet + +// Manuell: fetch('https://cms.c2sgmbh.de/api/posts?where[tenant][equals]=4&locale=de') - -// Beispiel: Pages für Tenant "gunshin" (ID: 5) -fetch('https://cms.c2sgmbh.de/api/pages?where[tenant][equals]=5&locale=de') - -// Beispiel: SEO-Settings (Global, kein Tenant-Filter) -fetch('https://cms.c2sgmbh.de/api/globals/seo-settings') ``` -### Tenant-IDs - -| ID | Name | Slug | Domain | -|----|------|------|--------| -| 1 | porwoll.de | porwoll | porwoll.de | -| 4 | Complex Care Solutions GmbH | c2s | complexcaresolutions.de | -| 5 | Gunshin | gunshin | gunshin.de | - --- ## Bild-Optimierung @@ -259,8 +363,6 @@ fetch('https://cms.c2sgmbh.de/api/posts?locale=en') ## Newsletter-Integration -### Anmeldung - ```typescript const response = await fetch('https://cms.c2sgmbh.de/api/newsletter/subscribe', { method: 'POST', @@ -272,148 +374,13 @@ const response = await fetch('https://cms.c2sgmbh.de/api/newsletter/subscribe', source: 'footer' // optional: Herkunft }) }) - -// Response: { success: true, message: '...' } ``` -### Flow -1. User gibt E-Mail ein → `POST /api/newsletter/subscribe` -2. Backend sendet Double Opt-In E-Mail -3. User klickt Bestätigungs-Link -4. Backend sendet Willkommens-E-Mail -5. User kann sich über Link in E-Mails abmelden +**Flow:** Subscribe → Double Opt-In E-Mail → Bestätigung → Willkommens-E-Mail --- -## Cookie-Consent (Production-Daten) - -### Konfiguration laden - -```typescript -// Cookie-Konfiguration aus Production laden -const config = await fetch('https://cms.c2sgmbh.de/api/cookie-configurations?where[tenant][equals]=4') - .then(r => r.json()) - -// config.docs enthält: -// - Kategorien (necessary, analytics, marketing, etc.) -// - Cookie-Details pro Kategorie -// - Texte für Banner (lokalisiert) -``` - -### Consent loggen - -```typescript -await fetch('https://cms.c2sgmbh.de/api/consent-logs', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - tenant: 4, - consentGiven: true, - categories: ['necessary', 'analytics'], - ipAddress: '...', // Optional, für DSGVO - userAgent: navigator.userAgent - }) -}) -``` - ---- - -## SEO-Integration (Production-Daten) - -### Global SEO-Settings - -```typescript -// SEO-Defaults aus Production laden -const seoSettings = await fetch('https://cms.c2sgmbh.de/api/globals/seo-settings') - .then(r => r.json()) - -// Enthält: -// - defaultTitle, titleTemplate -// - defaultDescription -// - defaultImage (OG-Image) -// - robotsDefault -``` - -### Page-spezifische SEO - -```typescript -// SEO-Daten aus Page laden -const page = await fetch('https://cms.c2sgmbh.de/api/pages?where[slug][equals]=about&where[tenant][equals]=4') - .then(r => r.json()) - -// page.docs[0].meta enthält: -// - title, description -// - image (OG-Image Override) -// - noIndex, noFollow -``` - -### Sitemap - -Die Sitemap wird automatisch von Payload generiert: -- **URL:** https://cms.c2sgmbh.de/sitemap.xml -- Enthält alle publizierten Pages und Posts - ---- - -## Kontaktformular - -Formular-Submissions werden über die Forms-Collection verarbeitet: - -```typescript -await fetch('https://cms.c2sgmbh.de/api/form-submissions', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - form: 1, // Form-ID - submissionData: [ - { field: 'name', value: 'Max Mustermann' }, - { field: 'email', value: 'max@example.com' }, - { field: 'message', value: 'Ihre Nachricht...' } - ] - }) -}) -``` - ---- - -## Authentifizierung (optional) - -Falls User-Authentifizierung benötigt wird: - -```typescript -// Login -const { token, user } = await fetch('https://cms.c2sgmbh.de/api/users/login', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email, password }) -}).then(r => r.json()) - -// Authentifizierte Requests -fetch('https://cms.c2sgmbh.de/api/...', { - headers: { 'Authorization': `JWT ${token}` } -}) -``` - ---- - -## Entwicklungshinweise - -### TypeScript-Typen - -Die Payload-Typen können aus dem Backend exportiert werden: - -```bash -# Auf dem Payload-Server (Production) -ssh payload@162.55.85.18 -cd ~/payload-cms -pnpm payload generate:types - -# Datei: src/payload-types.ts -``` - -Diese Datei kann ins Frontend-Projekt kopiert werden für typsichere API-Calls. - -### Rate-Limits +## Rate-Limits | Endpoint | Limit | |----------|-------| @@ -422,18 +389,6 @@ Diese Datei kann ins Frontend-Projekt kopiert werden für typsichere API-Calls. | Newsletter | 5/10min | | Formulare | 5/10min | -### Caching - -- API-Responses werden serverseitig gecacht (Redis) -- TTL: 60 Sekunden für Suche -- Cache wird bei Content-Änderungen invalidiert - -### CORS - -Die Production-API erlaubt Requests von: -- `*.porwoll.tech` (Development) -- `porwoll.de`, `complexcaresolutions.de`, `gunshin.de` (Production) - --- ## Development Server (sv-frontend) @@ -455,72 +410,55 @@ pnpm dev ### AI-Tools ```bash -claude # Claude Code CLI +claude # Claude Code CLI (v2.1.37) codex # Codex CLI gemini # Gemini CLI ``` -### Service-Management - -```bash -# Systemd Service starten -systemctl start frontend-porwoll - -# Service stoppen -systemctl stop frontend-porwoll - -# Logs anzeigen -journalctl -u frontend-porwoll -f -``` - --- -## Community Management Integration +## ESLint-Konfiguration -### YouTube-Inhalte abrufen +Alle Frontends verwenden die gleiche ESLint-Konfiguration: -```typescript -// Alle Videos eines Kanals -const videos = await fetch( - 'https://cms.c2sgmbh.de/api/youtube-content?where[channel][equals]=1&where[contentType][equals]=video' -).then(r => r.json()) +```javascript +// eslint.config.mjs +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; -// Serien eines Kanals -const series = await fetch( - 'https://cms.c2sgmbh.de/api/yt-series?where[channel][equals]=1&where[isActive][equals]=true' -).then(r => r.json()) +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + { + rules: { + "@typescript-eslint/no-unused-vars": ["warn", { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + }], + }, + }, + globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts", "server.js"]), +]); -// Videos einer Serie -const seriesVideos = await fetch( - 'https://cms.c2sgmbh.de/api/youtube-content?where[series][equals]=1' -).then(r => r.json()) +export default eslintConfig; ``` -### Kommentare/Interaktionen (Auth erforderlich) - -```typescript -// Kommentare eines Videos -const comments = await fetch( - 'https://cms.c2sgmbh.de/api/community-interactions?where[contentId][equals]=VIDEO_ID', - { headers: { 'Authorization': `JWT ${token}` } } -).then(r => r.json()) - -// Ungelesene Benachrichtigungen -const notifications = await fetch( - 'https://cms.c2sgmbh.de/api/yt-notifications?where[status][equals]=unread', - { headers: { 'Authorization': `JWT ${token}` } } -).then(r => r.json()) -``` +`server.js` wird ignoriert, da es CJS für Phusion Passenger verwendet. --- ## Ressourcen -- **Payload CMS Docs:** https://payloadcms.com/docs -- **API-Dokumentation:** https://cms.c2sgmbh.de/api/docs -- **Backend-Repository:** https://github.com/complexcaresolutions/cms.c2sgmbh.git -- **Analytics:** https://analytics.c2sgmbh.de +| Ressource | URL/Pfad | +|-----------|----------| +| Payload CMS Docs | https://payloadcms.com/docs | +| API-Dokumentation | https://cms.c2sgmbh.de/api/docs | +| payload-contracts | https://github.com/complexcaresolutions/payload-contracts | +| Infrastruktur-Docs | `docs/INFRASTRUCTURE.md` | +| Analytics | https://analytics.c2sgmbh.de | --- -*Letzte Aktualisierung: 17.01.2026* +*Letzte Aktualisierung: 15.02.2026*