further rework to the documentation

This commit is contained in:
Codex Agent
2025-11-20 12:31:21 +01:00
parent 6afa44d947
commit 9afcaa7836
90 changed files with 1721 additions and 29 deletions

View File

@@ -117,7 +117,7 @@ services:
queue:
image: registry.internal:5443/${APP_IMAGE:-fotospiel-app:latest}
command: /var/www/html/docs/queue-supervisor/queue-worker.sh default
command: /var/www/html/scripts/queue-worker.sh default
environment:
<<: *app-env
SKIP_CODE_SYNC: "1"
@@ -134,7 +134,7 @@ services:
media-storage-worker:
image: registry.internal:5443/${APP_IMAGE:-fotospiel-app:latest}
command: /var/www/html/docs/queue-supervisor/queue-worker.sh media-storage
command: /var/www/html/scripts/queue-worker.sh media-storage
environment:
<<: *app-env
QUEUE_TRIES: 5
@@ -169,7 +169,7 @@ services:
horizon:
image: registry.internal:5443/${APP_IMAGE:-fotospiel-app:latest}
command: /var/www/html/docs/queue-supervisor/horizon.sh
command: /var/www/html/scripts/horizon.sh
environment:
<<: *app-env
SKIP_CODE_SYNC: "1"

View File

@@ -42,7 +42,7 @@ services:
queue:
image: fotospiel-app:latest
command: /var/www/html/docs/queue-supervisor/queue-worker.sh default
command: /var/www/html/scripts/queue-worker.sh default
env_file:
- docker/.env.docker
environment:
@@ -56,7 +56,7 @@ services:
media-storage-worker:
image: fotospiel-app:latest
command: /var/www/html/docs/queue-supervisor/queue-worker.sh media-storage
command: /var/www/html/scripts/queue-worker.sh media-storage
env_file:
- docker/.env.docker
environment:
@@ -85,7 +85,7 @@ services:
horizon:
image: fotospiel-app:latest
command: /var/www/html/docs/queue-supervisor/horizon.sh
command: /var/www/html/scripts/horizon.sh
env_file:
- docker/.env.docker
environment:

View File

