mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 17:24:12 +00:00
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 <noreply@anthropic.com>
This commit is contained in:
parent
0e978e77f4
commit
9f7a9ad558
3 changed files with 580 additions and 388 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
# Infrastruktur Dokumentation
|
# Infrastruktur Dokumentation
|
||||||
|
|
||||||
*Letzte Aktualisierung: 13. Februar 2026*
|
*Letzte Aktualisierung: 15. Februar 2026*
|
||||||
|
|
||||||
## Gesamtübersicht
|
## Gesamtübersicht
|
||||||
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
│ │ 37.24.237.179 │ cloud.complexcaresolutions.de → 10.10.179.100 │ │
|
│ │ 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.180 │ zh3.de (Nginx PM) → 10.10.180.100 │ │
|
||||||
│ │ 37.24.237.181 │ porwoll.tech (Caddy) → 10.10.181.99 │ │
|
│ │ 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) │ │
|
│ │ 37.24.237.182 │ FREI (Reserve) │ │
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ └──────────────────────────────────┬──────────────────────────────────────────┘ │
|
│ └──────────────────────────────────┬──────────────────────────────────────────┘ │
|
||||||
|
|
@ -31,15 +32,27 @@
|
||||||
│ └── porwoll.org (intern DNS only) │
|
│ └── porwoll.org (intern DNS only) │
|
||||||
│ │
|
│ │
|
||||||
│ HETZNER (Extern) │
|
│ HETZNER (Extern) │
|
||||||
│ ├── 78.46.87.137 (Hetzner 1 - zweitmeinu.ng) │
|
│ ├── 78.46.87.137 (Hetzner 1) — blogwoman.de, ccs.de, zweitmeinu.ng │
|
||||||
│ ├── 94.130.141.114 (Hetzner 2 - Porwoll) │
|
│ ├── 94.130.141.114 (Hetzner 2) — porwoll.de, caroline-porwoll.* │
|
||||||
│ └── 162.55.85.18 (Hetzner 3 - Payload Prod) │
|
│ └── 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
|
## Öffentliche IP-Adressen
|
||||||
|
|
||||||
| IP | Verwendung | Ziel (intern) |
|
| IP | Verwendung | Ziel (intern) |
|
||||||
|
|
@ -48,6 +61,7 @@
|
||||||
| 37.24.237.179 | cloud.complexcaresolutions.de | 10.10.179.100 (Nextcloud) |
|
| 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.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 | 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) | - |
|
| 37.24.237.182 | FREI (Reserve) | - |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -85,23 +99,23 @@
|
||||||
- Node.js 22.x
|
- Node.js 22.x
|
||||||
- pnpm
|
- pnpm
|
||||||
- Next.js 16.2.0-canary.41
|
- Next.js 16.2.0-canary.41
|
||||||
- Claude Code (aktuell)
|
- Claude Code 2.1.37
|
||||||
- Codex CLI (aktuell)
|
- Codex CLI (aktuell)
|
||||||
- Gemini CLI (aktuell)
|
- Gemini CLI (aktuell)
|
||||||
|
|
||||||
### Projekte & Ports
|
### Projekte & Ports
|
||||||
|
|
||||||
| Port | Service | Repository | URL |
|
| Port | Service | Repository | Staging URL | Production |
|
||||||
|------|---------|------------|-----|
|
|------|---------|------------|-------------|------------|
|
||||||
| 3000 | frontend-porwoll | frontend.porwoll.de | porwoll-dev.porwoll.tech |
|
| 3000 | frontend-porwoll | frontend.porwoll.de | porwoll-dev.porwoll.tech | **porwoll.de** ✅ |
|
||||||
| 3001 | frontend-blogwoman | frontend.blogwoman.de | blogwoman-dev.porwoll.tech |
|
| 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 |
|
| 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 |
|
| 3003 | frontend-caroline-de | frontend.caroline-porwoll.de | caroline-de-dev.porwoll.tech | - |
|
||||||
| 3004 | frontend-ccs | frontend.complexcaresolutions.de | ccs-dev.porwoll.tech |
|
| 3004 | frontend-ccs | frontend.complexcaresolutions.de | ccs-dev.porwoll.tech | - |
|
||||||
| 3005 | frontend-gunshin | frontend.gunshin.de | gunshin-dev.porwoll.tech |
|
| 3005 | frontend-gunshin | frontend.gunshin.de | gunshin-dev.porwoll.tech | - |
|
||||||
| 3006 | frontend-sensual | frontend.sensualmoment.de | sensual-dev.porwoll.tech |
|
| 3006 | frontend-sensual | frontend.sensualmoment.de | sensual-dev.porwoll.tech | - |
|
||||||
| 3007 | frontend-zweitmeinu | frontend.zweitmeinu.ng | zweitmeinu-dev.porwoll.tech |
|
| 3007 | frontend-zweitmeinu | frontend.zweitmeinu.ng | zweitmeinu-dev.porwoll.tech | - |
|
||||||
| 3008 | frontend-zytoskandal | frontend.zytoskandal.de | zytoskandal-dev.porwoll.tech |
|
| 3008 | frontend-zytoskandal | frontend.zytoskandal.de | zytoskandal-dev.porwoll.tech | - |
|
||||||
|
|
||||||
### Service-Verwaltung
|
### Service-Verwaltung
|
||||||
|
|
||||||
|
|
@ -136,24 +150,137 @@ systemctl status frontend-*
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## GitHub Organisation: complexcaresolutions
|
## SSH-Infrastruktur
|
||||||
|
|
||||||
| Repository | Beschreibung | Visibility |
|
### Verbindungen von sv-payload
|
||||||
|------------|--------------|------------|
|
|
||||||
| cms.c2sgmbh | Payload CMS Backend | Internal |
|
| Ziel | Host-Alias | User | Key | Zweck |
|
||||||
| frontend.porwoll.de | porwoll.de Frontend | Internal |
|
|------|-----------|------|-----|-------|
|
||||||
| frontend.blogwoman.de | blogwoman.de Frontend | Internal |
|
| sv-frontend (10.10.181.104) | `sv-frontend` | frontend | `~/.ssh/frontend_deploy` | Entwicklung, Work Orders |
|
||||||
| frontend.caroline-porwoll.com | caroline-porwoll.com Frontend | Internal |
|
| Hetzner 1 (78.46.87.137) | `hetzner1` | root | `~/.ssh/plesk_deploy` | Production Troubleshooting |
|
||||||
| frontend.caroline-porwoll.de | caroline-porwoll.de Frontend | Internal |
|
| Hetzner 2 (94.130.141.114) | `hetzner2` | root | `~/.ssh/plesk_deploy` | Production Troubleshooting |
|
||||||
| frontend.complexcaresolutions.de | CCS Website Frontend | Internal |
|
|
||||||
| frontend.gunshin.de | gunshin.de Frontend | Internal |
|
### SSH-Config (`/home/payload/.ssh/config`)
|
||||||
| frontend.sensualmoment.de | sensualmoment.de Frontend | Internal |
|
|
||||||
| frontend.zweitmeinu.ng | zweitmeinu.ng Frontend | Internal |
|
```
|
||||||
| frontend.zytoskandal.de | zytoskandal.de Frontend | Internal |
|
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
|
- **IP:** 162.55.85.18
|
||||||
- **Domain:** cms.c2sgmbh.de
|
- **Domain:** cms.c2sgmbh.de
|
||||||
|
|
@ -185,16 +312,58 @@ systemctl status frontend-*
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Development Workflow
|
## Deployment-Workflow
|
||||||
|
|
||||||
|
### CMS (Payload)
|
||||||
|
|
||||||
```
|
```
|
||||||
DEVELOPMENT STAGING PRODUCTION
|
sv-payload (develop) → GitHub CI → sv-payload (main) → Hetzner 3 (deploy.sh)
|
||||||
sv-frontend → sv-payload → Hetzner 03
|
|
||||||
porwoll.tech pl.porwoll.tech cms.c2sgmbh.de
|
|
||||||
develop branch main branch
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**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)
|
### Production (Hetzner)
|
||||||
|
|
||||||
| Service | URL |
|
| Service | URL | Server |
|
||||||
|---------|-----|
|
|---------|-----|--------|
|
||||||
| Payload Admin | https://cms.c2sgmbh.de/admin |
|
| Payload Admin | https://cms.c2sgmbh.de/admin | Hetzner 3 |
|
||||||
| Payload API | https://cms.c2sgmbh.de/api |
|
| Payload API | https://cms.c2sgmbh.de/api | Hetzner 3 |
|
||||||
| Umami Analytics | https://analytics.c2sgmbh.de |
|
| Umami Analytics | https://analytics.c2sgmbh.de | Hetzner 3 |
|
||||||
|
| blogwoman.de | https://blogwoman.de | Hetzner 1 |
|
||||||
|
| porwoll.de | https://porwoll.de | Hetzner 2 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Frontend-Server
|
# --- Development ---
|
||||||
ssh frontend@10.10.181.104
|
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
|
# --- CMS Production ---
|
||||||
ssh payload@162.55.85.18
|
ssh payload@162.55.85.18 # Hetzner 3
|
||||||
|
pm2 logs payload # CMS Logs
|
||||||
|
|
||||||
# Caddy neu laden
|
# --- Frontend Production ---
|
||||||
ssh root@10.10.181.99 "systemctl reload caddy"
|
ssh hetzner1 # Hetzner 1 (blogwoman.de)
|
||||||
|
ssh hetzner2 # Hetzner 2 (porwoll.de)
|
||||||
|
|
||||||
# Frontend Service starten
|
# Git-Status auf Production prüfen
|
||||||
systemctl start frontend-porwoll
|
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*
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ Die komplette Entwicklungsinfrastruktur ist eingerichtet und funktionsfähig:
|
||||||
- Analytics (Umami)
|
- Analytics (Umami)
|
||||||
- **Community Management System** (YouTube, Facebook, Instagram)
|
- **Community Management System** (YouTube, Facebook, Instagram)
|
||||||
- **YouTube Operations Hub** (Multi-Kanal-Verwaltung)
|
- **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 |
|
| 703 | sv-analytics | 10.10.181.103 | Umami Analytics | ✅ Running |
|
||||||
| 704 | sv-frontend | 10.10.181.104 | Multi-Project Next.js | ✅ 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] Debian 13 Installation
|
||||||
- [x] PostgreSQL 17 mit payload_db und umami_db
|
- [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] Backup-Scripts (täglich)
|
||||||
- [x] CVE-2025-55182 Hotfix
|
- [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)
|
### Caddy Reverse Proxy (sv-caddy)
|
||||||
|
|
||||||
- [x] Caddy 2.9.x mit Cloudflare DNS Plugin
|
- [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] SSH-Zugriff mit Key
|
||||||
- [x] VS Code Remote-SSH kompatibel
|
- [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
|
### GitHub Repositories
|
||||||
|
|
||||||
Organisation: **complexcaresolutions** (Internal)
|
Organisation: **complexcaresolutions** (Public Frontend-Repos)
|
||||||
|
|
||||||
- [x] cms.c2sgmbh (Payload CMS)
|
- [x] cms.c2sgmbh (Payload CMS) — Internal
|
||||||
- [x] frontend.porwoll.de
|
- [x] payload-contracts (Shared Types + API Client) — Internal
|
||||||
- [x] frontend.blogwoman.de
|
- [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.com
|
||||||
- [x] frontend.caroline-porwoll.de
|
- [x] frontend.caroline-porwoll.de
|
||||||
- [x] frontend.complexcaresolutions.de
|
- [x] frontend.complexcaresolutions.de
|
||||||
|
|
@ -153,24 +185,34 @@ Organisation: **complexcaresolutions** (Internal)
|
||||||
|
|
||||||
## 🔜 Nächste Schritte
|
## 🔜 Nächste Schritte
|
||||||
|
|
||||||
### Kurzfristig (diese Woche)
|
### Erledigt
|
||||||
|
|
||||||
1. [x] ~~Meta (Facebook/Instagram) Kommentar-Synchronisation fertigstellen~~
|
1. [x] ~~Meta (Facebook/Instagram) Kommentar-Synchronisation~~
|
||||||
2. [x] ~~YouTube Thumbnail-Download für Offline-Anzeige~~
|
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
|
8. [ ] porwoll.de: Fehlende Blocks implementieren (~6 Blocks via Work Orders)
|
||||||
4. [ ] blogwoman.de Frontend mit YouTube-Integration
|
9. [ ] blogwoman.de: Types-Bridge durch direkte Contracts-Imports ersetzen
|
||||||
5. [ ] Design-System (Tailwind + Shadcn/UI)
|
10. [ ] blogwoman.de: YouTube-Serien-Integration vervollständigen
|
||||||
6. [ ] Frontend-Staging auf Hetzner 3
|
|
||||||
|
|
||||||
### Langfristig (Q1 2026)
|
### Mittelfristig (März/April 2026)
|
||||||
|
|
||||||
7. [ ] Alle 9 Frontends entwickeln
|
11. [ ] complexcaresolutions.de Frontend starten
|
||||||
8. [ ] Migration von Plesk-Domains zu neuer Infra
|
12. [ ] caroline-porwoll.com/de Frontend starten
|
||||||
9. [ ] AI-gestützte Kommentar-Moderation
|
13. [ ] Cookie-Banner implementieren (DSGVO)
|
||||||
10. [x] ~~Monitoring & Alerting Dashboard~~
|
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)
|
### Production (Hetzner)
|
||||||
|
|
||||||
| Service | URL | Status |
|
| Service | URL | Server | Status |
|
||||||
|---------|-----|--------|
|
|---------|-----|--------|--------|
|
||||||
| Payload CMS | https://cms.c2sgmbh.de | ✅ |
|
| Payload CMS | https://cms.c2sgmbh.de | Hetzner 3 | ✅ |
|
||||||
| Umami Analytics | https://analytics.c2sgmbh.de | ✅ |
|
| 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
|
gemini # Gemini CLI
|
||||||
```
|
```
|
||||||
|
|
||||||
### Hetzner 3
|
### Hetzner 3 (CMS Production)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# SSH Zugang
|
# SSH Zugang
|
||||||
|
|
@ -227,11 +271,36 @@ ssh payload@162.55.85.18
|
||||||
pm2 logs payload
|
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
|
## 📝 Änderungsprotokoll
|
||||||
|
|
||||||
### 15.02.2026
|
### 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:**
|
- **Monitoring & Alerting Dashboard implementiert:**
|
||||||
- 4 neue Collections: MonitoringSnapshots, MonitoringLogs, MonitoringAlertRules, MonitoringAlertHistory
|
- 4 neue Collections: MonitoringSnapshots, MonitoringLogs, MonitoringAlertRules, MonitoringAlertHistory
|
||||||
- Backend-Services: MonitoringService, PerformanceTracker, MonitoringLogger, AlertEvaluator, SnapshotCollector
|
- Backend-Services: MonitoringService, PerformanceTracker, MonitoringLogger, AlertEvaluator, SnapshotCollector
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,125 @@
|
||||||
|
|
||||||
> **Server:** sv-frontend (LXC 704) - 10.10.181.104
|
> **Server:** sv-frontend (LXC 704) - 10.10.181.104
|
||||||
> **Backend API:** https://cms.c2sgmbh.de/api (Production)
|
> **Backend API:** https://cms.c2sgmbh.de/api (Production)
|
||||||
|
> **Shared Types:** `@c2s/payload-contracts` (Git-Dependency)
|
||||||
|
|
||||||
## Übersicht
|
## Ü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 (
|
||||||
|
<section>
|
||||||
|
<h1>{block.headline}</h1>
|
||||||
|
{block.subline && <p>{block.subline}</p>}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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
|
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?
|
### Warum Production-Daten?
|
||||||
|
|
||||||
| Aspekt | Grund |
|
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.
|
||||||
|--------|-------|
|
|
||||||
| **Content** | Echte Inhalte für realistische Entwicklung |
|
---
|
||||||
| **SEO** | Produktions-Meta-Tags und Structured Data |
|
|
||||||
| **Cookie-Consent** | Live Cookie-Konfigurationen (DSGVO-relevant) |
|
## CI/CD Pipeline
|
||||||
| **Media** | Produktions-Bilder mit allen Größen |
|
|
||||||
| **Consistency** | Keine Sync-Probleme zwischen Dev/Prod |
|
### 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**
|
| Frontend | Production | Blocks | Contracts |
|
||||||
- [ ] Hero Block
|
|----------|-----------|--------|-----------|
|
||||||
- [ ] Hero Slider Block
|
| porwoll.de | ✅ Hetzner 2 | 9 implementiert | Direkte Types |
|
||||||
- [ ] Text Block
|
| blogwoman.de | ✅ Hetzner 1 | Alle implementiert | Bridge-Pattern (lokale types.ts) |
|
||||||
- [ ] 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
|
|
||||||
|
|
||||||
- [ ] **Newsletter-Anmelde-Formular**
|
### Geplant
|
||||||
- API: `POST /api/newsletter/subscribe`
|
|
||||||
- Double Opt-In Flow bereits im Backend implementiert
|
|
||||||
- Felder: email, firstName (optional), tenantId, source
|
|
||||||
|
|
||||||
- [ ] **Cookie-Banner implementieren**
|
| Frontend | Server | Priorität |
|
||||||
- Cookie Configurations aus Production-API laden
|
|----------|--------|-----------|
|
||||||
- Consent-Logs an Backend senden
|
| complexcaresolutions.de | Hetzner 1 | Hoch |
|
||||||
- DSGVO-konform mit Opt-In
|
| 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**
|
- [ ] porwoll.de: Fehlende Blocks implementieren (~6 via Work Orders)
|
||||||
- Domain-basierte Tenant-Erkennung
|
- [ ] blogwoman.de: Bridge-Pattern durch direkte Contracts-Imports ersetzen
|
||||||
- Locale-Routing (`/[locale]/...`)
|
- [ ] Cookie-Banner implementieren (DSGVO)
|
||||||
- Unterstützte Locales: `de` (default), `en`
|
- [ ] Newsletter-Formular-Komponente
|
||||||
|
|
||||||
- [ ] **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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -149,21 +285,7 @@ NEXT_PUBLIC_TENANT_SLUG=c2s
|
||||||
| Favorites | `GET /api/favorites` | Affiliate-Produkte (BlogWoman) |
|
| Favorites | `GET /api/favorites` | Affiliate-Produkte (BlogWoman) |
|
||||||
| Series | `GET /api/series` | YouTube-Serien (BlogWoman) |
|
| Series | `GET /api/series` | YouTube-Serien (BlogWoman) |
|
||||||
|
|
||||||
### Community Management (YouTube/Meta)
|
### Site Settings & Navigation (Tenant-isoliert)
|
||||||
|
|
||||||
| 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.
|
|
||||||
|
|
||||||
| Collection | Endpoint | Beschreibung |
|
| Collection | Endpoint | Beschreibung |
|
||||||
|------------|----------|--------------|
|
|------------|----------|--------------|
|
||||||
|
|
@ -171,12 +293,6 @@ NEXT_PUBLIC_TENANT_SLUG=c2s
|
||||||
| Navigation | `GET /api/navigations?where[tenant][equals]=4` | Menü-Struktur |
|
| Navigation | `GET /api/navigations?where[tenant][equals]=4` | Menü-Struktur |
|
||||||
| Privacy Policy | `GET /api/privacy-policy-settings?where[tenant][equals]=4` | Datenschutz |
|
| 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
|
### Spezielle Endpoints
|
||||||
|
|
||||||
| Endpoint | Methode | Beschreibung |
|
| Endpoint | Methode | Beschreibung |
|
||||||
|
|
@ -184,8 +300,6 @@ NEXT_PUBLIC_TENANT_SLUG=c2s
|
||||||
| `/api/search` | GET | Volltextsuche |
|
| `/api/search` | GET | Volltextsuche |
|
||||||
| `/api/search/suggestions` | GET | Auto-Complete |
|
| `/api/search/suggestions` | GET | Auto-Complete |
|
||||||
| `/api/newsletter/subscribe` | POST | Newsletter-Anmeldung |
|
| `/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:
|
Alle Collection-Anfragen sollten nach Tenant gefiltert werden:
|
||||||
|
|
||||||
```typescript
|
```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')
|
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
|
## Bild-Optimierung
|
||||||
|
|
@ -259,8 +363,6 @@ fetch('https://cms.c2sgmbh.de/api/posts?locale=en')
|
||||||
|
|
||||||
## Newsletter-Integration
|
## Newsletter-Integration
|
||||||
|
|
||||||
### Anmeldung
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const response = await fetch('https://cms.c2sgmbh.de/api/newsletter/subscribe', {
|
const response = await fetch('https://cms.c2sgmbh.de/api/newsletter/subscribe', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -272,148 +374,13 @@ const response = await fetch('https://cms.c2sgmbh.de/api/newsletter/subscribe',
|
||||||
source: 'footer' // optional: Herkunft
|
source: 'footer' // optional: Herkunft
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Response: { success: true, message: '...' }
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Flow
|
**Flow:** Subscribe → Double Opt-In E-Mail → Bestätigung → Willkommens-E-Mail
|
||||||
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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cookie-Consent (Production-Daten)
|
## Rate-Limits
|
||||||
|
|
||||||
### 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
|
|
||||||
|
|
||||||
| Endpoint | Limit |
|
| Endpoint | Limit |
|
||||||
|----------|-------|
|
|----------|-------|
|
||||||
|
|
@ -422,18 +389,6 @@ Diese Datei kann ins Frontend-Projekt kopiert werden für typsichere API-Calls.
|
||||||
| Newsletter | 5/10min |
|
| Newsletter | 5/10min |
|
||||||
| Formulare | 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)
|
## Development Server (sv-frontend)
|
||||||
|
|
@ -455,72 +410,55 @@ pnpm dev
|
||||||
### AI-Tools
|
### AI-Tools
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
claude # Claude Code CLI
|
claude # Claude Code CLI (v2.1.37)
|
||||||
codex # Codex CLI
|
codex # Codex CLI
|
||||||
gemini # Gemini 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
|
```javascript
|
||||||
// Alle Videos eines Kanals
|
// eslint.config.mjs
|
||||||
const videos = await fetch(
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
'https://cms.c2sgmbh.de/api/youtube-content?where[channel][equals]=1&where[contentType][equals]=video'
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||||
).then(r => r.json())
|
import nextTs from "eslint-config-next/typescript";
|
||||||
|
|
||||||
// Serien eines Kanals
|
const eslintConfig = defineConfig([
|
||||||
const series = await fetch(
|
...nextVitals,
|
||||||
'https://cms.c2sgmbh.de/api/yt-series?where[channel][equals]=1&where[isActive][equals]=true'
|
...nextTs,
|
||||||
).then(r => r.json())
|
{
|
||||||
|
rules: {
|
||||||
|
"@typescript-eslint/no-unused-vars": ["warn", {
|
||||||
|
argsIgnorePattern: "^_",
|
||||||
|
varsIgnorePattern: "^_",
|
||||||
|
destructuredArrayIgnorePattern: "^_",
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts", "server.js"]),
|
||||||
|
]);
|
||||||
|
|
||||||
// Videos einer Serie
|
export default eslintConfig;
|
||||||
const seriesVideos = await fetch(
|
|
||||||
'https://cms.c2sgmbh.de/api/youtube-content?where[series][equals]=1'
|
|
||||||
).then(r => r.json())
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Kommentare/Interaktionen (Auth erforderlich)
|
`server.js` wird ignoriert, da es CJS für Phusion Passenger verwendet.
|
||||||
|
|
||||||
```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())
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Ressourcen
|
## Ressourcen
|
||||||
|
|
||||||
- **Payload CMS Docs:** https://payloadcms.com/docs
|
| Ressource | URL/Pfad |
|
||||||
- **API-Dokumentation:** https://cms.c2sgmbh.de/api/docs
|
|-----------|----------|
|
||||||
- **Backend-Repository:** https://github.com/complexcaresolutions/cms.c2sgmbh.git
|
| Payload CMS Docs | https://payloadcms.com/docs |
|
||||||
- **Analytics:** https://analytics.c2sgmbh.de
|
| 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*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue