mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 17:24:12 +00:00
- CLAUDE.md: Update tech stack versions (Payload 3.68.4, Next.js 15.5.9, React 19.2.3) - CLAUDE.md: Expand architecture with sv-caddy (LXC 699) and sv-frontend (LXC 704) - CLAUDE.md: Add Videos and VideoCategories collections - CLAUDE.md: Update documentation references section - INFRASTRUCTURE.md: Complete rewrite with current infrastructure - PROJECT_STATUS.md: Add new project status document - TODO.md: Add changelog entry for documentation consolidation - Remove obsolete: INFRASTRUCTURE_COMPLETE_DECEMBER_2025.md, TECHSTACK_COMPLETE_DECEMBER_2025.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1030 lines
33 KiB
Markdown
1030 lines
33 KiB
Markdown
# Payload CMS Multi-Tenant Project
|
|
|
|
## Projektübersicht
|
|
|
|
Multi-Tenant CMS für 4 Websites unter einer Payload CMS 3.x Instanz:
|
|
|
|
- porwoll.de
|
|
- complexcaresolutions.de
|
|
- gunshin.de
|
|
- zweitmein.ng
|
|
|
|
## Tech Stack
|
|
|
|
- **CMS:** Payload CMS 3.68.4
|
|
- **Framework:** Next.js 15.5.9
|
|
- **React:** 19.2.3
|
|
- **Sprache:** TypeScript
|
|
- **Runtime:** Node.js 22.x
|
|
- **Datenbank:** PostgreSQL 17.6 (separater Server)
|
|
- **Connection Pool:** PgBouncer 1.24.1 (Transaction-Mode)
|
|
- **Reverse Proxy:** Caddy 2.9.x mit Let's Encrypt (Dev) / Nginx (Prod)
|
|
- **Process Manager:** PM2
|
|
- **Package Manager:** pnpm
|
|
- **Cache:** Redis 7.x (optional, mit In-Memory-Fallback)
|
|
- **Job Queue:** BullMQ (Redis-basiert)
|
|
- **Analytics:** Umami 3.x
|
|
- **AI Tools:** Claude Code, Codex CLI, Gemini CLI
|
|
|
|
## Architektur
|
|
|
|
### Development (VLAN 181 - porwoll.tech)
|
|
|
|
```
|
|
Internet → Cloudflare → 37.24.237.181 → Caddy (sv-caddy) → Services
|
|
↓
|
|
┌───────────────────────────┴───────────────────────────┐
|
|
│ │
|
|
sv-payload:3000 sv-frontend:3000-3008
|
|
(Payload CMS) (9 Frontend-Projekte)
|
|
│
|
|
PgBouncer (6432)
|
|
│
|
|
PostgreSQL (sv-postgres:5432)
|
|
```
|
|
|
|
| LXC | Hostname | IP | Service | Status |
|
|
|-----|----------|-----|---------|--------|
|
|
| 699 | sv-caddy | 10.10.181.99 | Caddy Reverse Proxy | ✅ Running |
|
|
| 700 | sv-payload | 10.10.181.100 | Payload CMS + Redis | ✅ Running |
|
|
| 701 | sv-postgres | 10.10.181.101 | PostgreSQL 17 + Redis Commander | ✅ Running |
|
|
| 702 | sv-dev-payload | 10.10.181.102 | Payload Experimental | ⏸️ Stopped |
|
|
| 703 | sv-analytics | 10.10.181.103 | Umami Analytics | ✅ Running |
|
|
| 704 | sv-frontend | 10.10.181.104 | Multi-Frontend Dev (9 Projekte) | ✅ Running |
|
|
|
|
### Production (Hetzner 3)
|
|
|
|
| Service | URL | Port |
|
|
|---------|-----|------|
|
|
| Payload CMS | https://cms.c2sgmbh.de | 3001 |
|
|
| Umami Analytics | https://analytics.c2sgmbh.de | 3000 |
|
|
| PostgreSQL 17 | localhost | 5432 |
|
|
| Redis Cache | localhost | 6379 |
|
|
|
|
## Wichtige Pfade
|
|
|
|
```
|
|
/home/payload/payload-cms/ # Projektroot
|
|
├── src/
|
|
│ ├── payload.config.ts # Haupt-Konfiguration
|
|
│ ├── collections/ # Alle Collections
|
|
│ │ ├── Users.ts
|
|
│ │ ├── Media.ts
|
|
│ │ ├── Tenants.ts
|
|
│ │ ├── Posts.ts
|
|
│ │ ├── Categories.ts
|
|
│ │ ├── Portfolios.ts
|
|
│ │ ├── PortfolioCategories.ts
|
|
│ │ ├── FAQs.ts
|
|
│ │ ├── Team.ts
|
|
│ │ ├── ServiceCategories.ts
|
|
│ │ ├── Services.ts
|
|
│ │ ├── EmailLogs.ts
|
|
│ │ ├── AuditLogs.ts
|
|
│ │ └── ...
|
|
│ ├── app/(payload)/api/ # Custom API Routes
|
|
│ │ ├── users/login/route.ts # Custom Login mit Audit
|
|
│ │ ├── send-email/route.ts
|
|
│ │ ├── email-logs/
|
|
│ │ │ ├── export/route.ts
|
|
│ │ │ └── stats/route.ts
|
|
│ │ └── test-email/route.ts
|
|
│ ├── lib/
|
|
│ │ ├── email/ # E-Mail-System
|
|
│ │ │ ├── tenant-email-service.ts
|
|
│ │ │ ├── payload-email-adapter.ts
|
|
│ │ │ ├── newsletter-service.ts # Newsletter Double Opt-In
|
|
│ │ │ └── newsletter-templates.ts # E-Mail-Templates
|
|
│ │ ├── security/ # Security-Module
|
|
│ │ │ ├── rate-limiter.ts
|
|
│ │ │ ├── csrf.ts
|
|
│ │ │ ├── ip-allowlist.ts
|
|
│ │ │ └── data-masking.ts
|
|
│ │ ├── queue/ # BullMQ Job Queue
|
|
│ │ │ ├── queue-service.ts
|
|
│ │ │ ├── jobs/email-job.ts
|
|
│ │ │ ├── jobs/pdf-job.ts
|
|
│ │ │ ├── workers/email-worker.ts
|
|
│ │ │ └── workers/pdf-worker.ts
|
|
│ │ ├── pdf/ # PDF-Generierung
|
|
│ │ │ └── pdf-service.ts
|
|
│ │ ├── search.ts # Volltextsuche
|
|
│ │ └── redis.ts # Redis Cache Client
|
|
│ └── hooks/ # Collection Hooks
|
|
│ ├── sendFormNotification.ts
|
|
│ ├── sendNewsletterConfirmation.ts # Newsletter Double Opt-In
|
|
│ ├── invalidateEmailCache.ts
|
|
│ └── auditLog.ts
|
|
├── tests/ # Test Suite
|
|
│ ├── unit/security/ # Security Unit Tests
|
|
│ └── int/ # Integration Tests
|
|
├── scripts/
|
|
│ ├── run-queue-worker.ts # Queue Worker Starter
|
|
│ └── backup/ # Backup-System
|
|
│ ├── backup-db.sh # PostgreSQL Backup-Skript
|
|
│ ├── restore-db.sh # PostgreSQL Restore-Skript
|
|
│ ├── setup-backup.sh # Interaktives Setup
|
|
│ └── README.md # Backup-Dokumentation
|
|
├── .env # Umgebungsvariablen
|
|
├── ecosystem.config.cjs # PM2 Config
|
|
└── .next/ # Build Output
|
|
```
|
|
|
|
## Umgebungsvariablen (.env)
|
|
|
|
> **Hinweis:** Sensible Credentials (DB_PASSWORD, SMTP_PASS, etc.) werden aus `~/.pgpass`
|
|
> und Umgebungsvariablen gelesen. Niemals Klartext-Passwörter in diese Datei schreiben!
|
|
|
|
```env
|
|
# Datenbank (Passwort in ~/.pgpass oder als Umgebungsvariable)
|
|
DATABASE_URI=postgresql://payload:${DB_PASSWORD}@127.0.0.1:6432/payload_db
|
|
PAYLOAD_SECRET=a53b254070d3fffd2b5cfcc3
|
|
PAYLOAD_PUBLIC_SERVER_URL=https://pl.porwoll.tech
|
|
NEXT_PUBLIC_SERVER_URL=https://pl.porwoll.tech
|
|
NODE_ENV=production
|
|
PORT=3000
|
|
|
|
# E-Mail (Global Fallback)
|
|
SMTP_HOST=smtp.example.com
|
|
SMTP_PORT=587
|
|
SMTP_SECURE=false
|
|
SMTP_USER=user@example.com
|
|
SMTP_PASS=secret
|
|
SMTP_FROM_ADDRESS=noreply@c2sgmbh.de
|
|
SMTP_FROM_NAME=Payload CMS
|
|
|
|
# Redis Cache
|
|
REDIS_URL=redis://localhost:6379
|
|
|
|
# Security
|
|
CSRF_SECRET=your-csrf-secret # PFLICHT in Production (oder PAYLOAD_SECRET)
|
|
TRUST_PROXY=true # PFLICHT hinter Reverse-Proxy (Caddy/Nginx)
|
|
SEND_EMAIL_ALLOWED_IPS= # Optional: Komma-separierte IPs/CIDRs
|
|
ADMIN_ALLOWED_IPS= # Optional: IP-Beschränkung für Admin-Panel
|
|
BLOCKED_IPS= # Optional: Global geblockte IPs
|
|
```
|
|
|
|
> **Wichtig:** `TRUST_PROXY=true` muss gesetzt sein wenn die App hinter einem Reverse-Proxy
|
|
> (wie Caddy) läuft. Ohne diese Einstellung funktionieren IP-basierte Sicherheitsfunktionen
|
|
> (Rate-Limiting, IP-Allowlists, Blocklists) nicht korrekt.
|
|
|
|
## PgBouncer Connection Pooling
|
|
|
|
PgBouncer läuft auf dem App-Server und pooled Datenbankverbindungen:
|
|
|
|
```bash
|
|
# Konfiguration
|
|
/etc/pgbouncer/pgbouncer.ini
|
|
/etc/pgbouncer/userlist.txt # chmod 600
|
|
|
|
# Service
|
|
sudo systemctl status pgbouncer
|
|
sudo systemctl restart pgbouncer
|
|
|
|
# Statistiken abfragen
|
|
# Pool-Statistiken (Passwort aus ~/.pgpass)
|
|
PGPASSWORD="$DB_PASSWORD" psql -h 127.0.0.1 -p 6432 -U payload -d pgbouncer -c "SHOW POOLS;"
|
|
PGPASSWORD="$DB_PASSWORD" psql -h 127.0.0.1 -p 6432 -U payload -d pgbouncer -c "SHOW STATS;"
|
|
```
|
|
|
|
**Konfiguration:**
|
|
| Parameter | Wert | Beschreibung |
|
|
|-----------|------|--------------|
|
|
| pool_mode | transaction | Verbindung wird nach Transaktion freigegeben |
|
|
| default_pool_size | 20 | Standard-Pool-Größe pro DB/User |
|
|
| min_pool_size | 5 | Mindestens gehaltene Verbindungen |
|
|
| reserve_pool_size | 5 | Reserve für Lastspitzen |
|
|
| max_db_connections | 50 | Max. Verbindungen zu PostgreSQL |
|
|
| max_client_conn | 200 | Max. Clients zu PgBouncer |
|
|
|
|
**Verbindungen:**
|
|
- App → PgBouncer: `127.0.0.1:6432` (DATABASE_URI)
|
|
- PgBouncer → PostgreSQL: `10.10.181.101:5432` (TLS 1.3, `server_tls_sslmode = require`)
|
|
|
|
**Direkte Verbindung (für Migrationen/CLI):**
|
|
|
|
PgBouncer im Transaction-Mode kann Probleme mit lang laufenden Migrationen verursachen.
|
|
Für solche Fälle das `db-direct.sh` Skript verwenden:
|
|
|
|
```bash
|
|
# Migrationen direkt an PostgreSQL (umgeht PgBouncer)
|
|
./scripts/db-direct.sh migrate
|
|
|
|
# Interaktive psql-Session
|
|
./scripts/db-direct.sh psql
|
|
|
|
# Schema-Änderungen
|
|
./scripts/db-direct.sh migrate:create
|
|
```
|
|
|
|
Das Skript liest Credentials aus `~/.pgpass` (chmod 600).
|
|
|
|
## Multi-Tenant Plugin
|
|
|
|
Verwendet `@payloadcms/plugin-multi-tenant` für Mandantenfähigkeit.
|
|
|
|
**Aktuelle Tenants:**
|
|
| ID | Name | Slug |
|
|
|----|------|------|
|
|
| 1 | porwoll.de | porwoll |
|
|
| 4 | Complex Care Solutions GmbH | c2s |
|
|
| 5 | Gunshin | gunshin |
|
|
|
|
**User-Tenant-Zuweisung:** Tabelle `users_tenants`
|
|
|
|
## Wichtige Befehle
|
|
|
|
```bash
|
|
# Entwicklung
|
|
pnpm dev
|
|
|
|
# Production Build
|
|
pnpm build
|
|
|
|
# Migrationen
|
|
pnpm payload migrate:create
|
|
pnpm payload migrate
|
|
|
|
# ImportMap nach Plugin-Änderungen
|
|
pnpm payload generate:importmap
|
|
|
|
# PM2
|
|
pm2 status
|
|
pm2 logs payload
|
|
pm2 logs queue-worker
|
|
pm2 restart payload
|
|
pm2 restart queue-worker
|
|
|
|
# Tests
|
|
pnpm test # Alle Tests
|
|
pnpm test:security # Security Tests
|
|
pnpm test:access-control # Access Control Tests
|
|
pnpm test:coverage # Mit Coverage-Report
|
|
|
|
# Datenbank prüfen
|
|
# Verwende ./scripts/db-direct.sh psql oder:
|
|
PGPASSWORD="$DB_PASSWORD" psql -h 10.10.181.101 -U payload -d payload_db
|
|
|
|
# Backup
|
|
/home/payload/backups/postgres/backup-db.sh --verbose # Manuelles Backup
|
|
scripts/backup/setup-backup.sh # Backup-System einrichten
|
|
```
|
|
|
|
## Workflow nach Code-Änderungen
|
|
|
|
1. Code ändern
|
|
2. `pnpm build`
|
|
3. `pm2 restart payload`
|
|
4. Testen unter https://pl.porwoll.tech/admin
|
|
|
|
## Bekannte Besonderheiten
|
|
|
|
- **ES Modules:** package.json hat `"type": "module"`, daher PM2 Config als `.cjs`
|
|
- **Plugin ImportMap:** Nach Plugin-Änderungen `pnpm payload generate:importmap` ausführen
|
|
- **User-Tenant-Zuweisung:** Neue User müssen manuell Tenants zugewiesen bekommen
|
|
- **Admin Login:** Custom Route mit Audit-Logging, unterstützt JSON und `_payload` FormData
|
|
|
|
## Build-Konfiguration
|
|
|
|
Der Build ist für speichereffizientes Kompilieren optimiert:
|
|
|
|
- `package.json`: `--max-old-space-size=2048` (2GB Heap-Limit)
|
|
- `next.config.mjs`: `experimental.cpus: 1`, `workerThreads: false`
|
|
|
|
**WICHTIG:** Der Server hat 8GB RAM ohne Swap. Bei laufendem VS Code Server kann der Build mit reduziertem Memory ausgeführt werden:
|
|
|
|
```bash
|
|
pm2 stop payload # Speicher freigeben
|
|
NODE_OPTIONS="--no-deprecation --max-old-space-size=1024" ./node_modules/.bin/next build
|
|
pm2 start payload
|
|
```
|
|
|
|
Ohne PM2-Stop und mit VS Code wird der Build vom OOM Killer beendet (Exit code 137).
|
|
|
|
## Mehrsprachigkeit (i18n)
|
|
|
|
Das System unterstützt Deutsch (default) und Englisch:
|
|
|
|
- **Admin UI:** `@payloadcms/translations` für DE/EN
|
|
- **Content:** Localization mit Fallback auf Deutsch
|
|
- **Datenbank:** 36 `_locales` Tabellen für lokalisierte Felder
|
|
- **API:** `?locale=de` oder `?locale=en` Parameter
|
|
- **Frontend:** Routing über `/[locale]/...`
|
|
|
|
```bash
|
|
# Locales in der Datenbank prüfen
|
|
# Verwende ./scripts/db-direct.sh psql oder:
|
|
PGPASSWORD="$DB_PASSWORD" psql -h 10.10.181.101 -U payload -d payload_db -c "\dt *_locales"
|
|
```
|
|
|
|
## URLs
|
|
|
|
- **Admin Panel:** https://pl.porwoll.tech/admin
|
|
- **API:** https://pl.porwoll.tech/api
|
|
- **API-Dokumentation (Swagger UI):** https://pl.porwoll.tech/api/docs
|
|
- **OpenAPI JSON:** https://pl.porwoll.tech/api/openapi.json
|
|
- **E-Mail API:** https://pl.porwoll.tech/api/send-email (POST, Auth erforderlich)
|
|
- **Test-E-Mail:** https://pl.porwoll.tech/api/test-email (POST, Admin erforderlich)
|
|
- **E-Mail Stats:** https://pl.porwoll.tech/api/email-logs/stats (GET, Auth erforderlich)
|
|
- **PDF-Generierung:** https://pl.porwoll.tech/api/generate-pdf (POST/GET, Auth erforderlich)
|
|
- **Newsletter Anmeldung:** https://pl.porwoll.tech/api/newsletter/subscribe (POST, öffentlich)
|
|
- **Newsletter Bestätigung:** https://pl.porwoll.tech/api/newsletter/confirm (GET/POST)
|
|
- **Newsletter Abmeldung:** https://pl.porwoll.tech/api/newsletter/unsubscribe (GET/POST)
|
|
- **Timeline API:** https://pl.porwoll.tech/api/timelines (GET, öffentlich, tenant required)
|
|
- **Workflows API:** https://pl.porwoll.tech/api/workflows (GET, öffentlich, tenant required)
|
|
- **Data Retention API:** https://pl.porwoll.tech/api/retention (GET/POST, Super-Admin erforderlich)
|
|
|
|
## Security-Features
|
|
|
|
### Proxy-Vertrauen (TRUST_PROXY)
|
|
**WICHTIG:** Wenn die App hinter einem Reverse-Proxy läuft (Caddy, Nginx, etc.),
|
|
muss `TRUST_PROXY=true` gesetzt sein:
|
|
|
|
```env
|
|
TRUST_PROXY=true
|
|
```
|
|
|
|
Ohne diese Einstellung:
|
|
- Werden `X-Forwarded-For` und `X-Real-IP` Header ignoriert
|
|
- Können Angreifer IP-basierte Sicherheitsmaßnahmen nicht umgehen
|
|
- Aber: Rate-Limiting und IP-Allowlists funktionieren nicht korrekt
|
|
|
|
### Rate-Limiting
|
|
Zentraler Rate-Limiter mit vordefinierten Limits:
|
|
- `publicApi`: 60 Requests/Minute
|
|
- `auth`: 5 Requests/15 Minuten (Login)
|
|
- `email`: 10 Requests/Minute
|
|
- `search`: 30 Requests/Minute
|
|
- `form`: 5 Requests/10 Minuten
|
|
|
|
**Hinweis:** Rate-Limiting basiert auf Client-IP. Bei `TRUST_PROXY=false` wird
|
|
`direct-connection` als IP verwendet, was alle Clients zusammenfasst.
|
|
|
|
### CSRF-Schutz
|
|
- Double Submit Cookie Pattern
|
|
- Origin-Header-Validierung
|
|
- Token-Endpoint: `GET /api/csrf-token`
|
|
- Admin-Panel hat eigenen CSRF-Schutz
|
|
- **CSRF_SECRET oder PAYLOAD_SECRET ist in Production PFLICHT**
|
|
- Server startet nicht ohne Secret in Production
|
|
|
|
### IP-Allowlist
|
|
- Konfigurierbar via `SEND_EMAIL_ALLOWED_IPS`, `ADMIN_ALLOWED_IPS`
|
|
- Unterstützt IPs, CIDRs (`192.168.1.0/24`) und Wildcards (`10.10.*.*`)
|
|
- Globale Blocklist via `BLOCKED_IPS`
|
|
- **Warnung:** Leere Allowlists erlauben standardmäßig alle IPs
|
|
|
|
### Data-Masking
|
|
- Automatische Maskierung sensibler Daten in Logs
|
|
- Erkennt Passwörter, Tokens, API-Keys, SMTP-Credentials
|
|
- Safe-Logger-Factory für konsistentes Logging
|
|
|
|
## E-Mail-System
|
|
|
|
Multi-Tenant E-Mail-System mit tenant-spezifischer SMTP-Konfiguration:
|
|
|
|
**Architektur:**
|
|
- Globaler SMTP als Fallback (via .env)
|
|
- Tenant-spezifische SMTP in Tenants Collection
|
|
- Transporter-Caching mit automatischer Invalidierung
|
|
- EmailLogs Collection für Audit-Trail
|
|
|
|
**Tenant E-Mail-Konfiguration:**
|
|
```
|
|
Tenants → email → fromAddress, fromName, replyTo
|
|
→ email → useCustomSmtp (Checkbox)
|
|
→ email → smtp → host, port, secure, user, pass
|
|
```
|
|
|
|
**API-Endpoint `/api/send-email`:**
|
|
```bash
|
|
curl -X POST https://pl.porwoll.tech/api/send-email \
|
|
-H "Content-Type: application/json" \
|
|
-H "Cookie: payload-token=..." \
|
|
-d '{
|
|
"to": "empfaenger@example.com",
|
|
"subject": "Betreff",
|
|
"html": "<p>Inhalt</p>",
|
|
"tenantId": 1
|
|
}'
|
|
```
|
|
|
|
**Sicherheit:**
|
|
- Authentifizierung erforderlich
|
|
- Tenant-Zugriffskontrolle (User muss Tenant-Mitglied sein)
|
|
- Rate-Limiting: 10 E-Mails/Minute pro User
|
|
- SMTP-Passwort nie in API-Responses
|
|
|
|
### Newsletter Double Opt-In
|
|
|
|
DSGVO-konformes Newsletter-System mit Double Opt-In:
|
|
|
|
**Flow:**
|
|
1. User meldet sich an → Status: `pending`, Token wird generiert
|
|
2. Double Opt-In E-Mail wird automatisch gesendet
|
|
3. User klickt Bestätigungs-Link → Status: `confirmed`
|
|
4. Willkommens-E-Mail wird gesendet
|
|
5. Abmeldung jederzeit über Link in E-Mails möglich
|
|
|
|
**API-Endpoints:**
|
|
|
|
```bash
|
|
# Newsletter-Anmeldung
|
|
curl -X POST https://pl.porwoll.tech/api/newsletter/subscribe \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"email": "user@example.com",
|
|
"firstName": "Max",
|
|
"tenantId": 1,
|
|
"source": "footer"
|
|
}'
|
|
|
|
# Bestätigung (via Link aus E-Mail)
|
|
GET https://pl.porwoll.tech/api/newsletter/confirm?token=<uuid>
|
|
|
|
# Abmeldung (via Link aus E-Mail)
|
|
GET https://pl.porwoll.tech/api/newsletter/unsubscribe?token=<uuid>
|
|
```
|
|
|
|
**Features:**
|
|
- Automatischer E-Mail-Versand bei Anmeldung
|
|
- Token-Ablauf nach 48 Stunden
|
|
- Willkommens-E-Mail nach Bestätigung
|
|
- Abmelde-Bestätigung per E-Mail
|
|
- Rate-Limiting: 5 Anmeldungen/10 Minuten pro IP
|
|
- Erneute Anmeldung nach Abmeldung möglich
|
|
|
|
## BullMQ Job Queue
|
|
|
|
Das System verwendet BullMQ für asynchrone Job-Verarbeitung mit Redis als Backend.
|
|
|
|
### PM2 Worker
|
|
|
|
Der Queue-Worker läuft als separater PM2-Prozess:
|
|
|
|
```bash
|
|
# Worker-Status prüfen
|
|
pm2 status
|
|
pm2 logs queue-worker
|
|
|
|
# Worker neustarten
|
|
pm2 restart queue-worker
|
|
```
|
|
|
|
### Email Queue
|
|
|
|
E-Mails können asynchron über die Queue versendet werden:
|
|
|
|
```typescript
|
|
import { queueEmail } from '@/lib/queue'
|
|
|
|
await queueEmail({
|
|
tenantId: 1,
|
|
to: 'empfaenger@example.com',
|
|
subject: 'Betreff',
|
|
html: '<p>Inhalt</p>',
|
|
source: 'form-submission'
|
|
})
|
|
```
|
|
|
|
### PDF Queue
|
|
|
|
PDF-Generierung erfolgt über Playwright (HTML/URL zu PDF):
|
|
|
|
**API-Endpoint `/api/generate-pdf`:**
|
|
```bash
|
|
# PDF aus HTML generieren
|
|
curl -X POST https://pl.porwoll.tech/api/generate-pdf \
|
|
-H "Content-Type: application/json" \
|
|
-H "Cookie: payload-token=..." \
|
|
-d '{
|
|
"source": "html",
|
|
"html": "<h1>Test</h1><p>Inhalt</p>",
|
|
"filename": "test.pdf"
|
|
}'
|
|
|
|
# Job-Status abfragen
|
|
curl "https://pl.porwoll.tech/api/generate-pdf?jobId=abc123" \
|
|
-H "Cookie: payload-token=..."
|
|
```
|
|
|
|
**Programmatisch:**
|
|
```typescript
|
|
import { queuePdfFromHtml, queuePdfFromUrl, getPdfJobStatus } from '@/lib/queue'
|
|
|
|
// HTML zu PDF
|
|
const job = await queuePdfFromHtml('<h1>Test</h1>', { filename: 'test.pdf' })
|
|
|
|
// URL zu PDF
|
|
const job2 = await queuePdfFromUrl('https://example.com', { format: 'A4' })
|
|
|
|
// Status abfragen
|
|
const status = await getPdfJobStatus(job.id)
|
|
```
|
|
|
|
### Worker-Konfiguration
|
|
|
|
Über `ecosystem.config.cjs`:
|
|
- `QUEUE_EMAIL_CONCURRENCY`: Parallele E-Mail-Jobs (default: 3)
|
|
- `QUEUE_PDF_CONCURRENCY`: Parallele PDF-Jobs (default: 2)
|
|
- `QUEUE_RETENTION_CONCURRENCY`: Parallele Retention-Jobs (default: 1)
|
|
- `QUEUE_DEFAULT_RETRY`: Retry-Versuche (default: 3)
|
|
- `QUEUE_REDIS_DB`: Redis-Datenbank für Queue (default: 1)
|
|
|
|
## Data Retention
|
|
|
|
Automatische Datenbereinigung für DSGVO-Compliance und Speicheroptimierung.
|
|
|
|
### Retention Policies
|
|
|
|
| Collection | Retention | Umgebungsvariable | Beschreibung |
|
|
|------------|-----------|-------------------|--------------|
|
|
| email-logs | 90 Tage | `RETENTION_EMAIL_LOGS_DAYS` | E-Mail-Protokolle |
|
|
| audit-logs | 90 Tage | `RETENTION_AUDIT_LOGS_DAYS` | Audit-Trail |
|
|
| consent-logs | 3 Jahre | `RETENTION_CONSENT_LOGS_DAYS` | DSGVO: expiresAt-basiert |
|
|
| media (orphans) | 30 Tage | `RETENTION_MEDIA_ORPHAN_MIN_AGE_DAYS` | Unreferenzierte Medien |
|
|
|
|
### Automatischer Scheduler
|
|
|
|
Retention-Jobs laufen täglich um 03:00 Uhr (konfigurierbar via `RETENTION_CRON_SCHEDULE`).
|
|
|
|
```bash
|
|
# Umgebungsvariablen in .env
|
|
RETENTION_EMAIL_LOGS_DAYS=90
|
|
RETENTION_AUDIT_LOGS_DAYS=90
|
|
RETENTION_CONSENT_LOGS_DAYS=1095
|
|
RETENTION_MEDIA_ORPHAN_MIN_AGE_DAYS=30
|
|
RETENTION_CRON_SCHEDULE="0 3 * * *"
|
|
|
|
# Worker aktivieren/deaktivieren
|
|
QUEUE_ENABLE_RETENTION=true
|
|
QUEUE_ENABLE_RETENTION_SCHEDULER=true
|
|
```
|
|
|
|
### API-Endpoint `/api/retention`
|
|
|
|
**GET - Konfiguration abrufen:**
|
|
```bash
|
|
curl https://pl.porwoll.tech/api/retention \
|
|
-H "Cookie: payload-token=..."
|
|
```
|
|
|
|
**GET - Job-Status abfragen:**
|
|
```bash
|
|
curl "https://pl.porwoll.tech/api/retention?jobId=abc123" \
|
|
-H "Cookie: payload-token=..."
|
|
```
|
|
|
|
**POST - Manuellen Job auslösen:**
|
|
```bash
|
|
# Vollständige Retention (alle Policies + Media-Orphans)
|
|
curl -X POST https://pl.porwoll.tech/api/retention \
|
|
-H "Content-Type: application/json" \
|
|
-H "Cookie: payload-token=..." \
|
|
-d '{"type": "full"}'
|
|
|
|
# Einzelne Collection bereinigen
|
|
curl -X POST https://pl.porwoll.tech/api/retention \
|
|
-H "Content-Type: application/json" \
|
|
-H "Cookie: payload-token=..." \
|
|
-d '{"type": "collection", "collection": "email-logs"}'
|
|
|
|
# Nur Media-Orphans bereinigen
|
|
curl -X POST https://pl.porwoll.tech/api/retention \
|
|
-H "Content-Type: application/json" \
|
|
-H "Cookie: payload-token=..." \
|
|
-d '{"type": "media-orphans"}'
|
|
```
|
|
|
|
### Architektur
|
|
|
|
```
|
|
Scheduler (Cron)
|
|
↓
|
|
Retention Queue (BullMQ)
|
|
↓
|
|
Retention Worker
|
|
↓
|
|
┌─────────────────┬─────────────────┬─────────────────┐
|
|
│ Email-Logs │ Audit-Logs │ Consent-Logs │
|
|
│ (createdAt) │ (createdAt) │ (expiresAt) │
|
|
└─────────────────┴─────────────────┴─────────────────┘
|
|
↓
|
|
Media-Orphan-Cleanup
|
|
↓
|
|
Cleanup-Ergebnis (Logs)
|
|
```
|
|
|
|
### Dateien
|
|
|
|
- `src/lib/retention/retention-config.ts` - Zentrale Konfiguration
|
|
- `src/lib/retention/cleanup-service.ts` - Lösch-Logik
|
|
- `src/lib/queue/jobs/retention-job.ts` - Job-Definition
|
|
- `src/lib/queue/workers/retention-worker.ts` - Worker
|
|
- `src/app/(payload)/api/retention/route.ts` - API-Endpoint
|
|
|
|
## Redis Caching
|
|
|
|
Redis wird für API-Response-Caching und E-Mail-Transporter-Caching verwendet:
|
|
|
|
```typescript
|
|
import { redis } from '@/lib/redis'
|
|
|
|
// Cache setzen (TTL in Sekunden)
|
|
await redis.set('key', JSON.stringify(data), 'EX', 60)
|
|
|
|
// Cache lesen
|
|
const cached = await redis.get('key')
|
|
|
|
// Pattern-basierte Invalidierung
|
|
await redis.keys('posts:*').then(keys => keys.length && redis.del(...keys))
|
|
```
|
|
|
|
## Backup-System
|
|
|
|
Automatisches tägliches PostgreSQL-Backup mit lokalem Speicher und S3-Offsite-Backup.
|
|
|
|
**Setup auf neuem Server:**
|
|
```bash
|
|
cd /home/payload/payload-cms/scripts/backup
|
|
./setup-backup.sh
|
|
```
|
|
|
|
**Konfigurationsdateien (nicht im Repo):**
|
|
- `~/.pgpass` - PostgreSQL-Credentials (chmod 600)
|
|
- `~/.s3cfg` - S3-Credentials (chmod 600)
|
|
|
|
**Backup-Speicherorte:**
|
|
| Ort | Pfad | Retention |
|
|
|-----|------|-----------|
|
|
| Lokal | `/home/payload/backups/postgres/` | 30 Tage |
|
|
| S3 | `s3://c2s/backups/postgres/` | 30 Tage |
|
|
|
|
**Cron-Job:** Täglich um 03:00 Uhr
|
|
|
|
**Manuelles Backup:**
|
|
```bash
|
|
/home/payload/backups/postgres/backup-db.sh --verbose
|
|
```
|
|
|
|
**Restore aus Backup:**
|
|
```bash
|
|
# Lokal
|
|
gunzip -c /home/payload/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz | \
|
|
psql -h 10.10.181.101 -U payload -d payload_db
|
|
|
|
# Aus S3
|
|
s3cmd get s3://c2s/backups/postgres/payload_db_YYYY-MM-DD_HH-MM-SS.sql.gz
|
|
gunzip -c payload_db_*.sql.gz | psql -h 10.10.181.101 -U payload -d payload_db
|
|
```
|
|
|
|
Dokumentation: `scripts/backup/README.md`
|
|
|
|
## Datenbank-Direktzugriff
|
|
|
|
```bash
|
|
# Verwende ./scripts/db-direct.sh psql oder:
|
|
PGPASSWORD="$DB_PASSWORD" psql -h 10.10.181.101 -U payload -d payload_db
|
|
|
|
# Nützliche Queries
|
|
SELECT * FROM tenants;
|
|
SELECT * FROM users_tenants;
|
|
SELECT * FROM email_logs ORDER BY created_at DESC LIMIT 10;
|
|
SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 10;
|
|
\dt -- Alle Tabellen
|
|
```
|
|
|
|
## Blocks Übersicht
|
|
|
|
| Block | Slug | Beschreibung |
|
|
|-------|------|--------------|
|
|
| HeroBlock | hero-block | Einzelner Hero mit Bild, Headline, CTA |
|
|
| HeroSliderBlock | hero-slider-block | Hero-Slider mit mehreren Slides |
|
|
| TextBlock | text-block | Textinhalt mit Rich-Text |
|
|
| ImageTextBlock | image-text-block | Bild + Text nebeneinander |
|
|
| CardGridBlock | card-grid-block | Karten-Raster |
|
|
| QuoteBlock | quote-block | Zitat |
|
|
| CTABlock | cta-block | Call-to-Action |
|
|
| ContactFormBlock | contact-form-block | Kontaktformular |
|
|
| TimelineBlock | timeline-block | Timeline-Darstellung |
|
|
| DividerBlock | divider-block | Trennlinie |
|
|
| VideoBlock | video-block | Video einbetten |
|
|
| PostsListBlock | posts-list-block | Beitrags-Liste |
|
|
| TestimonialsBlock | testimonials-block | Kundenbewertungen |
|
|
| NewsletterBlock | newsletter-block | Newsletter-Anmeldung |
|
|
| ProcessStepsBlock | process-steps-block | Prozess-Schritte |
|
|
| FAQBlock | faq-block | FAQ-Akkordeon |
|
|
| TeamBlock | team-block | Team-Mitglieder |
|
|
| ServicesBlock | services-block | Leistungen |
|
|
| BeforeAfterBlock | before-after-block | Vorher/Nachher Bildvergleich (porwoll.de) |
|
|
|
|
### HeroSliderBlock Features
|
|
|
|
Vollwertiger Hero-Slider mit:
|
|
|
|
**Slides (Array, 1-10):**
|
|
- Hintergrundbild (Desktop + optional Mobil)
|
|
- Headline + Subline (lokalisiert)
|
|
- Text-Ausrichtung (links/zentriert/rechts)
|
|
- Vertikale Position (oben/mitte/unten)
|
|
- Overlay (Farbe, Deckkraft, Gradient)
|
|
- Primärer + Sekundärer CTA-Button
|
|
- Textfarbe (weiß/dunkel/primär)
|
|
|
|
**Animationen:**
|
|
- Typen: fade, slide, zoom, flip, none
|
|
- Konfigurierbare Dauer (300-1200ms)
|
|
|
|
**Autoplay:**
|
|
- Intervall (3-10 Sekunden)
|
|
- Pause bei Hover
|
|
- Pause bei Interaktion
|
|
|
|
**Navigation:**
|
|
- Pfeile (verschiedene Stile, Positionen)
|
|
- Dots (Punkte, Striche, Nummern, Thumbnails, Fortschritt)
|
|
- Touch-Swipe
|
|
- Tastaturnavigation
|
|
|
|
**Layout:**
|
|
- Höhe (Vollbild bis kompakt)
|
|
- Separate Mobile-Höhe
|
|
- Content-Breite
|
|
|
|
## Collections Übersicht
|
|
|
|
| Collection | Slug | Beschreibung |
|
|
|------------|------|--------------|
|
|
| Users | users | Benutzer mit isSuperAdmin Flag |
|
|
| Tenants | tenants | Mandanten mit E-Mail-Konfiguration |
|
|
| Media | media | Medien mit 11 responsive Image Sizes |
|
|
| Pages | pages | Seiten mit Blocks |
|
|
| Posts | posts | Blog/News/Presse mit Kategorien |
|
|
| Categories | categories | Kategorien für Posts |
|
|
| Portfolios | portfolios | Portfolio-Galerien (Fotografie) |
|
|
| PortfolioCategories | portfolio-categories | Kategorien für Portfolios |
|
|
| Testimonials | testimonials | Kundenbewertungen |
|
|
| FAQs | faqs | Häufig gestellte Fragen (FAQ) |
|
|
| Team | team | Team-Mitglieder und Mitarbeiter |
|
|
| ServiceCategories | service-categories | Kategorien für Leistungen |
|
|
| Services | services | Leistungen und Dienstleistungen |
|
|
| NewsletterSubscribers | newsletter-subscribers | Newsletter mit Double Opt-In |
|
|
| SocialLinks | social-links | Social Media Links |
|
|
| Forms | forms | Formular-Builder |
|
|
| FormSubmissions | form-submissions | Formular-Einsendungen mit Status-Workflow |
|
|
| EmailLogs | email-logs | E-Mail-Protokollierung |
|
|
| AuditLogs | audit-logs | Security Audit Trail |
|
|
| CookieConfigurations | cookie-configurations | Cookie-Banner Konfiguration |
|
|
| CookieInventory | cookie-inventory | Cookie-Inventar |
|
|
| ConsentLogs | consent-logs | Consent-Protokollierung |
|
|
| Timelines | timelines | Chronologische Events (Geschichte, Meilensteine) |
|
|
| Workflows | workflows | Komplexe Prozesse mit Phasen und Schritten |
|
|
| Bookings | bookings | Fotografie-Buchungen (porwoll.de) |
|
|
| Certifications | certifications | Zertifizierungen (C2S) |
|
|
| Projects | projects | Game-Development-Projekte (gunshin.de) |
|
|
| Videos | videos | Video-Bibliothek mit YouTube/Vimeo/Uploads |
|
|
| VideoCategories | video-categories | Kategorien für Videos |
|
|
|
|
## Timeline Collection
|
|
|
|
Dedizierte Collection für komplexe chronologische Darstellungen:
|
|
|
|
**Timeline-Typen:**
|
|
- `history` - Unternehmensgeschichte
|
|
- `milestones` - Projektmeilensteine
|
|
- `releases` - Produkt-Releases
|
|
- `career` - Karriere/Lebenslauf
|
|
- `events` - Ereignisse
|
|
- `process` - Prozess/Ablauf
|
|
|
|
**Event-Features:**
|
|
- Flexible Datumsformate (Jahr, Monat+Jahr, vollständig, Zeitraum, Freitext)
|
|
- Kategorien (Meilenstein, Gründung, Produkt, Team, Auszeichnung, etc.)
|
|
- Wichtigkeitsstufen (Highlight, Normal, Minor)
|
|
- Bilder und Galerien
|
|
- Links und Metadaten
|
|
- Rich-Text-Beschreibungen
|
|
|
|
**Display-Optionen:**
|
|
- Layouts: vertikal, alternierend, horizontal, kompakt
|
|
- Sortierung: aufsteigend/absteigend
|
|
- Gruppierung nach Jahr
|
|
- Verschiedene Marker-Stile
|
|
|
|
**Prozess-spezifische Felder (type=process):**
|
|
- `stepNumber` - Explizite Schritt-Nummerierung
|
|
- `duration` - Dauer (z.B. "2-3 Tage")
|
|
- `responsible` - Verantwortliche Person/Rolle
|
|
- `actionRequired` - Wer muss aktiv werden (customer, internal, both, automatic)
|
|
- `deliverables` - Ergebnisse/Dokumente des Schritts
|
|
|
|
**API-Endpoint:**
|
|
```bash
|
|
# Liste aller Timelines eines Tenants
|
|
curl "https://pl.porwoll.tech/api/timelines?tenant=1"
|
|
|
|
# Nach Typ filtern
|
|
curl "https://pl.porwoll.tech/api/timelines?tenant=1&type=history"
|
|
|
|
# Einzelne Timeline
|
|
curl "https://pl.porwoll.tech/api/timelines?tenant=1&slug=company-history"
|
|
|
|
# Mit Sprache
|
|
curl "https://pl.porwoll.tech/api/timelines?tenant=1&locale=en"
|
|
```
|
|
|
|
## Workflows Collection
|
|
|
|
Komplexe Prozess- und Workflow-Darstellungen mit Phasen, Abhängigkeiten und Status-Tracking.
|
|
|
|
**Workflow-Typen:**
|
|
- `project` - Projektabläufe
|
|
- `business` - Geschäftsprozesse
|
|
- `approval` - Genehmigungs-Workflows
|
|
- `onboarding` - Mitarbeiter-/Kundeneinführung
|
|
- `support` - Support/Service-Prozesse
|
|
- `development` - Entwicklungsprozesse
|
|
- `marketing` - Marketing-Workflows
|
|
- `other` - Sonstige
|
|
|
|
**Eigenschaften:**
|
|
- `estimatedDuration` - Geschätzte Gesamtdauer
|
|
- `complexity` - simple, medium, complex, very_complex
|
|
- `isIterative` - Kann wiederholt werden
|
|
- `allowParallelPhases` - Parallele Phasen möglich
|
|
|
|
**Display-Optionen:**
|
|
- Layouts: vertical, horizontal, flowchart, kanban, gantt
|
|
- Farbschema: phase, status, priority, brand
|
|
- Optionale Anzeige: Nummern, Zeiten, Verantwortliche, Fortschritt
|
|
|
|
**Phasen-Struktur:**
|
|
```
|
|
Workflow
|
|
└── Phasen (Array)
|
|
├── name, description, icon, color
|
|
├── estimatedDuration, responsible
|
|
├── deliverables (Array)
|
|
└── Schritte (Array)
|
|
├── name, description, stepType, priority
|
|
├── estimatedDuration, responsible
|
|
├── dependencies (dependsOnSteps, canRunParallel, isBlocking)
|
|
├── conditions (für Entscheidungen)
|
|
├── checklist (Array)
|
|
├── resources (Dokumente, Links, Tools)
|
|
└── outputs (Ergebnisse)
|
|
```
|
|
|
|
**API-Endpoint:**
|
|
```bash
|
|
# Liste aller Workflows eines Tenants
|
|
curl "https://pl.porwoll.tech/api/workflows?tenant=1"
|
|
|
|
# Nach Typ filtern
|
|
curl "https://pl.porwoll.tech/api/workflows?tenant=1&type=project"
|
|
|
|
# Nach Komplexität filtern
|
|
curl "https://pl.porwoll.tech/api/workflows?tenant=1&complexity=medium"
|
|
|
|
# Einzelner Workflow
|
|
curl "https://pl.porwoll.tech/api/workflows?tenant=1&slug=web-project"
|
|
|
|
# Mit Sprache
|
|
curl "https://pl.porwoll.tech/api/workflows?tenant=1&locale=en"
|
|
```
|
|
|
|
**Validierung:**
|
|
- `tenant` - Pflichtparameter (Tenant-Isolation)
|
|
- `type` - Validiert gegen erlaubte Typen (400 bei Fehler)
|
|
- `complexity` - Validiert gegen erlaubte Werte (400 bei Fehler)
|
|
- `locale` - de (default) oder en
|
|
|
|
## FormSubmissions CRM-Workflow
|
|
|
|
Die FormSubmissions Collection wurde zu einem leichtgewichtigen CRM erweitert:
|
|
|
|
**Status-Workflow:**
|
|
- 🆕 Neu → 👀 Gelesen → 🔄 In Bearbeitung → ⏳ Warten → ✅ Erledigt → 🗑️ Archiviert
|
|
|
|
**Features:**
|
|
- Priorität (Hoch/Normal/Niedrig)
|
|
- Zuständigkeits-Zuweisung an User
|
|
- Interne Notizen mit Auto-Autor und Zeitstempel
|
|
- Antwort-Tracking (Methode, Zeitstempel, Zusammenfassung)
|
|
- Tags zur Kategorisierung
|
|
- Auto-Markierung als gelesen beim ersten Öffnen
|
|
|
|
**Dateien:**
|
|
- `src/collections/FormSubmissionsOverrides.ts` - Feld-Definitionen
|
|
- `src/hooks/formSubmissionHooks.ts` - Automatisierungen
|
|
|
|
## Globals
|
|
|
|
| Global | Slug | Beschreibung |
|
|
|--------|------|--------------|
|
|
| SiteSettings | site-settings | Allgemeine Website-Einstellungen |
|
|
| Navigation | navigation | Navigationsmenü |
|
|
| SEOSettings | seo-settings | SEO-Einstellungen |
|
|
| PrivacyPolicySettings | privacy-policy-settings | Datenschutz-Einstellungen |
|
|
|
|
## Test Suite
|
|
|
|
```bash
|
|
# Alle Tests ausführen
|
|
pnpm test
|
|
|
|
# Security Tests
|
|
pnpm test:security
|
|
|
|
# Coverage Report
|
|
pnpm test:coverage
|
|
```
|
|
|
|
**Test Coverage Thresholds:**
|
|
- Lines: 35%
|
|
- Functions: 50%
|
|
- Branches: 65%
|
|
|
|
## CI/CD Pipeline
|
|
|
|
GitHub Actions Workflows in `.github/workflows/`:
|
|
|
|
### ci.yml (Main CI Pipeline)
|
|
Läuft bei Push/PR auf `main` und `develop`:
|
|
|
|
| Job | Beschreibung |
|
|
|-----|--------------|
|
|
| **lint** | ESLint + Prettier Check |
|
|
| **typecheck** | TypeScript Compiler (`tsc --noEmit`) |
|
|
| **test** | Unit & Integration Tests (Vitest) |
|
|
| **build** | Next.js Production Build |
|
|
| **e2e** | Playwright E2E Tests |
|
|
|
|
**Lokale Ausführung:**
|
|
```bash
|
|
pnpm lint # ESLint
|
|
pnpm typecheck # TypeScript Check
|
|
pnpm format:check # Prettier Check
|
|
pnpm format # Prettier Auto-Fix
|
|
pnpm test # Alle Tests
|
|
pnpm build # Production Build
|
|
```
|
|
|
|
### security.yml (Security Scanning)
|
|
- **Gitleaks**: Secret Scanning
|
|
- **pnpm audit**: Dependency Vulnerabilities
|
|
- **CodeQL**: Static Analysis (SAST)
|
|
- **Security Tests**: Unit & Integration Tests für Security-Module
|
|
|
|
### deploy-staging.yml (Staging Deployment)
|
|
Automatisches Deployment auf Staging-Server bei Push auf `develop`:
|
|
|
|
| Trigger | Aktion |
|
|
|---------|--------|
|
|
| Push auf `develop` | Automatisches Deployment |
|
|
| `workflow_dispatch` | Manuelles Deployment (optional: skip_tests) |
|
|
|
|
**Deployment-Ziel:**
|
|
- **URL:** https://pl.porwoll.tech
|
|
- **Server:** 37.24.237.181 (sv-payload)
|
|
|
|
**Ablauf:**
|
|
1. Pre-deployment Checks (Lint, Tests)
|
|
2. SSH-Verbindung zum Staging-Server
|
|
3. Git Pull + Dependencies installieren
|
|
4. Migrations ausführen
|
|
5. Build + PM2 Restart
|
|
6. Health Check
|
|
|
|
**Manuelles Staging-Deployment:**
|
|
```bash
|
|
# Auf dem Staging-Server (pl.porwoll.tech)
|
|
./scripts/deploy-staging.sh
|
|
|
|
# Mit Optionen
|
|
./scripts/deploy-staging.sh --skip-build # Nur Code-Update
|
|
./scripts/deploy-staging.sh --skip-migrations # Ohne Migrationen
|
|
```
|
|
|
|
**GitHub Secret erforderlich:**
|
|
- `STAGING_SSH_KEY` - SSH Private Key für `payload@37.24.237.181`
|
|
|
|
## Dokumentation
|
|
|
|
### Hauptdokumentation
|
|
- `CLAUDE.md` - Diese Datei (Projekt-Übersicht für AI-Assistenten)
|
|
- `docs/INFRASTRUCTURE.md` - Infrastruktur-Übersicht (Dev + Prod)
|
|
- `docs/PROJECT_STATUS.md` - Aktueller Projektstatus & Roadmap
|
|
- `docs/STAGING-DEPLOYMENT.md` - Staging Deployment Workflow
|
|
|
|
### Anleitungen
|
|
- `docs/anleitungen/TODO.md` - Task-Liste & Changelog
|
|
- `docs/anleitungen/SECURITY.md` - Sicherheitsrichtlinien
|
|
- `docs/anleitungen/FRONTEND.md` - Frontend-Entwicklung (sv-frontend)
|
|
- `docs/anleitungen/API_ANLEITUNG.md` - API-Dokumentation
|
|
- `docs/anleitungen/framework-monitoring.md` - Framework-Updates beobachten
|
|
|
|
### Scripts & Backup
|
|
- `scripts/backup/README.md` - Backup-System Dokumentation
|
|
|
|
*Letzte Aktualisierung: 18.12.2025*
|