@@ -27,8 +27,8 @@ sync_code() {
}
ensure_helper_scripts() {
if compgen -G "$APP_TARGET/docs/queue-supervisor/*.sh" > /dev/null; then
chmod +x "$APP_TARGET"/docs/queue-supervisor/*.sh || true
if compgen -G "$APP_TARGET/scripts/*.sh" > /dev/null; then
chmod +x "$APP_TARGET"/scripts/*.sh || true
fi
}

View File

Before

Width:  |  Height:  |  Size: 655 KiB

After

Width:  |  Height:  |  Size: 655 KiB

View File

Before

Width:  |  Height:  |  Size: 768 KiB

After

Width:  |  Height:  |  Size: 768 KiB

View File

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View File

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 384 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 739 KiB

After

Width:  |  Height:  |  Size: 739 KiB

View File

Before

Width:  |  Height:  |  Size: 365 KiB

After

Width:  |  Height:  |  Size: 365 KiB

View File

Before

Width:  |  Height:  |  Size: 340 KiB

After

Width:  |  Height:  |  Size: 340 KiB

View File

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 364 KiB

View File

Before

Width:  |  Height:  |  Size: 365 KiB

After

Width:  |  Height:  |  Size: 365 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -8,6 +8,6 @@ This section consolidates everything platform operators need: deployment guides,
- `photobooth/` — FTP ingest service docs and ops playbooks.
- `media-storage-spec.md` — Upload/archival flow overview.
- `guest-notification-ops.md` — Push notification queue monitoring.
- `queue-workers.md` — Worker container instructions referencing scripts in `/docs/queue-supervisor/`.
- `queue-workers.md` — Worker container instructions referencing scripts in `/scripts/`.
Future additions (e.g., escalations, on-call checklists, Terraform notes) should live here as well so all ops content remains in one location.

View File

@@ -0,0 +1,94 @@
---
title: Backup & Restore / Disaster Recovery
sidebar_label: Backup & DR
---
Dieses Dokument beschreibt, was gesichert werden sollte, wie Backups geprüft werden und wie ein Restore im Notfall abläuft.
## 1. Was muss gesichert werden?
- **Datenbank**
- MySQLDatenbank (alle Schemas/Tables des FotospielBackends).
- Enthält Tenants, Events, FotosMetadaten, JoinTokens, Abrechnungsdaten, Logs (soweit in DB).
- **Medienspeicher**
- HotStorage: Pfade unter `storage/app/private` / `storage/app/public` oder konfigurierten „hot“Disks.
- Archivspeicher: Buckets/Disks, in denen `event_media_assets` mit Status `archived` liegen.
- **Konfiguration**
- `.env` Dateien (ohne sie in Git zu speichern), DokployComposeKonfigurationen, Secrets für externe Dienste.
- Optional: HorizonKonfiguration, MonitoringDashboards.
> TODO: Füge hier konkrete Pfade/BucketNamen und die verwendeten BackupTools (z.B. `mysqldump`, S3Snapshots, DokployBackups) ein.
## 2. Backup-Strategie
- **Datenbank-Backups**
- Frequenz: mindestens täglich (idealerweise alle 46 Stunden für ProduktionsDB).
- Aufbewahrung: z.B. 730 Tage, mit OffSiteKopie.
- Prüfschritte:
- Dump/Backupfile auf Plausibilität (Größe, letzte Änderung).
- Regelmäßige TestRestores in eine StagingDB:
- Beispiel (einfacher Dump auf Host Pfade/Passwörter an Umgebung anpassen):
- `mysqldump -h 127.0.0.1 -u fotospiel -p fotospiel > fotospiel-$(date +%F).sql`
- Restore in temporäre DB (z.B. `fotospiel_restore`) und kurze Stichproben:
- `mysql -h 127.0.0.1 -u fotospiel -p fotospiel_restore < fotospiel-YYYY-MM-DD.sql`
- **Medien-Backups**
- HotStorage:
- Snapshot/IncrementalBackup der StorageVolumes oder S3Buckets.
- Archive:
- Sicherstellen, dass ArchivBackups nicht versehentlich durch LifecyclePolicies gelöscht werden, bevor gesetzliche Retention erfüllt ist.
- **Konfig-Backups**
- `.env` und Secrets nur verschlüsselt speichern (z.B. in einem SecretsManager, nicht in KlartextBackups).
- Dokploy/ComposeKonfiguration versionieren (Git) und zusätzlich sicher exportieren.
## 3. Restore-Szenarien
### 3.1 Einzelner Tenant/Event defekt
1. Reproduzieren, ob der Fehler rein logisch (Datenkonsistenz) oder physisch (Fehlender MedienBlob) ist.
2. **DBRestore (punktuell)**:
- Wenn möglich, nur relevante Tabellenbereiche (z.B. `tenants`, `events`, `photos`, `event_media_assets`, `event_packages`) aus Backup in eine temporäre DB laden.
- Differenzanalyse: welche Daten fehlen/fehlerhaft? Manuell oder via Skript zurückspielen.
3. **Medien-Check**
- Fehlende Dateien im Hot/ArchiveStorage identifizieren (z.B. per `event_media_assets` Pfade + `Storage::disk()->exists`).
- Wenn Dateien im Backup vorhanden, gezielt an den richtigen Pfad zurückkopieren.
> Diese Schritte sollten zuerst in einer StagingUmgebung eingeübt werden, bevor sie in Produktion angewendet werden.
### 3.2 Betriebsweite Störung (DB/Storage Verlust)
1. **DB wiederherstellen**
- Leere Datenbank aufsetzen, letztes konsistentes Backup einspielen.
2. **Storage wiederherstellen**
- HotStorageBackup auf Volumes/Buckets zurückspielen (z.B. DockerVolume `app-storage` oder zugeordneten Bucket).
- ArchivBuckets ggf. unverändert lassen, sofern noch intakt.
3. **App & Queues**
- App mit readonly/maintenanceFlag starten, Queues gestoppt lassen.
- Konsistenzprüfungen (z.B. stichprobenartige Tenants, Events, Medien, Abrechnungsdaten).
4. **Queues wieder freigeben**
- Wenn die wichtigsten Funktionen wieder intakt sind, Queues/Horizon graduell zuschalten.
> TODO: Ergänze konkrete Kommandos (Migrationsstatus prüfen, HealthChecks) und definierte RTO/RPOZiele.
## 4. Tests & DR-Übungen
- Mindestens 12 Mal pro Jahr einen vollständigen Restore in einer separaten Umgebung durchspielen:
- DBBackup einspielen.
- MedienBackups anbinden.
- Eine Handvoll Tenants/Events kompletter durchklicken (Upload, Galerie, AdminFunktionen).
- Ergebnisse im `docs/process/changes/`Ordner dokumentieren (z.B. „DRÜbung 2026Q1“ mit Learnings).
## 5. Verantwortlichkeiten
- **Backup-Ownership**: Wer stellt sicher, dass Backups laufen und testweise wiederhergestellt werden?
- **DR-Ownership**: Wer führt die DRÜbungen durch und wer entscheidet im Ernstfall über Failover/Restore?
Diese Punkte sollten mit konkreten Namen/Rollen befüllt werden, damit im Ernstfall keine Unklarheiten bestehen.
## 6. Ergänzende DR-Playbooks
Spezielle DRSzenarien sind in separaten Runbooks beschrieben:
- `docs/ops/dr-tenant-event-restore.md` Vorgehen bei versehentlich gelöschten oder beschädigten Tenants/Events.
- `docs/ops/dr-storage-issues.md` Vorgehen bei Hot/ArchiveStorageProblemen (voll, hängende Archivierung, fehlende Medien).
Dieses Dokument bleibt die HighLevelÜbersicht für konkrete Fälle solltest du immer auch die entsprechenden Playbooks konsultieren.

133
docs/ops/billing-ops.md Normal file
View File

@@ -0,0 +1,133 @@
---
title: Billing & Zahlungs-Operationen
sidebar_label: Billing-Runbook
---
Dieses Runbook beschreibt, wie mit Zahlungsproblemen, Paddle/RevenueCatWebhooks und PaketInkonsistenzen operativ umzugehen ist.
## 1. Komponentenüberblick
- **Paddle**
- Abwicklung von WebCheckout, Paketen und Subscriptions.
- Webhooks für Käufe, Verlängerungen, Stornos.
- **Fotospiel Backend**
- Modelle wie `Tenant`, `Packages`, `tenant_packages`, `event_packages`.
- Services/Jobs zur PaketZuweisung, LimitBerechnung und Nutzungstracking.
> Details zur Architektur findest du in den PRPKapiteln (Billing/Freemium) sowie in den TODODokumenten unter `docs/process/todo/paddle-migration.md` und `docs/process/todo/paddle-catalog-sync.md`.
## 2. Typische Problemszenarien
- **Webhook kommt nicht an / schlägt fehl**
- Symptom: Paddle zeigt Zahlung „completed“, TenantPaket im Backend bleibt unverändert.
- Checkliste:
- Logs der WebhookRoutes prüfen (Statuscodes, Exceptions).
- Endpoint: `POST /paddle/webhook``PaddleWebhookController::handle()`.
- Controller ruft `CheckoutWebhookService::handlePaddleEvent()` auf.
- WebhookReplay über das Paddle Dashboard auslösen (für einzelne Events).
- QueueStatus prüfen:
- Falls Webhooks über Queues verarbeitet werden, auf `default`/`billing`Queues achten (je nach Konfiguration).
- **Doppelte oder fehlende Abbuchungen**
- Abgleich von ZahlungsproviderDaten (Paddle/RevenueCat) mit internem Ledger.
- Bei doppelten Buchungen: Prozess definieren (Refund via Paddle, Anpassung im Ledger).
- Bei fehlenden Buchungen: ggf. manuelle Paketzuweisung nach erfolgter Zahlung.
- **Pakete/Limits passen nicht zur Realität**
- Tenant meldet: „Paket falsch“, „Galerie schon abgelaufen“ o.Ä.
- Prüfen:
- Aktives Paket (`tenant_packages`, `event_packages`).
- LimitZähler (`used_photos`, `used_events`) und aktuelle Nutzung.
- Letzte relevante Webhooks/Jobs (z.B. vor kurzem migriert?).
## 3. Operative Schritte bei Payment Incidents
1. **Event/Tenant identifizieren**
- IDs und relevante PaketInfos aus DB/Admin UI holen.
2. **Provider-Status prüfen**
- PaddleDashboard: ist die Zahlung dort korrekt verbucht? (Transaktions/AbonnementAnsicht).
3. **Backend-Status prüfen**
- Paketzuweisung und Limits in der DB (Readonly!) inspizieren:
- `checkout_sessions` wurde die Session korrekt auf `completed` gesetzt? (`provider = paddle`, `paddle_transaction_id` gefüllt?)
- `package_purchases` existiert ein Eintrag für Tenant/Package mit erwarteter ProviderReferenz?
- `tenant_packages` stimmt der `active`Status und `expires_at` mit dem erwarteten Abostatus überein?
4. **Entscheidung**
- Automatische Nachverarbeitung via WebhookReplay/JobRetry:
- PaddleEvents erneut senden lassen, ggf. `tests/api/_testing/checkout/sessions/{session}/simulate-paddle` (in TestUmgebungen) nutzen.
- Notfall: manuelle PaketAnpassung (nur mit klar dokumentierter Begründung):
- Paket in `tenant_packages` aktivieren/verlängern und `package_purchases` sauber nachziehen.
5. **Dokumentation**
- Vorgang im Ticket / `docs/process/changes/*` festhalten, falls wiederkehrend.
> TODO: Ergänze konkrete Tabellen-/Modellnamen und die relevanten Jobs/Artisan Commands, sobald Paddle/RevenueCat Migration finalisiert ist.
## 4. Zusammenarbeit mit Finance/Support
- Klar definieren, wer Rückerstattungen freigibt und durchführt.
- Playbook für Support:
- Welche Informationen sie sammeln sollen, bevor sie an Ops eskalieren (TenantID, EventID, PaymentProviderReferenz, Zeitstempel).
- Welche Standardantworten es gibt (z.B. „Zahlung in Prüfung, Paket kurzfristig manuell freigeschaltet“).
## 5. Hinweise zur Implementierung
- **Konfiguration**
- PaddleKeys, WebhookSecrets und FeatureFlags sollten ausschließlich in `.env`/ConfigDateien liegen und niemals im Code/Logs landen.
- Sandbox vs. LiveKeys klar trennen; Ops sollte wissen, welche Umgebung gerade aktiv ist.
- **Sicherheit**
- WebhookSignaturen und Timestamps prüfen; bei verdächtigen Mustern (z.B. ReplayAngriffe) SecurityRunbooks konsultieren.
- Keine sensiblen PaymentDetails in ApplikationsLogs ausgeben.
Diese Sektion ist bewusst generisch gehalten, damit sie auch nach Implementation der finalen BillingArchitektur noch passt. Details zu Tabellen/Jobs sollten ergänzt werden, sobald die PaddleMigration abgeschlossen ist.
## 6. Konkrete Paddle-Flows im System
### 6.1 Checkout-Erstellung
- Marketing-Checkout / API:
- `MarketingController` und `PackageController` nutzen `PaddleCheckoutService::createCheckout()` (`App\Services\Paddle\PaddleCheckoutService`).
- Der Service:
- Stellt sicher, dass ein `paddle_customer_id` für den Tenant existiert (`PaddleCustomerService::ensureCustomerId()`).
- Baut Metadaten (`tenant_id`, `package_id`, optional `checkout_session_id`) für spätere Zuordnung.
- Ruft `POST /checkout/links` im PaddleAPI auf und erhält eine `checkout_url`.
- Ops-Sicht:
- Wenn `paddle_price_id` bei einem Package fehlt, wird kein Checkout erzeugt MarketingUI zeigt entsprechende Fehlertexte (siehe `resources/lang/*/marketing.php`).
- Bei wiederkehrenden „checkout failed“Fehlern die Logs (`PaddleCheckoutService`, Controller) und PackageKonfiguration prüfen.
### 6.2 Webhook-Verarbeitung & Idempotenz
- Endpoint: `POST /paddle/webhook``PaddleWebhookController::handle()`.
- Service: `CheckoutWebhookService` (`App\Services\Checkout\CheckoutWebhookService`):
- Unterscheidet zwischen **TransaktionsEvents** (`transaction.*`) und **SubscriptionEvents** (`subscription.*`).
- Idempotenz:
- Nutzt ein CacheLock (`checkout:webhook:paddle:{transaction_id|session_id}`), um parallele Verarbeitung desselben Events zu verhindern.
- Schreibt Metadaten (`paddle_last_event`, `paddle_status`, `paddle_checkout_id`) in `checkout_sessions.provider_metadata`.
- Ergebnis:
- Bei `transaction.completed`:
- `CheckoutSession` wird als `processing` markiert.
- `CheckoutAssignmentService::finalise()` weist Paket/Tenant zu.
- Session wird auf `completed` gesetzt.
- Bei `transaction.failed` / `transaction.cancelled`:
- Session wird auf `failed` gesetzt, Coupons werden als fehlgeschlagen markiert.
### 6.3 Subscriptions & TenantPackages
- SubscriptionEvents (`subscription.*`) werden ebenfalls von `CheckoutWebhookService` behandelt:
- Tenant wird aus `metadata.tenant_id` oder `paddle_customer_id` ermittelt.
- Package wird über `metadata.package_id` oder `paddle_price_id` aufgelöst.
- `TenantPackage` wird erstellt/aktualisiert (`paddle_subscription_id`, `expires_at`, `active`).
- `Tenant.subscription_status` und `subscription_expires_at` werden gesteuert.
- Ops-Sicht:
- Bei abweichenden Abostatus (z.B. Paddle zeigt „active“, Tenant nicht):
- SubscriptionEvents im PaddleDashboard prüfen.
- Letzte `subscription.*`Events in den Logs, `TenantPackage` und `Tenant`Felder gegenprüfen.
### 6.4 Paket- & Coupon-Synchronisation
- Pakete:
- ArtisanCommand `paddle:sync-packages` (`App\Console\Commands\PaddleSyncPackages`) stößt für ausgewählte oder alle Pakete `SyncPackageToPaddle`/`PullPackageFromPaddle` Jobs an.
- SyncJobs nutzen `PaddleCatalogService`, um Produkte/Preise in Paddle zu erstellen/aktualisieren und `paddle_product_id`/`paddle_price_id` lokal zu pflegen.
- Coupons:
- `SyncCouponToPaddle`Job spiegelt interne CouponKonfiguration in Paddle Discounts (`PaddleDiscountService`).
- Ops-Sicht:
- Bei KatalogAbweichungen `paddle:sync-packages --dry-run` verwenden, um Snapshots zu prüfen, bevor tatsächliche Änderungen gesendet werden.
- Fehlgeschlagene Syncs in den Logs (`Paddle package sync failed`, `Paddle discount sync failed`) beobachten.
Diese Untersektion soll dir als Operator helfen zu verstehen, wie PaddleAktionen im System abgebildet sind und an welchen Stellen du im Fehlerfall ansetzen kannst.

View File

@@ -0,0 +1,90 @@
---
title: DSGVO & Compliance-Operationen
sidebar_label: DSGVO-Operationen
---
Dieses Runbook beschreibt praktische Abläufe für DatenschutzAnfragen, Datenlöschung und Aufbewahrungsfristen.
## 1. Grundprinzipien
- Gäste benötigen kein Konto; die meisten Daten sind Event und Fotobezogen.
- Tenant Admins sind in der Regel Verantwortliche im Sinne der DSGVO, Fotospiel fungiert als Auftragsverarbeiter (je nach Vertragsmodell).
- Rechtsgrundlagen, Impressum und Datenschutzerklärungen werden über die LegalPages im Admin verwaltet dieses Dokument fokussiert sich auf **Betriebsprozesse**.
## 2. Typische Anfragen & Aktionen
- **Auskunftsanfragen**
- Gast möchte wissen, ob Fotos von ihm/ihr gespeichert sind.
- Typischer Ablauf:
- Gast an Tenant verweisen (wenn Veranstalter Ansprechpartner ist).
- Falls Fotospiel direkt handeln muss: Event/FotoIDs anhand bereitgestellter Infos identifizieren (z.B. Link, Screenshot, Zeitfenster).
- Relevante Datensätze in DB (Fotos, Likes, Meldungen) lokalisieren und dokumentieren.
- **Löschanfragen**
- Ein Gast/Tenant bittet um Löschung spezifischer Fotos oder eines ganzen Events.
- Vorgehen:
1. Identität und Berechtigung prüfen (z.B. Tenant Admin, verifizierte Anfrage).
2. Fotos/Ereignisse über Admin UI oder interne Tools löschen/archivieren.
- Sicherstellen, dass `event_media_assets` und ArchivSpeicher ebenfalls bereinigt werden.
3. Prüfen, ob Logs/Audits pseudonymisiert bleiben können, ohne personenbezogene Inhalte.
4. Anfrage und Zeitpunkt dokumentieren (Ticket, internes Log).
- **Datenexport**
- Tenant will einen Export seiner Daten (Events, Medien, Statistiken).
- Nutzung der vorhandenen ExportFunktionen (z.B. CSV/ZIP im Admin) bevorzugen.
- Falls diese nicht ausreichen, manuelle Exporte via Skript/DB mit Datenschutz im Blick (keine unnötigen Felder).
- Beispiel: nur die Felder exportieren, die für den Zweck der Anfrage wirklich notwendig sind (kein DebugLog, keine internen IDs, sofern nicht sinnvoll).
### 2.1 Konkrete Tools & Endpoints
- **Profil-Datenexport (User-Ebene)**
- Controller: `App\Http\Controllers\ProfileDataExportController`.
- UI: Profilbereich der Tenant Admin PWA; Nutzer kann dort einen Export anstoßen.
- Ablauf:
1. Nutzer triggert Export → `ProfileDataExportController::store()` legt einen `DataExport`Eintrag an (`status = pending`) und dispatcht `GenerateDataExport`.
2. Der Job `GenerateDataExport` erstellt ein ZIP mit relevanten Daten und setzt `status = ready`, `path`, ggf. `expires_at`.
3. Nutzer kann die Datei über `ProfileDataExportController::download()` abrufen, solange `isReady()` und nicht `hasExpired()`.
- Ops-Sicht:
- Wenn Exporte „hängen bleiben“ (lange `pending`/`processing`), Queue/Horizon und Logs prüfen, ggf. Job neu anstoßen.
- Für DSGVOExports bevorzugt diesen Pfad nutzen, statt adhoc DBAbfragen.
- **Account-Anonymisierung (User/Tenant-Ebene)**
- Service: `App\Services\Compliance\AccountAnonymizer`.
- Job: `App\Jobs\AnonymizeAccount` nutzt diesen Service typischerweise im Hintergrund.
- Verhalten:
- Löscht/entfernt Medien (`EventMediaAsset`, `Photo`) für einen Tenant.
- Anonymisiert Tenant und UserDaten (setzt neutrale Namen, entfernt Kontaktinfos, sperrt Accounts).
- Ops-Sicht:
- Nur nach klarer Freigabe einsetzen, da Anonymisierung irreversibel ist.
- Vor Einsatz prüfen, ob für den betreffenden Tenant alle vertraglichen Zusagen (z.B. Datenexport) erfüllt sind.
## 3. Retention & automatisierte Löschung
- **Event-bezogene Aufbewahrung**
- StandardRetentionsfristen für Events/Fotos (z.B. X Tage nach Eventende/Archivierung) laut ProduktSpezifikation.
- Jobs/Kommandos, die nach Ablauf Medien archivieren oder löschen (siehe `docs/ops/media-storage-spec.md`).
- **Logs**
- Aufbewahrungsdauer von ApplikationsLogs (z.B. 3090 Tage), Rotation/Anonymisierung.
- **Konfiguration pro Tenant**
- Wenn Tenants eigene Retention wünschen, prüfen ob das UI/ConfigModel dies unterstützt (nicht adhoc in SQL ändern).
## 4. Operative Checkliste bei DSGVO-Fällen
1. Anfrage klassifizieren (Auskunft, Löschung, Export, Sonstiges).
2. Verantwortlichkeit klären (Tenant vs. Fotospiel).
3. Technische Schritte definieren (welche Events/Fotos/Accounts betroffen).
4. Durchführung:
- In Admin UI oder via internen Tools.
- Medien/Metadaten konsistent behandeln (keine „hängenden“ Records).
5. Dokumentation:
- Ticket/E-MailThread mit Datum, Betreff, Maßnahmen.
6. FollowUp:
- Prüfen, ob Runbooks/Automatisierungen angepasst werden sollten (z.B. besserer SelfService für Tenants).
## 5. Verbindung zu Security-Hardening
Das SecurityHardeningEpic (`docs/process/todo/security-hardening-epic.md`) enthält mehrere Workstreams, die DSGVOrelevant sind:
- Signierte AssetURLs statt direkter StorageLinks.
- Verbesserte Token/AuthFlows.
- StorageHealth und ChecksummenVerifizierung.
Wenn dort neue Features produktiv gehen, sollten die Auswirkungen auf DSGVOProzesse in diesem Runbook ergänzt werden.

View File

@@ -67,7 +67,7 @@ If you already have data, skip the seeder or seed only new records.
## 5. Queue & Horizon management
Worker entrypoints live in `docs/queue-supervisor/`. The Compose services mount the same application volume so code stays in sync. Adjust concurrency by scaling services:
Worker entrypoints live in `/scripts/` inside the container (copied from the repositorys `scripts/` folder). The Compose services mount the same application volume so code stays in sync. Adjust concurrency by scaling services:
```bash
docker compose up -d --scale queue=2 --scale media-storage-worker=2

View File

@@ -8,8 +8,8 @@ Dokploy is our self-hosted PaaS for orchestrating the Fotospiel stack (Laravel a
|---------|-------|
| **Laravel App** | Build from this repository. Expose port 8080 (or Dokploy HTTP service). Attach the production `.env`. Health check `/up`. |
| **Scheduler** | Clone the app container; command `php artisan schedule:work`. |
| **Queue workers** | Use `docs/queue-supervisor/queue-worker.sh` scripts (default, media-storage, media-security). Deploy each as a dedicated Dokploy application or Docker service. |
| **Horizon (optional)** | Run `docs/queue-supervisor/horizon.sh` for dashboard + metrics. |
| **Queue workers** | Use the `/scripts/queue-worker.sh` entrypoints (default, media-storage, media-security). Deploy each as a dedicated Dokploy application or Docker service. |
| **Horizon (optional)** | Run `/scripts/horizon.sh` for dashboard + metrics. |
| **Redis / Database** | Use managed offerings or self-host in Dokploy. Configure network access for the app + workers. |
| **vsftpd container** | Expose port 2121 and mount the shared Photobooth volume. |
| **Photobooth Control Service** | Lightweight API (Go/Node/Laravel Octane) that can be redeployed together with vsftpd for ingest controls. |
@@ -72,10 +72,10 @@ Follow these steps for each component:
3. **Queue workers**
- Duplicate the image.
- Commands:
- `docs/queue-supervisor/queue-worker.sh default`
- `docs/queue-supervisor/queue-worker.sh media-storage`
- `docs/queue-supervisor/queue-worker.sh media-security`
- Optionally create a dedicated container for Horizon using `docs/queue-supervisor/horizon.sh`.
- `/var/www/html/scripts/queue-worker.sh default`
- `/var/www/html/scripts/queue-worker.sh media-storage`
- `/var/www/html/scripts/queue-worker.sh media-security`
- Optionally create a dedicated container for Horizon using `/var/www/html/scripts/horizon.sh`.
4. **vsftpd + Photobooth control**
- Nutze deinen bestehenden Docker-Compose-Stack (z.B. `docker-compose.dokploy.yml`) oder dedizierte Compose-Applikationen.

42
docs/ops/diagrams.md Normal file
View File

@@ -0,0 +1,42 @@
---
title: Architekturdiagramme
sidebar_label: Diagramme
---
Diese Seite bündelt einfache Diagramme für zentrale PlattformFlows. Sie sind absichtlich highlevel gehalten und sollen neuen Operatoren einen schnellen Überblick geben.
## 1. MedienPipeline (Mermaid)
```mermaid
flowchart LR
Guest[Guest PWA] -->|Foto upload| API[Laravel API]
API -->|Validierung & DB| DB[(DB: events,\nevent_media_assets)]
API -->|Datei schreiben| HotStorage[(Hot Storage\n/var/www/storage)]
HotStorage --> QueueMedia[Queue: media-storage]
QueueMedia --> WorkerMedia[Worker: media-storage-worker]
WorkerMedia --> Archive[(Archive Storage\nz.B. S3/Wasabi)]
WorkerMedia --> Thumbs[Job: Thumbnails]
Thumbs --> HotStorage
DB --> PublicAPI[Public API]
PublicAPI --> Guest
```
## 2. Checkout & Billing (Mermaid)
```mermaid
flowchart LR
Tenant[Browser Tenant-Admin] -->|Paket wählen| App[Laravel App]
App -->|CheckoutSession anlegen| DB[(DB: checkout_sessions,\n tenant_packages)]
App -->|Redirect| Paddle[Paddle Checkout]
Paddle -->|Zahlung erfolgreich| Webhook[Paddle Webhook Endpoint]
Webhook -->|Event verarbeiten| BillingService[CheckoutWebhookService]
BillingService -->|TenantPackage aktualisieren| DB
DB --> App
App --> Tenant
```

View File

@@ -0,0 +1,74 @@
---
title: DR-Playbook Storage-Probleme (Hot/Archive)
sidebar_label: DR Storage
---
Dieses Playbook beschreibt, wie du vorgehst, wenn es Probleme mit dem MedienStorage gibt z.B. HotStorage voll, Archivierung bleibt hängen oder viele Assets im Status `failed`.
## 1. Symptome & erste Checks
Typische Symptome:
- Gäste können keine Fotos mehr hochladen (Fehlermeldungen im UploadFlow).
- Tenant Admins sehen „fehlende Medien“ oder sehr langsame Galerien.
- `event_media_assets` enthält viele Einträge mit Status `pending` oder `failed`.
- Logs enthalten Hinweise auf fehlgeschlagene Archivierungen oder fehlende Dateien.
Erste Checks:
- StorageUsage der HotVolumes/Buckets prüfen (DockerVolume, S3Dashboard o.ä.).
- `EventMediaAsset`Status stichprobenartig prüfen (`hot`, `archived`, `pending`, `failed`).
- QueueLängen und Fehler in `media-storage` und `media-security` via Horizon und Logs.
## 2. Hot-Storage voll oder kurz vor Limit
1. **Warnungen bestätigen**
- System/ProviderWarnungen (z.B. 90 % voll) bestätigen.
- Prüfen, ob `storage:monitor` oder ähnliche Kommandos bereits Alerts ausgelöst haben.
2. **Sofortmaßnahmen**
- Archivierung priorisieren: sicherstellen, dass `storage:archive-pending` regelmäßig läuft und die `media-storage`Queue abgearbeitet wird.
- Temporäre Limits erhöhen, falls Provider dies erlaubt (z.B. S3Bucket praktisch „unbegrenzt“ vs. lokaler Disk).
3. **Aufräumen**
- Alte Caches/Thumbnails, die problemlos neu generiert werden können, ggf. gezielt löschen.
- Keine unüberlegten `rm -rf` Aktionen auf dem Storage immer mit klarer Strategie arbeiten.
## 3. Archivierung hängt oder schlägt häufig fehl
1. **Queue-Status prüfen**
- `media-storage` QueueLänge, Failed Jobs in Horizon prüfen.
- LogChannel `storage-jobs` nach Fehlermeldungen durchsuchen.
2. **Fehlerbilder auswerten**
- Typische Ursachen:
- Netzwerk/CredentialProbleme beim Zugriff auf den ArchivBucket.
- Zeitüberschreitungen bei sehr großen Medien.
- Inkonsistente `EventMediaAsset`Einträge (Pfad nicht mehr vorhanden, falscher DiskKey).
3. **Abhilfe**
- Netzwerk/Credentials fixen (z.B. S3Keys, Endpoints, Rechte).
- Problematische Assets gezielt in den Logs identifizieren und manuell nachziehen (Kopie auf ArchiveDisk, Status auf `archived` setzen, FehlerFeld leeren).
- Wenn viele Assets betroffen sind, lieber ein dediziertes Skript/Job bauen als adhoc SQL.
## 4. Fehlende oder beschädigte Medien-Dateien
Wenn `EventMediaAsset`Einträge existieren, die zu nicht mehr vorhandenen Dateien zeigen:
1. **Umfang ermitteln**
- Stichproben auf Basis der Fehlerlogs oder per BatchCheck (z.B. ein ArtisanCommand, das `exists()` prüft).
2. **Backup-Sicht**
- Prüfen, ob die Dateien noch im Backup vorhanden sind (Hot/ArchiveBackups).
3. **Wiederherstellung**
- Fehlende Dateien an den erwarteten Pfad im Storage kopieren (Hot oder Archive).
- `EventMediaAsset`Status und Timestamps ggf. aktualisieren (`hot` vs. `archived`).
Wenn keine Backups existieren, bleibt nur, die betroffenen Assets sauber als „nicht mehr verfügbar“ zu kennzeichnen und die Nutzer entsprechend zu informieren.
## 5. Nach einem Storage-Incident
- **Monitoring schärfen**
- Schwellwerte in `storage-monitor` anpassen (Warnung/Kritisch), Alerts für Queues/Storage erweitern.
- **Kapazitätsplanung**
- Erkenntnisse über Medienwachstum nutzen, um frühzeitig auf größere Volumes/Buckets oder häufigere Archivierung umzusteigen.
- **Dokumentation**
- Incident und Maßnahmen in `docs/process/changes/*` dokumentieren.
- Dieses Playbook aktualisieren, wenn neue Muster entdeckt wurden.
Dieses Playbook ist eng mit `docs/ops/media-storage-spec.md` und `docs/ops/monitoring-observability.md` verknüpft. Nutze diese Dokumente für Detailinformationen zu Queues, Thresholds und StorageTargets.

View File

@@ -0,0 +1,97 @@
---
title: DR-Playbook Tenant/Event versehentlich gelöscht
sidebar_label: DR Tenant/Event
---
Dieses Playbook beschreibt, wie du vorgehst, wenn ein Tenant oder Event versehentlich gelöscht oder stark beschädigt wurde. Es baut auf den allgemeinen Hinweisen aus `docs/ops/backup-restore.md` auf.
> Wichtig: Diese Schritte sollten zuerst in einer **Staging-Umgebung** geübt werden. In Produktion nur nach klarer Freigabe und mit sauberer Dokumentation anwenden.
## 1. Schadensbild erfassen
Bevor du irgendetwas wiederherstellst:
- **Was genau ist betroffen?**
- Nur ein Event (z.B. versehentlich im Admin archiviert/gelöscht)?
- Mehrere Events eines Tenants?
- Der komplette Tenant (inkl. Benutzer, Events, Pakete)?
- **Welche Daten fehlen/fehlerhaft?**
- Fehlen nur Metadaten (Events, Fotos, Pakete) oder auch MedienDateien?
- Gibt es noch Spuren im Admin/UI (z.B. leere Übersichten, aber Logs mit Fehlermeldungen)?
- **Zeitfenster eingrenzen**
- Wann wurde der Fehler bemerkt?
- Wann war der Zustand sicher noch korrekt (z.B. vor letztem Deploy / gestern Abend)?
Diese Informationen bestimmen, welches Backup verwendet werden sollte.
## 2. Logische vs. physische Schäden unterscheiden
- **Logischer Schaden**
- Falsche Flags (Status falsch, Event „archiviert“ statt „aktiv“).
- Inkompatible PaketZuweisungen, aber Daten sind noch vorhanden.
- Lösbare Fälle oft ohne Restore durch gezielte Updates / AdminUI.
- **Physischer Schaden**
- Reihen in KernTabellen gelöscht (z.B. `events`, `photos`, `event_media_assets`, `tenants`).
- MedienDateien im Storage gelöscht/überschrieben.
Nur bei physischen Schäden ist ein Restore aus Backup nötig. Logische Schäden sollten möglichst mit minimalinvasiven Korrekturen behoben werden.
## 3. Vorgehen bei einzelnen Events
### 3.1 Datenbank Event-Datensätze identifizieren
1. **Event-IDs ermitteln**
- Aus Logs, alten Links, Metriken oder Backups.
2. **Querverweise prüfen**
- `events` (Basisdaten), `photos`, `event_media_assets`, `event_packages`, ggf. `event_join_tokens`.
3. **Temporäre Restore-DB nutzen**
- Erzeuge eine temporäre Datenbank (z.B. `fotospiel_restore`) und spiele den relevanten BackupDump ein.
- Dort die betroffenen EventDatensätze suchen.
### 3.2 Selektiver Restore von Event-Daten
Empfohlenes Muster:
- In **Restore-DB**:
- Exportiere alle relevanten Zeilen für das Event (z.B. `events`, `photos`, `event_media_assets`) in SQL/CSV.
- In **Produktions-DB**:
- Prüfe, ob IDs kollidieren (z.B. neue Events seit dem Backup).
- Freie IDs und referentielle Integrität beachten; wenn IDs bereits vergeben sind, ist ein reiner Import meist nicht möglich → dann manuelle Rekonstruktion (neues Event + Medien erneut verknüpfen).
> Dieses Playbook beschreibt bewusst kein generisches „SQL-Skript“, weil die tatsächliche Struktur und IDs von der aktuellen Migration abhängen. Ziel ist, die **Vorgehensweise** zu standardisieren, nicht ein unüberlegtes MassenUpdate.
### 3.3 Medien-Dateien
1. In der RestoreUmgebung prüfen, welche Pfade `event_media_assets` für das Event referenzieren.
2. Im BackupStorage nach diesen Pfaden suchen (Hot und ggf. ArchivBucket).
3. Fehlende Dateien in das produktive StorageVolume/Bucket an den erwarteten Pfad kopieren.
Wenn die Medien physisch nicht mehr vorhanden sind, ist nur eine teilweise Rekonstruktion möglich (z.B. Thumbnails ohne Originale) das sollte mit dem Tenant klar kommuniziert werden.
## 4. Vorgehen bei Tenant-weiten Fehlern
Wenn ein kompletter Tenant versehentlich gelöscht wurde (inkl. Benutzer/Events):
1. **Einordnung**
- Handelt es sich um einen isolierten Tenant oder könnten mehrere betroffen sein (z.B. durch fehlerhaftes Skript)?
2. **Restore-Strategie wählen**
- _Variante A: Partial Restore_ nur die Tabellenzeilen zum Tenant aus der BackupDB in die ProduktionsDB zurückführen.
- _Variante B: Backup-Spiegel_ Tenant + zugehörige Medien in eine separate Umgebung wiederherstellen und dem Kunden dort einen temporären Zugang geben.
3. **Risikoabwägung**
- Partial Restore in eine laufende ProduktionsDB trägt höhere Risiken (Kollisionsgefahr mit neuen Daten).
- SpiegelVariante ist operativ aufwändiger, kann aber sicherer sein, wenn viele neue Daten seit dem Backup hinzugekommen sind.
> Welche Variante gewählt wird, sollte von PlatformOps + Produkt gemeinsam entschieden werden.
## 5. Kommunikation & Dokumentation
- **Mit dem betroffenen Tenant**
- Ehrlich kommunizieren, was passiert ist, was wiederherstellbar ist und welches Risiko ein Restore birgt.
- Zeitrahmen und mögliche Einschränkungen klar benennen.
- **Intern**
- Den gesamten Prozess in einem `docs/process/changes/*`Eintrag oder im Ticketing festhalten:
- Was, wann, warum schief ging.
- Welche RestoreSchritte durchgeführt wurden.
- Welche Verbesserungen künftig notwendig sind (z.B. bessere Schutzmechanismen, zusätzliche Bestätigungen beim Löschen).
Dieses Playbook ist bewusst höherlevelig gehalten; spezifische SQL oder ToolSnippets sollten ergänzend in einem internen Notizsystem oder als separate Anhänge gepflegt werden, sobald eure BackupPipelines stabil etabliert sind.

View File

@@ -22,7 +22,7 @@ This runbook explains how to keep the guest notification centre healthy, roll ou
Push deliveries are dispatched on the dedicated `notifications` queue. Ensure one of the queue workers listens to it:
```bash
docs/queue-supervisor/queue-worker.sh default,notifications
/var/www/html/scripts/queue-worker.sh default,notifications
```
If Horizon is in use just add `notifications` to the list of queues for at least one supervisor. Monitor `storage/logs/notifications.log` (channel `notifications`) for transport failures.

View File

@@ -0,0 +1,79 @@
---
id: howto-dsgvo-delete-photo
title: How-to DSGVO-Löschung eines Fotos
sidebar_label: DSGVO Foto löschen
---
Dieses Howto beschreibt den operativen Ablauf, wenn ein Gast verlangt, dass ein konkretes Foto DSGVOkonform gelöscht wird.
## 1. Anfrage & Berechtigung prüfen
Bevor du etwas löschst:
- Handelt der Gast über den Veranstalter (Tenant) oder direkt bei Fotospiel?
- Kann das Foto eindeutig identifiziert werden?
- Am besten via Link zur Galerie / FotoDetailseite.
- Alternativ via Screenshot + EventName + Zeitfenster.
- Ist der Tenant (Veranstalter) einverstanden?
- In der Regel sollte die Entscheidung, ob ein Foto gelöscht wird, beim Tenant liegen, sofern der Vertrag dies vorsieht.
Alle relevanten Informationen und Entscheidungen sollten im Ticket erfasst werden.
## 2. Foto im System identifizieren
1. Über die AdminUI:
- In der Tenant Admin PWA den betroffenen Event öffnen.
- Foto über Moderations/Galerieansicht suchen.
- ID des Fotos notieren (sofern sichtbar) oder den direkten AdminLink verwenden.
2. Falls nötig, über DB/Logs:
- Anhand von Dateinamen/URLs aus Logs (`event_media_assets.path`, `photos.thumbnail_path`) das Foto lokalisieren.
## 3. Löschung über Admin-UI (präferiert)
Wenn die AdminOberfläche eine Delete/HideFunktion bietet:
1. Tenant Admin das Foto über das Moderationsinterface löschen lassen.
2. Sicherstellen, dass:
- Foto nicht mehr in Galerie/Moderationslisten erscheint.
- ShareLinks oder öffentliche Galerien das Foto nicht mehr anzeigen.
3. Falls es trotzdem noch angezeigt wird:
- Caches prüfen (Browser, CDN, ggf. ThumbnailCaches).
## 4. Technischer Löschpfad (Backend)
Falls eine UILöschung nicht ausreicht oder du nachkontrollieren willst:
1. **Datenbank**
- `photos`:
- Prüfen, dass der Eintrag für das Foto gelöscht oder hinreichend anonymisiert wurde.
- `event_media_assets`:
- Alle Einträge, die auf dieses Foto (`photo_id`) zeigen, identifizieren.
- Pfade (`disk`, `path`) notieren.
2. **Storage**
- Für alle relevanten `EventMediaAsset`Einträge:
- Dateien im Hot/ArchiveStorage löschen (Original + Derivate/Thumbnails).
3. **Verknüpfungen**
- Sicherstellen, dass keine weiteren Verweise existieren:
- Likes/Statistiken für dieses Foto (z.B. `photo_likes`) optional mit entfernen, sofern vorhanden.
> Hinweis: Wenn ihr `AccountAnonymizer` auf Tenant/UserEbene verwendet, löscht dieser im Regelfall großflächig Medien. Für Einzelfälle (ein Foto) ist der oben skizzierte Weg geeigneter.
## 5. Dokumentation & Bestätigung
- Im Ticket festhalten:
- Welches Foto (Event, ID/URL).
- Wer die Löschung veranlasst und genehmigt hat.
- Welche Schritte tatsächlich durchgeführt wurden (UI, DB, Storage).
- Tenant/Gast informieren:
- Bestätigung, dass das Foto aus Galerie und Speicher entfernt wurde.
- Hinweis, dass ggf. Browser/CDNCaches eine kurze Zeit nachlaufen können, aber keine neuen Zugriffe mehr möglich sind.
## 6. Präventive Verbesserungen
Wenn dieser Vorgang häufig vorkommt:
- Prüfen, ob die AdminUI einen klareren, selbstbedienbaren Weg zur FotoLöschung bietet.
- Sicherstellen, dass die Dokumentation für Tenant Admins (siehe HelpCenter) erklärt, wie sie Fotos eigenständig löschen und wie sich das auf Gäste auswirkt.
Dieses Howto ergänzt `docs/ops/compliance-dsgvo-ops.md` um einen konkreten Einzelfall. Für komplexere AnonymisierungsSzenarien siehe den Abschnitt zum `AccountAnonymizer`.

View File

@@ -0,0 +1,83 @@
---
id: howto-guest-upload-failing
title: How-to Gäste können nicht hochladen
sidebar_label: Gäste können nicht hochladen
---
Dieses Howto beschreibt, wie du vorgehst, wenn Gäste melden, dass sie keine Fotos mehr hochladen können (Fehler im UploadFlow oder „hängenbleibende“ Uploads).
## 1. Problem eingrenzen
Fragen an den Tenant/Support:
- Betrifft es **alle** Gäste oder nur einzelne?
- Betrifft es **alle** Events oder nur ein bestimmtes Event?
- Welche Fehlermeldung erscheint im GuestFrontend (so genau wie möglich, gerne mit Screenshot)?
- Seit wann tritt das Problem auf? (Zeitfenster)
Diese Informationen bestimmen, ob du in Richtung API/RateLimit, Storage/Queues oder EventKonfiguration schauen musst.
## 2. Basischecks API & App
1. **Public-API Status**
- Teste manuell einen Upload gegen ein TestEvent oder reproduziere das Problem mit dem betroffenen JoinToken.
- Achte auf HTTPStatuscodes im BrowserNetworkTab (4xx vs. 5xx).
2. **App- / Deployment-Status**
- Prüfe in Docker/Dokploy, ob App/Queue/Redis/DBContainer gesund sind.
- Schaue in `storage/logs/laravel.log` nach offensichtlichen Exceptions rund um das gemeldete Zeitfenster.
Wenn die PublicAPI generell 5xx liefert, greift eher das PublicAPIIncidentPlaybook (`docs/ops/deployment/public-api-incident-playbook.md`).
## 3. Queues & Upload-Health
Wenn das Problem hauptsächlich Uploads betrifft (andere Funktionen laufen):
1. **Queue-Längen prüfen**
- In Horizon:
- `media-storage`, `media-security` und ggf. `notifications` QueueLängen ansehen.
- In Logs:
- Warnungen aus `storage:check-upload-queues` oder `storage-jobs` suchen.
2. **Upload-Health-Command**
- Sicherstellen, dass `storage:check-upload-queues` regelmäßig läuft (Cron / Scheduler).
- Manuell ausführen (in der AppContainerShell):
```bash
php artisan storage:check-upload-queues
```
- Ausgaben/Logs prüfen:
- Meldungen zu „stalled“ Uploads, Events mit dauerhaft vielen PendingAssets.
## 4. Storage & Limit-Probleme
1. **Hot-Storage-Füllstand**
- Prüfen, ob das StorageVolume/Bucket nahe an 100 % ist (siehe `docs/ops/dr-storage-issues.md`).
- Wenn ja:
- Archivierung beschleunigen (`storage:archive-pending` verifizieren).
- Kurzfristig Speicher vergrößern oder Caches aufräumen.
2. **Paket-/Limit-Prüfungen**
- Wenn nur bestimmte Events betroffen sind:
- PaketLimits des Events prüfen (z.B. max_photos/max_guests).
- EventStatus (abgelaufen/archiviert?) prüfen.
- Logs können Fehlercodes liefern wie „photo_limit_exceeded“ diese deuten auf bewusst ausgelöste LimitSperren hin, nicht auf technische Fehler.
## 5. Typische Muster & Gegenmaßnahmen
- **Hohe Fehlerrate beim Upload (5xx)**
- Hinweis auf API/BackendProblem:
- Siehe PublicAPIRunbook und AppLogs (Datenbank/RedisFehler, Timeouts).
- **Uploads bleiben „ewig“ auf „wird verarbeitet“**
- Queues laufen nicht oder `media-storage`/`media-security` steckt fest:
- Horizon prüfen, ob WorkerContainer laufen.
- Ggf. Worker neu starten und Failed Jobs analysieren.
- **Nur ein Event betroffen, andere funktionieren**
- Meist Limit oder KonfigThema (Paket voll, Galerie abgelaufen, Event deaktiviert).
- TenantAdminUI prüfen: EventStatus, PaketStatus, Data Lifecycle Einstellungen.
## 6. Kommunikation
- **An Tenant/Support zurückmelden**:
- Was war die Ursache? (z.B. PaketLimit, temporäre Überlastung, StorageKnappheit).
- Was wurde getan? (z.B. Paket angepasst, Queues neu gestartet, Storage erweitert).
- Ob und wie der Tenant/gäste weiteres tun müssen (z.B. Seite neu laden, später erneut probieren).
Für tiefere Ursachen rund um Storage siehe `docs/ops/media-storage-spec.md` und `docs/ops/dr-storage-issues.md`.

View File

@@ -0,0 +1,87 @@
---
id: howto-photobooth-no-photos
title: How-to Photobooth lädt keine Fotos
sidebar_label: Photobooth lädt nichts
---
Dieses Howto beschreibt, wie du vorgehst, wenn ein Tenant meldet, dass von der Photobooth keine Fotos im Event ankommen.
## 1. Problem eingrenzen
Fragen an den Tenant:
- Welcher Event ist betroffen? (EventID oder Titel).
- Wird im TenantAdmin unter „Fotobox-Uploads“ angezeigt, dass die Photobooth aktiviert ist?
- Sieht der PhotoboothOperator offensichtliche Fehler am Gerät (z.B. FTPFehler, Timeout)?
- Seit wann kommt nichts mehr an? (Zeitfenster)
Diese Infos helfen dir, zwischen Konfigurations, FTP oder IngestProblem zu unterscheiden.
## 2. Konfiguration im Admin prüfen
1. Im Tenant-Admin:
- Den betroffenen Event öffnen.
- Prüfen, ob die PhotoboothFunktion für diesen Event aktiviert ist.
2. Wenn Photobooth deaktiviert ist:
- Tenant bitten, sie im UI zu aktivieren (dies triggert die Provisionierung und Credentials).
- Danach erneut testen, ob Uploads ankommen.
## 3. FTP-/Control-Service überprüfen
Siehe auch `docs/ops/photobooth/control_service.md` und `docs/ops/photobooth/ops_playbook.md`.
1. **FTP-Erreichbarkeit**
- Host/Port aus den PhotoboothEinstellungen entnehmen.
- Testverbindung (z.B. über lokales FTPTool oder `nc`/`telnet`) herstellen:
- Port (z.B. 2121) erreichbar?
2. **Credentials validieren**
- Prüfen, ob Username/Passwort im TenantAdmin zu den ControlServiceDaten passen.
- Bei Verdacht auf Fehler:
- Im Admin die Zugangsdaten neu generieren lassen.
- Tenant/PhotoboothTeam informieren, dass sie die neuen Credentials konfigurieren müssen.
## 4. Ingest-Service & Scheduler prüfen
Die Photobooth legt Dateien zunächst in einem ImportPfad ab, der dann vom IngestService verarbeitet wird.
1. **Import-Verzeichnis prüfen**
- Pfad: üblicherweise `storage/app/photobooth/{tenant}/{event}` (siehe `docs/ops/photobooth/README.md`).
- In den Logs kontrollieren, ob neue Dateien dort landen.
2. **Ingest-Command**
- Sicherstellen, dass `photobooth:ingest` regelmäßig läuft (Scheduler/Cron):
```bash
php artisan photobooth:ingest --max-files=100
```
- Optional: für einen konkreten Event:
```bash
php artisan photobooth:ingest --event=EVENT_ID --max-files=50 -vv
```
- Logs auf Hinweise prüfen:
- Fehler beim Lesen der FTPDateien.
- Probleme beim Schreiben in den HotStorage.
3. **Queues**
- Verifizieren, dass relevante Queues laufen (falls Ingest Jobs dispatcht).
## 5. Typische Fehlerbilder & Lösungen
- **FTP erreicht, aber Import-Verzeichnis bleibt leer**
- PhotoboothSoftware schreibt nicht an den erwarteten Pfad → Pfad in der PhotoboothKonfiguration mit den Angaben aus `PHOTOBOOTH_IMPORT_ROOT` abgleichen.
- Evtl. Berechtigungsproblem im FTPContainer (Perms/Ownership).
- **Import-Verzeichnis gefüllt, aber nichts im Event**
- `photobooth:ingest` läuft nicht oder bricht ab:
- Scheduler prüfen (`scheduler`Service in Docker/Dokploy).
- Kommando manuell ausführen und Fehler analysieren.
- **Fotos tauchen mit großer Verzögerung auf**
- Ingest läuft zu selten (Cron/Intervalle zu groß).
- Events haben hohe Medienlast → `--max-files` erhöhen oder Ingest häufiger anstoßen.
## 6. Kommunikation mit dem Tenant
- Sobald Ursache und Fix klar sind:
- Tenant informieren, ob es ein Konfig, Netzwerk oder IngestProblem war.
- Falls nötig, dem PhotoboothTeam neue Credentials/Anweisungen zukommen lassen.
- Falls einige Dateien irreversibel verloren gegangen sind:
- Transparent kommunizieren und ggf. Kulanzlösungen (z.B. Gutschrift) über Finance/Success abstimmen.
Nutze für tiefere Analysen die ausführlicheren Playbooks in `docs/ops/photobooth/ops_playbook.md`.

View File

@@ -0,0 +1,52 @@
---
title: Howto TenantKomplettExport
sidebar_label: Tenant-Komplett-Export
---
Dieses Howto beschreibt, wie du für einen Tenant kurz vor Vertragsende einen möglichst vollständigen DatenExport erstellst.
## 1. Anfrage prüfen
- Schriftliche Anfrage des Tenants (EMail/Ticket).
- Klarer Scope:
- Nur Medien?
- Medien + Metadaten (Events, Gäste, Likes)?
- BillingNachweise (Rechnungen)?
## 2. MedienExport
- Für jeden relevanten Event:
- Prüfen, ob alle UploadJobs durch sind (`event_media_assets` ohne `pending`/`failed`).
- ArchivExport nutzen (sofern vorhanden) oder:
- MedienOrdner pro Event aus dem Storage exportieren.
- Thumbnails optional, Originale Pflicht.
## 3. MetadatenExport
- Events, Gäste, Likes, Kommentare nach Bedarf exportieren:
- Entweder über bestehende ExportFunktion (CSV/JSON).
- Oder über einen einmaligen, internen Report (z.B. `php artisan make:report`ähnlicher Flow, falls vorhanden).
- Output als ZIP mit klarer Ordnerstruktur:
- `media/`
- `metadata/events.csv`
- `metadata/guests.csv`
## 4. Billing-Unterlagen
- Rechnungen / Zahlungsbelege:
- PaddleBelege (Links oder PDFs).
- Interne RechnungsPDFs (falls generiert).
## 5. Nach dem Export
- Export dem Tenant sicher zur Verfügung stellen (z.B. DownloadLink mit Ablaufdatum).
- Dokumentieren:
- Datum des Exports.
- Umfang (welche Tabellen/Events enthalten).
- Speicherort und Aufbewahrungsdauer des ExportBundles.
Siehe auch:
- `docs/ops/compliance-dsgvo-ops.md`
- `docs/ops/backup-restore.md`

View File

@@ -0,0 +1,95 @@
---
id: howto-tenant-package-not-active
title: How-to Zahlung erfolgreich, Paket nicht aktiv
sidebar_label: Zahlung ok, Paket nicht aktiv
---
Dieses Howto beschreibt, wie du vorgehst, wenn ein Tenant meldet: „Zahlung war erfolgreich, aber mein Paket ist nicht aktiv / Galerie bleibt limitiert.“
## 1. Informationen vom Tenant einsammeln
Bevor du nachschaust:
- TenantID oder TenantSlug.
- Betroffenes Paket (Name oder Beschreibung, z.B. „ProPaket 79 €“).
- Zeitpunkt der Zahlung (Datum/Uhrzeit, ggf. Screenshot).
- Ggf. Auszug aus der PaddleBestätigung (ohne vollständige Kartendaten!).
Diese Infos erlauben dir, die korrekte Transaktion sowohl in Paddle als auch im Backend zu finden.
## 2. Paddle-Status prüfen
1. Im PaddleDashboard:
- Suche nach EMail, TenantName oder dem vom Tenant genannten TransaktionsIdentifier.
- Stelle sicher, dass die Zahlung dort als „completed“/„paid“ markiert ist.
2. Notiere:
- PaddleTransactionID und ggf. CheckoutID.
- Status (paid/processing/failed/cancelled).
Wenn Paddle die Zahlung nicht als erfolgreich zeigt, ist dies primär ein Finance/CustomerTopic ggf. mit Customer Support klären, ob eine neue Zahlung oder Klärung mit dem Kunden notwendig ist.
## 3. Backend-Status prüfen
Mit bestätigter Zahlung in Paddle:
1. `checkout_sessions`:
- Suche nach Sessions des Tenants (`tenant_id`) mit dem betroffenen `package_id`:
- Achte auf `status` (erwartet `completed`) und `provider = paddle`.
- Prüfe `provider_metadata` auf `paddle_last_event`, `paddle_status`, `paddle_checkout_id`.
- Wenn du die Session über PaddleMetadaten finden möchtest:
- `paddle_checkout_id` aus dem Webhook/ProviderMetadata oder `transaction_id` verwenden.
2. `package_purchases`:
- Prüfe, ob ein Eintrag für `(tenant_id, package_id)` mit passender ProviderReferenz existiert:
- z.B. `provider = 'paddle'`, `provider_id` = TransactionID.
3. `tenant_packages`:
- Prüfe, ob es einen aktiven Eintrag für `(tenant_id, package_id)` gibt:
- `active = 1`, `expires_at` in der Zukunft.
## 4. Webhook-/Verarbeitungsstatus untersuchen
Wenn `checkout_sessions` noch nicht auf `completed` steht oder `tenant_packages` nicht aktualisiert wurden:
1. Logs prüfen:
- `storage/logs/laravel.log` und ggf. `billing`Channel.
- Suche nach Einträgen von `PaddleWebhookController` / `CheckoutWebhookService` rund um den Zahlungszeitpunkt.
2. Typische Ursachen:
- Webhook nicht zugestellt (Netzwerk/SSL).
- Webhook konnte die Session nicht auflösen (`[CheckoutWebhook] Paddle session not resolved`).
- IdempotenzLock (`Paddle lock busy`) hat dazu geführt, dass Event nur teilweise verarbeitet wurde.
## 5. Korrektur-Schritte
### 5.1 Automatischer Replay (empfohlen)
1. Im PaddleDashboard:
- Den betreffenden `transaction.*`Event finden.
- WebhookReplay auslösen.
2. In den Logs beobachten:
- Ob `CheckoutWebhookService::handlePaddleEvent()` diesmal die Session findet und `CheckoutAssignmentService::finalise()` ausführt.
3. Nochmal `checkout_sessions` und `tenant_packages` prüfen:
- Session sollte auf `completed` stehen, Paket aktiv sein.
### 5.2 Manuelle Korrektur (Notfall)
Nur anwenden, wenn klare Freigabe vorliegt und Paddle die Zahlung eindeutig als erfolgreich listet.
1. `tenant_packages` aktualisieren:
- Entweder neuen Eintrag anlegen oder bestehenden für `(tenant_id, package_id)` so setzen, dass:
- `active = 1`,
- `purchased_at` und `expires_at` zu PaddleDaten passen.
2. `package_purchases` ergänzen:
- Sicherstellen, dass die Zahlung als Zeile mit `provider = 'paddle'`, `provider_id = TransactionID` und passender `price` existiert (für spätere Audits).
3. Konsistenz prüfen:
- Admin UI für Tenant öffnen und prüfen, ob Limits/Paketstatus jetzt korrekt angezeigt werden.
4. Dokumentation:
- Den Vorgang im Ticket oder in `docs/process/changes/*` (falls wiederkehrend) dokumentieren.
## 6. Kommunikation mit dem Tenant
- Sobald der BackendStatus korrigiert ist:
- Kurz bestätigen, dass das Paket aktiv ist und welche Auswirkungen das hat (z.B. neue Limits, verlängerte Galerie).
- Falls Paddle die Zahlung nicht als erfolgreich führt:
- Ehrlich kommunizieren, dass laut Zahlungsprovider noch keine endgültige Zahlung vorliegt und welche Optionen es gibt (z.B. neue Zahlung, Klärung mit Bank/Kreditkarte).
Dieses Howto sollte dem Support/OnCall helfen, den gängigsten BillingFehlerfall strukturiert abzuarbeiten. Für tiefere Ursachenanalysen siehe `docs/ops/billing-ops.md`.

View File

@@ -0,0 +1,79 @@
---
title: Major Incidents & Eskalation
sidebar_label: Major Incidents
---
Diese Seite beschreibt, wie du bei größeren Störungen (SEV1/SEV2) vorgehst. Sie ergänzt die spezifischen Runbooks (Public API, MedienPipeline, Photobooth) um einen einheitlichen Rahmen.
## 1. Incident-Klassifikation
- **SEV1 (kritisch)**
- Gäste können nicht mehr hochladen ODER keine Events/Galerien mehr öffnen.
- Tenant Admins können sich nicht einloggen oder keine Kernaktionen ausführen (Events verwalten, Medien moderieren).
- Datenverlust oder potenzieller Datenverlust (z.B. Löschjob auf falscher StorageEbene).
- **SEV2 (hoch)**
- Teilweise Degradation (z.B. PhotoboothUploads hängen, PublicAPI stark verlangsamt, eine Region betroffen).
- Kritische BackgroundJobs (Archivierung, AV/EXIFScans, ZahlungsWebhooks) stauen sich, ohne dass Gäste sofort komplett blockiert sind.
- **SEV3 (mittel)**
- Einzelne Features gestört (NotificationCenter, JoinTokenAnalytics, einzelne AdminViews).
- Workaround möglich (z.B. manuelle Nacharbeit durch Support).
> Wichtig: Jede Störung, die einen zahlenden Eventkunden am Tag des Events blockiert, sollte mindestens als SEV2, ggf. als SEV1 eingeordnet werden.
## 2. Erstmaßnahmen (Triage)
1. **Scope bestimmen**
- Welche Benutzer sind betroffen? (Alle Gäste, einzelne Tenants, nur Photobooth, nur Admins?)
- Betrifft es nur eine Umgebung (staging vs. production)?
2. **Schnell-Checks**
- Status von App, Queue, Redis, DB (Docker/DokployÜbersicht prüfen).
- Horizon/Queues: sind relevante Queues leer, wachsend, „stuck“? Gibt es viele Failed Jobs?
- Logs für relevante Kanäle: `storage/logs/laravel.log`, spezielle Channels wie `storage-jobs`, `notifications`, `billing`, Nginx/ProxyLogs.
- Monitoring: externe UptimeChecks / Dashboards (z.B. PublicAPI Latenz, ErrorRate).
3. **Einordnung & Eskalation**
- SEV1/2: OnCall informieren (Pager/Chat), IncidentKanal im Teamchat eröffnen.
- SEV3: Im IssueTracker erfassen, ggf. gebündelt mit anderen Findings.
Nutze bei PublicAPIProblems zusätzlich das `docs/ops/deployment/public-api-incident-playbook.md`.
## 3. Standard-Runbooks nach Bereich
- **Public API / Gast-Zugriff**
- Siehe `docs/ops/deployment/public-api-incident-playbook.md`.
- Typische Auslöser: Peaks, Abuse, externe Integrationen, Ratenlimits.
- **Medien-Pipeline / Uploads**
- Siehe `docs/ops/media-storage-spec.md` und `docs/ops/guest-notification-ops.md`.
- Fälle: Uploads bleiben im Pending, Archivjobs laufen nicht, Speicherkapazität erreicht, Gäste bekommen „Uploads hängen noch…“.
- **Photobooth**
- Siehe `docs/ops/photobooth/ops_playbook.md`.
- Fälle: FTP nicht erreichbar, Ingest nicht laufend, falsche Credentials, SecurityVorfälle.
- **Abrechnung & Billing**
- Siehe `docs/ops/billing-ops.md`.
- Fälle: Paddle/RevenueCatWebhookFehler, falsche PaketZustände, doppelte/fehlende Buchungen.
Dieses Dokument verweist immer nur auf die jeweils tieferen Runbooks bei konkreten Problemen gehst du dort in die Details.
## 4. Kommunikation
- **Intern (Team)**
- Eröffne einen dedizierten IncidentThread im Chat (mit Zeitstempel, SEVLevel, Kurzbeschreibung).
- Halte dort Statusupdates fest (z.B. „17:05 UploadQueue entstaut, weitere Beobachtung 30 min“).
- Notiere bewusst Entscheidungen (z.B. „19:10 Feature X temporär deaktiviert“, „19:25 Rollback auf vorheriges Release“).
- **Extern (Kunden)**
- Ab SEV2: Überlege einen kurzen Statushinweis (StatusSeite oder manuelle Kommunikation an direkt betroffene Tenants).
- Bei Incidents während Events: Koordiniere mit Success/Support, um proaktiv auf Tenant Admins zuzugehen.
> TODO: Falls du eine StatusSeite oder automatisierte EMails hast, dokumentiere hier, wie und wann sie ausgelöst werden.
## 5. Nachbereitung (Postmortem)
Nach einem SEV1/2 Incident:
1. **Fakten sammeln** (Timeline, betroffene Tenants/Events, konkrete Auswirkungen).
2. **Ursache** (Root Cause) möglichst präzise identifizieren auch dann, wenn direkt „nur“ Symptome gefixt wurden.
3. **Kurzfristige Maßnahmen** (Hotfixes, KonfigAnpassungen, zusätzliche Checks).
4. **Langfristige Maßnahmen** sollten als Epics/Tasks in `docs/process/todo/*` bzw. `docs/process/changes/*` landen (inkl. Link zum Incident).
5. **Dokumentation aktualisieren**
- Relevante Runbooks (dieses Dokument, PublicAPIRunbook, StorageSpec, BillingOps, etc.) mit neuen Learnings ergänzen.
Ziel ist, dass die TimetoDetect und TimetoResolve für ähnliche Probleme in Zukunft sinkt.

View File

@@ -33,7 +33,7 @@ This document explains how customer photo uploads move through the Fotospiel pla
| Component | Role |
| --- | --- |
| `app` (Laravel FPM) | Accepts uploads, writes to the hot disk, and records metadata. |
| `media-storage-worker` | Runs `/docs/queue-supervisor/queue-worker.sh media-storage`; consumes archival/restoration jobs and copies data between disks. Shares the same `app-code` volume so it sees `/var/www/html/storage`. |
| `media-storage-worker` | Runs `/scripts/queue-worker.sh media-storage`; consumes archival/restoration jobs and copies data between disks. Shares the same `app-code` volume so it sees `/var/www/html/storage`. |
| `queue` workers | Default queue consumers for non-storage background jobs. |
| `media-security-worker` | Processes `ProcessPhotoSecurityScan` jobs (antivirus + EXIF scrub). |
| `scheduler` | Runs `php artisan schedule:work`, triggering `storage:archive-pending`, `storage:monitor`, queue health checks, etc. |
@@ -92,7 +92,7 @@ This document explains how customer photo uploads move through the Fotospiel pla
## Related Documentation
- `docs/prp/10-storage-media-pipeline.md` — canonical architecture diagram for storage tiers.
- `docs/ops/queue-workers.md` — how to run `media-storage` and `media-security` workers (scripts in `/docs/queue-supervisor/`).
- `docs/ops/queue-workers.md` — how to run `media-storage` and `media-security` workers (scripts live in `/scripts/`).
- `docs/ops/deployment/docker.md` / `docs/ops/deployment/dokploy.md` — container topology and volumes.
- `config/security.php`, `config/storage-monitor.php`, and `config/filesystems.php` for runtime knobs.

View File

@@ -0,0 +1,146 @@
---
title: Monitoring & Observability
sidebar_label: Monitoring
---
Dieses Dokument sammelt die wichtigsten MonitoringPunkte der Plattform und soll helfen, die richtigen Dashboards und Alerts aufzubauen.
## 1. Was sollte überwacht werden?
- **Verfügbarkeit**
- HTTPChecks auf zentrale Endpunkte (Landing, JoinTokenFlows, Guest Upload, Tenant Admin Login).
- PublicAPIChecks (`/api/v1/events/{token}`, Galerie, UploadEndpoints).
- **Queues**
- Länge und Durchsatz der Queues `default`, `media-storage`, `media-security`, `notifications`.
- Age/TimeinQueue, Anzahl der Failed Jobs.
- **Storage**
- Füllstand der HotStorageVolumes/Buckets.
- Anzahlen/Status in `event_media_assets` (z.B. viele `pending` oder `failed`).
- **Fehler-Raten**
- HTTP 5xx/4xx spitzenweise, gruppiert nach Route/Service.
- ApplikationsLogs mit Error/WarningLevel.
- **Billing & Webhooks**
- Fehlgeschlagene Paddle/RevenueCatWebhooks.
- Differenz zwischen erwarteten und verarbeiteten Zahlungen (optional).
## 2. Werkzeuge & Quellen
- **Horizon**
- LiveÜberblick über LaravelQueues.
- Alerts, wenn eine Queue zu lange Backlog aufbaut.
- **Docker/Dokploy**
- ContainerHealth (RestartLoops, Ressourcennutzung).
- ServiceHealthchecks.
- **Logs**
- LaravelLogs (`storage/logs/*.log`), ggf. via Promtail/Loki oder ELK zentralisiert.
- Spezifische Channels (z.B. `storage-jobs`, `notifications`, `billing`).
- **Metriken**
- Falls vorhanden: Prometheus/GrafanaDashboards für App/DB/RedisMetriken.
> TODO: Wenn konkrete Dashboards in Grafana o.Ä. existieren, füge hier Screenshots/Links und eine kurze Erklärung der Panels ein.
## 3. Alarmierung & Schwellenwerte
Konkrete Schwellenwerte hängen von Traffic und Infrastruktur ab, aber folgende Muster haben sich bewährt:
- **Queues**
- `default`:
- Warnung: > 100 Jobs oder ältester Job > 5 Minuten.
- Kritisch: > 300 Jobs oder ältester Job > 15 Minuten.
- `media-storage`:
- Warnung: > 200 Jobs oder ältester Job > 10 Minuten.
- Kritisch: > 500 Jobs oder ältester Job > 30 Minuten.
- `media-security`:
- Warnung: > 50 Jobs oder ältester Job > 5 Minuten.
- Kritisch: > 150 Jobs oder ältester Job > 15 Minuten.
- `notifications`:
- Warnung: > 100 Jobs dauerhaft im Backlog.
- Kritisch: wenn die Queue dauerhaft wächst, während Events live laufen.
- **Uploads**
- Fehlerquote bei UploadEndpoints:
- Warnung: 25 % Fehler (HTTP 4xx/5xx) über 5minütiges Fenster.
- Kritisch: > 510 % Fehler in 5 Minuten.
- Anzahl „hängender“ Uploads:
- Warnung, wenn `storage:check-upload-queues` für denselben Event wiederholt Alarm schlägt (z.B. mehr als 5 benachrichtigte Events in 10 Minuten).
- **Public API**
- Latenz für `GET /api/v1/events/{token}` und `/photos`:
- Warnung: P95 > 500 ms über 5 Minuten.
- Kritisch: P95 > 12 s über 5 Minuten.
- Fehlerraten für diese Endpoints:
- Warnung: > 2 % 5xx über 5 Minuten.
- Kritisch: > 5 % 5xx über 5 Minuten.
- **Billing**
- Failed Webhooks:
- Warnung: mehr als N (z.B. 510) fehlgeschlagene Webhooks pro 10 Minuten.
- Kritisch: schneller Anstieg oder > 20 % Fehleranteil.
- Differenz zwischen erwarteten und verarbeiteten Zahlungen:
- Regelmäßige Reports (z.B. täglich) statt harter Alerts, aber auffällige Abweichungen sollten ein Incident auslösen.
## 4. Betriebliche Nutzung
- **Daily Checks**
- Horizon QueueDashboard kurz prüfen.
- Logs auf neue Fehler/Warnmuster scannen.
- **Bei Incidents**
- MonitoringDaten helfen, Ursache und zeitlichen Verlauf zu rekonstruieren (siehe `docs/ops/incidents-major.md`).
## 5. Zusammenspiel mit bestehenden Kommandos
Einige ArtisanKommandos sind explizit für Monitoring/Health gedacht. Sie sollten in Cron/Scheduler oder externe Checks integriert werden:
- `storage:monitor` (falls vorhanden)
- Aggregiert StorageAuslastung und QueueHealth basierend auf `config/storage-monitor.php`.
- Kann Alerts per Mail/Log triggern, wenn Schwellwerte überschritten werden.
- `storage:check-upload-queues`
- Überprüft, ob Uploadbezogene Queues im erwarteten Rahmen liegen und triggert GastAlerts bei Problemen (siehe `docs/ops/guest-notification-ops.md`).
- `storage:archive-pending`
- Kein klassisches MonitoringKommando, aber relevant, um zu prüfen, ob Archivierungsjobs hinterherhinken (z.B. viele alte `hot`Assets).
Diese Kommandos sind kein Ersatz für echtes Monitoring, liefern aber wertvolle Signale, die in Dashboards und Alerts einfließen können.
## 6. Beispiele für Metrik- und Alert-Definitionen
Nachfolgend beispielhafte Formulierungen, wie Alerts unabhängig vom verwendeten MonitoringSystem aussehen könnten.
### 6.1 Queue-Backlog Alert (Pseudocode)
**Ziel**: Meldung, wenn `media-storage` zu lange Backlog aufbaut.
- Bedingung:
- `queue_length("media-storage") > 500` **OR**
- `oldest_job_age("media-storage") > 30min`
- Dauer:
- 2 aufeinanderfolgende Messintervalle (z.B. 2×5 Minuten).
- Aktion:
- Alarm an OnCall + Hinweis auf `docs/ops/media-storage-spec.md` und `docs/ops/dr-storage-issues.md`.
### 6.2 Upload-Error-Rate Alert
**Ziel**: UploadProbleme für Gäste früh erkennen.
- Bedingung:
- Anteil `5xx` oder „applikationsspezifische Fehlercodes“ bei `POST /api/v1/events/*/upload` > 5 % in 5 Minuten.
- Aktion:
- Alarm an OnCall, Link zum PublicAPIIncidentPlaybook und StorageRunbook.
### 6.3 Public-API-Latenz Alert
**Ziel**: Langsame Galerien / TokenAufrufe frühzeitig sehen.
- Bedingung:
- `P95(latency(GET /api/v1/events/*)) > 1000ms` über 5 Minuten.
- Aktion:
- Alarm an OnCall, eventuell automatische Skalierung oder Untersuchung (DB/RedisLast).
### 6.4 Billing-Webhook Alert
**Ziel**: Fehler bei Paddle/RevenueCatWebhookVerarbeitung erkennen.
- Bedingung:
- Mehr als 10 fehlgeschlagene WebhookVerarbeitungen innerhalb von 10 Minuten, oder Verhältnis `failed/success` > 0,2.
- Aktion:
- Alarm an OnCall + Finance/BillingVerantwortliche, Verweis auf `docs/ops/billing-ops.md`.
Diese Beispiele sollen helfen, konkrete Regeln in eurem MonitoringTool zu definieren. Die genauen Zahlen sollten anhand realer TrafficMuster feinjustiert werden.
Dieses Dokument ist bewusst technologieagnostisch formuliert die konkrete Implementierung (Prometheus, Grafana, Loki, ELK, SaaSMonitoring) sollte hier nachgezogen und mit Beispielen ergänzt werden.

View File

@@ -0,0 +1,48 @@
---
title: OnCall Cheat Sheet
sidebar_label: OnCall Spickzettel
---
Dieser Spickzettel ist für OnCallPersonen gedacht, die im Incident schnell handeln müssen. Er konzentriert sich bewusst auf die wichtigsten Kommandos, Dashboards und Checks.
## 1. Top10 Kommandos
- AppContainer Logs (Laravel / Horizon):
- `docker compose logs -f app`
- `docker compose logs -f horizon`
- QueueStatus:
- `php artisan queue:failed`
- `php artisan horizon:status`
- StorageHealth:
- `php artisan storage:monitor`
- `php artisan storage:check-upload-queues`
- DatenbankChecks (Beispiele):
- `php artisan tinker` → gezielte Queries zu `events`, `event_media_assets`, `checkout_sessions`.
## 2. Erstdiagnose bei „Nichts geht mehr“
- Statusseite / Monitoring prüfen (HTTPStatus, FehlerRate, QueueLänge).
- `docker compose ps` → welche Services sind „unhealthy“ oder down?
- Logs der auffälligen Services anschauen (App, Queue, DB, Nginx).
- Kurz festhalten:
- Wann trat das Problem auf?
- Betrifft es **alle** Tenants oder einzelne?
- Nur GuestPWA, nur TenantAdmin oder beides?
## 3. Wichtigste Dashboards (Beispiele)
- APIFehlerRate (5xx, 4xx für Public API).
- QueueBacklog (`default`, `media-storage`, `media-security`, `notifications`).
- ResponseTime Guest/TenantPWA.
- PaddleWebhookFehler (falls im Monitoring abgebildet).
> Ergänze hier konkrete Links zu euren Grafana/DatadogDashboards, sobald diese stabil sind.
## 4. Wann eskalieren?
- SEV1: Plattform weitgehend nicht nutzbar (> 15 Minuten Ausfall, viele Tenants betroffen).
- SEV2: Kritische Kernfunktion (Uploads, Logins, Zahlungen) länger als 30 Minuten gestört.
- SEV3: Einzelne Tenants oder Funktionen, Workaround vorhanden.
Siehe auch `docs/ops/incidents-major.md` für detaillierte SEVDefinitionen und Kommunikationsregeln.

126
docs/ops/oncall-roles.md Normal file
View File

@@ -0,0 +1,126 @@
---
title: Rollen & On-Call-Handbuch
sidebar_label: Rollen & On-Call
---
Dieses Dokument beschreibt, **wer** im Betrieb wofür zuständig ist und **wie** OnCallBereitschaft organisiert wird. Es ergänzt die technischen Runbooks um eine klare Verantwortungsebene.
> Hinweis: Konkrete Namen/Kontaktdaten sollten nicht in Git stehen, sondern getrennt (z.B. in einem internen Adressbuch oder PasswortSafe). Dieses Dokument definiert Rollen und Prozesse.
## 1. Rollenübersicht
### 1.1 Platform Ops
- Verantwortlich für:
- Infrastruktur (Docker/DokployStacks, Netzwerke, TLS, Backups).
- Technische Verfügbarkeit der Services (App, Queues, DB, Redis, Storage).
- Umsetzung und Pflege der Runbooks unter `docs/ops/`.
- Typische Aufgaben:
- Deployments koordinieren (`docker-compose`, Dokploy, Migrations).
- Monitoring/Alerting pflegen (`ops/monitoring-observability.md`).
- IncidentResponse bei SEV1/SEV2 (`ops/incidents-major.md`).
### 1.2 On-Call Engineer
- Rolle, die im wechselnden Turnus (z.B. wöchentlich) OnCall ist.
- Verantwortlich für:
- Reaktion auf laufende Alerts (Monitoring, Pager, ChatBots).
- Erstes Triage nach `ops/incidents-major.md`.
- Eskalation an weitere Rollen (z.B. Platform Ops, Produkt, Security).
- Voraussetzungen:
- Zugriff auf ProduktionsLogs, MonitoringDashboards, Dokploy/Horizon.
- Vertraut mit den wichtigsten Runbooks (PublicAPI, Storage, Photobooth, Billing).
### 1.3 Support / Customer Success
- Verantwortlich für:
- Kontakt mit Tenants (EMail/Telefon/Chat).
- Übersetzung technischer Probleme in Kundensprache.
- Sammeln aller relevanten Informationen, bevor an OnCall/Platform Ops eskaliert wird.
- Typische Aufgaben:
- Tickets aus dem HelpSystem triagieren.
- Proaktive Kommunikation bei Events („Wir haben ein UploadProblem identifiziert, wir arbeiten daran“).
### 1.4 Produkt / Engineering Leads
- Verantwortlich für:
- Entscheidungen bei FeatureFlags, Rollbacks, HotfixReleases.
- Priorisierung langfristiger Maßnahmen nach Incidents (`docs/process/roadmap.md`, `docs/process/todo/*`).
- Typische Aufgaben:
- Teilnahme an Postmortems.
- Freigabe von riskanteren Änderungen (z.B. große Migrations).
## 2. On-Call-Modell
### 2.1 Bereitschaftszeiten
Empfohlene Einteilung (anpassbar an dein Team):
- **Bürozeiten (z.B. 09:0017:00)**
- OnCall ist die jeweils zuständige PlatformOpsPerson des Tages.
- Reaktionsziel: 15 Minuten bei SEV1/2, 60 Minuten bei SEV3.
- **Außerhalb der Bürozeiten / Event-Spitzen**
- Optional: Rotierender OnCallDienst mit Rufbereitschaft.
- Reaktionsziel: nach individueller Vereinbarung (z.B. 3060 Minuten bei SEV1).
> Wenn ihr keinen formalen 24/7Dienst habt, sollte klar dokumentiert sein, **wann** keine garantierte Reaktionszeit besteht (z.B. nachts/wochenends) und wie das Kunden gegenüber kommuniziert wird.
### 2.2 Rotation & Übergabe
- OnCallRotation (z.B. wöchentlich) im Teamtool (Kalender/IssueTracker) pflegen.
- Vor Start einer Schicht:
- Offene Incidents und bekannte Problemzonen durchgehen.
- Sicherstellen, dass Aufrufwege funktionieren (Chat, Telefon, Pager).
- Nach Schicht:
- Kurze Übergabe an nächste OnCallPerson (offene Themen, laufende Beobachtungen).
## 3. Eskalationspfad bei Incidents
### 3.1 Standard-Eskalation (SEV-2/3)
1. OnCall nimmt Alert entgegen, prüft grob die Lage (`ops/incidents-major.md` → Triage).
2. Wenn Problem lösbar erscheint:
- Runbooks anwenden (z.B. PublicAPIPlaybook, MedienRunbook, PhotoboothOps).
- Kundenkommunikation via Support abstimmen.
3. Wenn unklar oder größer:
- PlatformOps bzw. Engineering Lead im Chat markieren.
- IncidentThread mit Statusupdates führen.
### 3.2 SEV-1 (kritisch)
1. OnCall ruft sofort **PlatformOps** und ggf. **ProduktLead** in den IncidentThread.
2. Falls nötig, mit Produkt die Entscheidung für:
- Rollback auf letztes Release,
- temporäre Abschaltung einzelner Features (FeatureFlags),
- Aktivierung einer MaintenanceSeite
treffen.
3. Support/Success informieren betroffene Tenants mit kurzem Status und ETA (auch wenn ETA noch grob ist).
## 4. Tools & Zugänge
Für OnCall/PlatformOps sollten mindestens folgende Zugänge eingerichtet und getestet sein:
- **Dokploy / Docker-Orchestrierung**
- Zugriff auf ComposeStacks, Logs, HealthChecks.
- **Horizon / Queue-Monitoring**
- Zugriff auf `/horizon` (nur für SuperAdmins).
- **Logs**
- Zentralisierte Logs (Loki/ELK) oder SSHZugriff zur Maschine mit `storage/logs`.
- **Monitoring/Alerts**
- Zugang zu Uptime/MonitoringService (StatusDashboard, AlertKonfiguration).
> Stelle sicher, dass OnCallPersonen ausprobiert haben, ob sie diese Tools tatsächlich erreichen können (VPN, 2FA, etc.), bevor eine Schicht beginnt.
## 5. Verbindung zu den Runbooks
Bei einem Incident sollte die OnCallPerson immer vom **Betriebshandbuch** aus denken:
- Einstieg über `docs/ops/operations-manual.md` (DocusaurusStartseite).
- Je nach Symptome:
- **API-/Frontend-Probleme** → PublicAPIPlaybook (`ops/deployment/public-api-incident-playbook.md`), ggf. Marketing/GuestPWASpezifikationen in `docs/prp/` (in PRP, nicht im OpsBereich).
- **Upload/Storage-Probleme**`ops/media-storage-spec.md`, `ops/guest-notification-ops.md`.
- **Photobooth**`ops/photobooth/ops_playbook.md`.
- **Abrechnung**`ops/billing-ops.md`.
- **DSGVO-Fälle**`ops/compliance-dsgvo-ops.md`.
Dieses Dokument soll nicht alle technischen Details wiederholen, sondern sicherstellen, dass immer klar ist, **wer** reagiert und **welches** Runbook als nächstes geöffnet werden sollte.

View File

@@ -0,0 +1,131 @@
---
title: Betriebshandbuch & Ops-Startseite
sidebar_label: Betriebshandbuch
slug: /
---
Willkommen im Betriebshandbuch von Fotospiel. Dieses Dokument ist der Einstiegspunkt für alle, die die Plattform betreiben: InfrastrukturOps, OnCall, Support mit erweiterten Rechten und ProduktOwner, die Auswirkungen von Änderungen verstehen möchten.
Ziel ist, dass du von hier aus schnell zu den relevanten Runbooks und Referenzen springen kannst.
## 1. Systemübersicht & Verantwortlichkeiten
- **Rollen & Verantwortlichkeiten**
- Wer ist für welche Ebene zuständig? (AppVerfügbarkeit, Infrastruktur, Sicherheit, Abrechnung, Support.)
- Empfehlung: definiere mindestens _OnCall_, _PlattformOps_ und _Support (2nd Level)_ als feste Rollen diese Seite ist für alle drei.
- **Systemlandschaft (HighLevel)**
- Laravel App + Nginx + Redis + MySQL.
- AsyncPipeline: Queues (`default`, `media-storage`, `media-security`, `notifications`) und Horizon.
- Satelliten: PhotoboothFTP + ControlService, DocsSite (`/internal-docs`), Monitoring/Dokploy.
- Externe Dienste: Paddle (Billing), RevenueCat (MobileAbos), EMail Provider, Logging/Monitoring (Loki/Grafana o.ä.).
> TODO: Ergänze ein Architekturdiagramm aus Sicht des Betriebs (z.B. als PNG oder PlantUML) und verlinke es hier.
## 2. Deployments & Infrastruktur
Diese Kapitel erklären, wie die Plattform in Docker/Dokploy betrieben wird.
- **Docker-Deployment (ComposeStack)**
- `docs/ops/deployment/docker.md` Referenz für `docker-compose.yml`, Services, Volumes, Migrations und SchedulerSetup.
- **Dokploy-Deployment (PaaS)**
- `docs/ops/deployment/dokploy.md` Wie die gleichen Services als DokployComposeStacks betrieben werden, inkl. SuperAdminIntegration.
- **Join-Token-Analytics & Public API**
- `docs/ops/deployment/join-token-analytics.md` Konfiguration der AnalyticsPfade für JoinTokens.
- `docs/ops/deployment/public-api-incident-playbook.md` Runbook für PublicAPIStörungen (RateLimits, Abuse, Outages).
- **Lokale Podman/Dev-URLs**
- `docs/ops/deployment/lokale-podman-adressen.md` Übersicht über lokale Services/Ports bei PodmanSetups.
Fragen zur Infrastruktur (Netzwerk, TLS, DNS, Backups) sollten immer zuerst gegen diese Dokumente geprüft werden.
## 3. Queues, Storage & Medien-Pipeline
Fotos sind das Herz des Produkts entsprechend wichtig ist ein klarer Blick auf die MedienPipeline.
- **Queues & Worker**
- `docs/ops/queue-workers.md` Wie die WorkerContainer (`queue`, `media-storage-worker`, `media-security-worker`, `notifications`) gestartet, skaliert und überwacht werden.
- **Media Storage & Archivierung**
- `docs/ops/media-storage-spec.md` Detaillierte Beschreibung, wie Uploads in den „hot“Storage laufen, wie `event_media_assets` gepflegt werden und wie ArchiveJobs funktionieren.
- **Upload-Gesundheit & Notifications**
- `docs/ops/guest-notification-ops.md` Runbook für das NotificationCenter, PushRegistrierung und UploadHealthAlerts.
> TODO: Ergänze ein zentrales „Storage & Queues Monitoring“-Kapitel mit konkreten Schwellenwerten und Alarmierung (z.B. Einbindung von Horizon, RedisMonitoring, Log-Channels).
## 4. Photobooth-Pipeline
Die PhotoboothIntegration hat eigene Betriebsanforderungen:
- `docs/ops/photobooth/README.md` Überblick über PhotoboothSetup und Datenfluss.
- `docs/ops/photobooth/control_service.md` SteuerAPI (UserProvisionierung, Credentials, RateLimits).
- `docs/ops/photobooth/ops_playbook.md` Operatives Playbook für Aktivierung, Fehleranalyse und IncidentResponse rund um PhotoboothUploads.
> Prüfe vor großen Events mit gebuchten Photobooths diese Playbooks und stelle sicher, dass Volumes, Credentials und Scheduler korrekt konfiguriert sind.
## 5. Störungs- & Incident-Runbooks
Die folgenden Dokumente sind deine erste Anlaufstelle im IncidentFall:
- **Major Incidents & Eskalation**
- `docs/ops/incidents-major.md` genereller Rahmen (SEVLevels, Triage, Kommunikation, Postmortems) und Verweise auf die spezifischen Runbooks unten.
- **Public API Störungen**
- `docs/ops/deployment/public-api-incident-playbook.md` SchrittfürSchrittPlan bei Missbrauch, Fehlerspitzen oder Ausfällen der öffentlichen APIs.
- **Upload-/Medien-Probleme**
- `docs/ops/media-storage-spec.md` Referenz, welche Queues/Jobs beteiligt sind und wie man Fehlerzustände erkennt (z.B. lange „pending“-Assets, gescheiterte Archivierung).
- `docs/ops/guest-notification-ops.md` UploadAlerts und Gastbenachrichtigungen.
- **Photobooth-Incidents**
- `docs/ops/photobooth/ops_playbook.md` Vorgehen bei ausfallendem FTP, IngestFehlern oder Sicherheitsvorfällen (Credentials).
Zusätzlich gibt es kurze „Howto“-Runbooks für häufige Supportfälle:
- `docs/ops/howto-tenant-package-not-active.md` Zahlung erfolgreich, Paket nicht aktiv.
- `docs/ops/howto-guest-upload-failing.md` Gäste können nicht hochladen.
- `docs/ops/howto-photobooth-no-photos.md` PhotoboothUploads landen nicht im Event.
- `docs/ops/howto-dsgvo-delete-photo.md` DSGVOLöschung eines konkreten Fotos.
> TODO: Ergänze ein allgemeines „Major Incident“Kapitel (SEV1/2 Definition, Kommunikationskanäle, Vorlagen) und verlinke es hier.
## 6. Prozesse, Roadmap & Änderungen
Der Betreiber muss wissen, welche größeren Änderungen anstehen oder kürzlich live gegangen sind.
- **Prozess-Hub**
- `docs/process/README.md` erklärt Struktur von `changes/`, `todo/` und `roadmap.md`.
- **Roadmap & Epics**
- `docs/process/roadmap.md` Überblick über aktive Epics (z.B. Security Hardening, PaddleMigration, StreamingUploads) und kürzlich abgeschlossene Themen.
- `docs/process/todo/security-hardening-epic.md` SecurityHardeningPlan mit Bezug zu Ops (Signierte URLs, AV/EXIF, MonitoringWorkstreams).
- PaddleThemen: `docs/process/todo/paddle-migration.md`, `docs/process/todo/paddle-catalog-sync.md`.
- **Changes & Retro-Notizen**
- `docs/process/changes/*` SessionNotizen, RefactorPläne und Lessons Learned (z.B. CheckoutRefactor, RegistrierungFixes).
Als Betreiber lohnt es sich, bei größeren Deployments kurz in `roadmap.md` und den passenden `changes/*` zu schauen, um Seiteneffekte zu antizipieren.
## 7. Tests, Qualität & Releases
Stabile Releases sind Grundvoraussetzung für ruhigen Betrieb:
- **E2E-Tests & Qualität**
- `docs/testing/e2e.md` beschreibt, welche EndtoEndTests existieren und wie sie als SmokeSuite für Releases verwendet werden können.
- **Release-Prozess (Entwurf)**
- `docs/ops/releases.md` Checkliste für CIPipelines, StagingDeploy, ProdRollout, SmokeTests und RollbackÜberlegungen.
## 8. Nächste Schritte für das Betriebshandbuch
Die folgenden Kapitel sind als eigenständige Runbooks angelegt und sollten mit der Zeit weiter gefüllt werden:
- **Rollen & On-Call-Handbuch**
- `docs/ops/oncall-roles.md` definiert PlatformOps, OnCall, Support und Produktrollen sowie Eskalationswege.
- **On-Call Cheat Sheet**
- `docs/ops/oncall-cheatsheet.md` schnelle Übersicht über wichtige Kommandos, Logs und Dashboards für Incidents.
- **Support & Eskalation**
- `docs/ops/support-escalation-guide.md` beschreibt, welche Informationen Support von Kunden einsammeln sollte, bevor an Ops eskaliert wird.
- **Backup & Restore / Disaster Recovery**
- `docs/ops/backup-restore.md` Was gesichert werden muss, RestoreSzenarien und DRÜbungen.
- **DSGVO & Compliance-Operationen**
- `docs/ops/compliance-dsgvo-ops.md` Praktische Abläufe für Auskunfts/Löschanfragen, Retention und Dokumentation.
- **Billing & Zahlungs-Operationen**
- `docs/ops/billing-ops.md` Umgang mit Zahlungsproblemen, WebhookFehlern und PaketInkonsistenzen.
- **Monitoring & Observability**
- `docs/ops/monitoring-observability.md` Welche Signale, Metriken und Alerts es geben sollte.
- **Architektur-Diagramme**
- `docs/ops/diagrams.md` MermaidDiagramme für MediaPipeline und Checkout/BillingFlow.
Das Betriebshandbuch bleibt damit ein lebendes Dokument. Neue Runbooks sollten unter `docs/ops/` entstehen und hier verlinkt werden, damit Operatoren einen klaren Einstiegspunkt behalten.

View File

@@ -1,15 +1,15 @@
## Docker Queue & Horizon Setup
This directory bundles ready-to-use entrypoint scripts and deployment notes for running Fotospiels queue workers inside Docker containers. The examples assume you already run the main application in Docker (e.g. via `docker-compose.yml`) and share the same application image for workers. The shell scripts referenced below remain under `/docs/queue-supervisor/` so existing Dockerfile references stay valid.
This directory bundles ready-to-use entrypoint scripts and deployment notes for running Fotospiels queue workers inside Docker containers. The examples assume you already run the main application in Docker (e.g. via `docker-compose.yml`) and share the same application image for workers. Queue entrypoints now live in `/scripts/` inside the container so every service can execute the same shell scripts.
### 1. Prepare the application image
Make sure the worker scripts are copied into the image and marked as executable:
```dockerfile
# Dockerfile
COPY docs/queue-supervisor /var/www/html/docs/queue-supervisor
RUN chmod +x /var/www/html/docs/queue-supervisor/*.sh
# Dockerfile (excerpt)
COPY scripts /var/www/html/scripts
RUN chmod +x /var/www/html/scripts/*.sh
```
If you keep the project root mounted as a volume during development the `chmod` step can be skipped because the files will inherit host permissions.
@@ -31,7 +31,7 @@ services:
QUEUE_TRIES: 3 # optional overrides
QUEUE_SLEEP: 3
command: >
/var/www/html/docs/queue-supervisor/queue-worker.sh default
/var/www/html/scripts/queue-worker.sh default
media-storage-worker:
image: fotospiel-app
@@ -44,7 +44,7 @@ services:
QUEUE_TRIES: 5
QUEUE_SLEEP: 5
command: >
/var/www/html/docs/queue-supervisor/queue-worker.sh media-storage
/var/www/html/scripts/queue-worker.sh media-storage
media-security-worker:
image: fotospiel-app
@@ -57,7 +57,7 @@ services:
QUEUE_TRIES: 3
QUEUE_SLEEP: 5
command: >
/var/www/html/docs/queue-supervisor/queue-worker.sh media-security
/var/www/html/scripts/queue-worker.sh media-security
```
Scale workers by increasing `deploy.replicas` (Swarm) or adding `scale` counts (Compose v2).
@@ -79,7 +79,7 @@ services:
APP_ENV: ${APP_ENV:-production}
QUEUE_CONNECTION: redis
command: >
/var/www/html/docs/queue-supervisor/horizon.sh
/var/www/html/scripts/horizon.sh
```
Expose Horizon via your web proxy and protect it with authentication (the app already guards `/horizon` behind the super admin panel login if configured).

48
docs/ops/releases.md Normal file
View File

@@ -0,0 +1,48 @@
---
title: Releases & Deployments
sidebar_label: Releases & Deployments
---
Dieses Dokument beschreibt, wie Releases vorbereitet und durchgeführt werden und welche Tests aus OpsSicht Pflicht sind.
## 1. Vor dem Release
- Changelog grob durchsehen (Feature/BugfixUmfang verstehen).
- DatenbankMigrations prüfen:
- Sind `up`/`down` sauber und idempotent?
- Gibt es lange laufende Migrations (IndexBuilds)?
- KonfigÄnderungen:
- Neue ENVVariablen in `dokploy`/Compose hinterlegt?
- Secrets über SecretStore / DokployUI konfiguriert?
## 2. PflichtTests vor ProdDeploy
- **PHPUnit**:
- `php artisan test` oder mindestens relevante Suites (z.B. „Checkout“, „Storage“).
- **FrontendBuild**:
- `npm run build` (bzw. CIJob).
- **E2ESmokeTests** (siehe `docs/testing/e2e.md`):
- GuestFlow: Event beitreten, Foto hochladen, Anzeige prüfen.
- TenantFlow: Login, Event anlegen, Medienübersicht öffnen.
## 3. DeploymentAblauf (Beispiel Dokploy)
- Neues Image wird gebaut und getaggt (z.B. `fotospiel-app:2025-11-20`).
- DokployStack aktualisieren:
- AppContainer.
- Queue/HorizonContainer.
- DocsContainer (falls betroffen).
- Nach dem Deploy:
- `php artisan migrate --force`.
- Queues prüfen (`horizon:status`, `queue:failed`).
- Schnelle SmokeTests in Prod (nur lesende Aktionen oder TestTenant).
## 4. RollbackStrategie
- Vor dem Deploy aktuellen DatenbankSnapshot sicherstellen.
- Vorheriges ImageTag notieren.
- Rollback:
- Dokploy/Compose auf vorheriges Image zurückdrehen.
- Falls Migrations rückwärtskompatibel: ggf. `migrate:rollback`.
- IncidentEintrag mit Ursache und Lessons Learned ergänzen.

View File

@@ -0,0 +1,50 @@
---
title: Support → Ops Eskalationsleitfaden
sidebar_label: Support-Eskalation
---
Dieses Dokument beschreibt, welche Informationen der Support einsammeln sollte, bevor ein Ticket an Ops eskaliert wird. Ziel: weniger PingPong, schnellere Lösung.
## 1. Pflichtinfos pro Ticket
- **TenantID** bzw. TenantSlug.
- **EventID** bzw. EventSlug.
- **Zeitstempel** der Beobachtung (lokale Zeit + Zeitzone).
- **Betroffene User**:
- GastSession ID (falls verfügbar).
- EMail (für TenantAdmins).
- **Umgebung**:
- Browser + Version.
- Betriebssystem / Device.
- Mobil / Desktop.
- **Screenshots / Screenrecording**:
- Fehlermeldungen.
- UIZustand (z.B. Upload hängt bei 90 %).
## 2. Typische Fälle & Zusatzinfos
- **Upload schlägt fehl**
- URL des JoinLinks.
- Anzahl betroffener Gäste (einige / viele / alle).
- Grobe Dateigröße (Handyfoto, stark komprimiert, RAW etc.).
- **PhotoboothFotos fehlen**
- Name/Typ der Photobooth.
- Zeitpunkt der letzten sichtbaren Fotos.
- Ob die Photobooth selbst Fehler anzeigt.
- **Paket nicht aktiv / Limits falsch**
- Bestellnummer / PaddleCheckoutID (falls vorhanden).
- Zeitpunkt der Zahlung.
- Welches Paket wurde erwartet?
## 3. Wie an Ops übergeben?
- Ticket im Tracker mit Label „ops“ versehen.
- Kurzes Summary in ein bis zwei Sätzen:
- „Gäste können seit 18:30 Uhr im Event XYZ keine Fotos hochladen. Fehler: Upload fehlgeschlagen.“
- Alle oben genannten Pflichtinfos als strukturierte Liste ergänzen.
Siehe auch:
- `docs/ops/oncall-roles.md`
- `docs/ops/oncall-cheatsheet.md`

View File

@@ -35,7 +35,7 @@ const config = {
routeBasePath: '/',
sidebarPath: require.resolve('./sidebars.js'),
include: ['**/*.md', '**/*.mdx'],
exclude: ['site/**', 'archive/**', '**/_drafts/**'],
exclude: ['site/**', 'help/**', 'agents/**', 'content/**', 'archive/**', '**/_drafts/**'],
editUrl: undefined,
showLastUpdateAuthor: true,
showLastUpdateTime: true,

View File

@@ -4,7 +4,145 @@
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
docsSidebar: [{ type: 'autogenerated', dirName: '.' }],
docsSidebar: [
// Ops first: Betriebshandbuch + alle Runbooks
{
type: 'category',
label: 'Ops & Betrieb',
collapsed: false,
items: [
{
type: 'category',
label: 'Grundlagen',
collapsed: false,
items: [
'ops/operations-manual',
'ops/oncall-roles',
'ops/oncall-cheatsheet',
'ops/support-escalation-guide',
],
},
{
type: 'category',
label: 'Incidents & DR',
items: [
'ops/incidents-major',
'ops/backup-restore',
'ops/dr-tenant-event-restore',
'ops/dr-storage-issues',
],
},
{
type: 'category',
label: 'Medien & Upload',
items: [
'ops/media-storage-spec',
'ops/guest-notification-ops',
'ops/queue-workers',
'ops/howto-guest-upload-failing',
'ops/howto-photobooth-no-photos',
],
},
{
type: 'category',
label: 'Photobooth',
items: [
'ops/photobooth/README',
'ops/photobooth/control_service',
'ops/photobooth/ops_playbook',
],
},
{
type: 'category',
label: 'Billing',
items: [
'ops/billing-ops',
'ops/howto-tenant-package-not-active',
],
},
{
type: 'category',
label: 'DSGVO & Compliance',
items: [
'ops/compliance-dsgvo-ops',
'ops/howto-dsgvo-delete-photo',
'ops/howto-tenant-full-export',
],
},
{
type: 'category',
label: 'Deployment',
items: [
'ops/deployment/docker',
'ops/deployment/dokploy',
'ops/deployment/join-token-analytics',
'ops/deployment/lokale-podman-adressen',
'ops/deployment/public-api-incident-playbook',
],
},
{
type: 'category',
label: 'Releases & Tests',
items: [
'ops/releases',
'testing/e2e',
],
},
{
type: 'category',
label: 'Monitoring & Diagramme',
items: [
'ops/monitoring-observability',
'ops/diagrams',
],
},
],
},
// Prozesse, Roadmap, Changes
{
type: 'category',
label: 'Prozess & Roadmap',
collapsed: true,
items: [
'process/README',
'process/roadmap',
{
type: 'category',
label: 'TODO / Epics',
items: [
'process/todo/security-hardening-epic',
'process/todo/paddle-migration',
'process/todo/paddle-catalog-sync',
'process/todo/localized-seo-hreflang-strategy',
'process/todo/media-streaming-upload-refactor',
],
},
{
type: 'category',
label: 'Changes',
items: [
'process/changes/2025-09-08-session',
'process/changes/2025-10-02-registration-role-fixes',
'process/changes/2025-10-05-checkout-refactor-todo',
'process/changes/2025-10-09-paypal-sdk-migration',
'process/changes/2025-10-10-tenant-admin-onboarding-plan',
'process/changes/2025-11-08-coupon-ops',
],
},
],
},
// Testing / Qualität
{
type: 'category',
label: 'Testing',
collapsed: true,
items: ['testing/e2e'],
},
],
};
module.exports = sidebars;