From 3f3061a89950b6cc53cd09670709f374f07210cf Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Mon, 5 Jan 2026 19:42:58 +0100 Subject: [PATCH] Add live show docs and smoke tests --- .beads/issues.jsonl | 4 +- .beads/last-touched | 2 +- docs/help/de/admin/index.md | 1 + docs/help/de/admin/live-ops-control.md | 1 + docs/help/de/admin/live-show-setup.md | 82 +++++++++++++++++++++++++ docs/help/en/admin/index.md | 1 + docs/help/en/admin/live-ops-control.md | 1 + docs/help/en/admin/live-show-setup.md | 82 +++++++++++++++++++++++++ tests/Feature/LiveShowRealtimeTest.php | 45 ++++++++++++++ tests/ui/guest/live-show-player.test.ts | 14 +++++ 10 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 docs/help/de/admin/live-show-setup.md create mode 100644 docs/help/en/admin/live-show-setup.md create mode 100644 tests/ui/guest/live-show-player.test.ts diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 1f91f64..69d6b98 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -25,10 +25,10 @@ {"id":"fotospiel-app-55n","title":"Tenant admin onboarding: add Paddle error UX + test coverage","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-01T16:08:40.463283816+01:00","created_by":"soeren","updated_at":"2026-01-01T16:08:40.463283816+01:00"} {"id":"fotospiel-app-574","title":"Paddle catalog sync: extend PaddleClient tests/mocks for catalog endpoints","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T15:59:03.486301225+01:00","created_by":"soeren","updated_at":"2026-01-02T21:11:39.626820206+01:00","closed_at":"2026-01-02T21:11:39.626820206+01:00","close_reason":"Deprioritized"} {"id":"fotospiel-app-576","title":"Tenant admin onboarding: legacy asset audit + component inventory","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T16:07:59.996563146+01:00","created_by":"soeren","updated_at":"2026-01-01T16:08:05.599274641+01:00","closed_at":"2026-01-01T16:08:05.599274641+01:00","close_reason":"Completed in codebase (verified)"} -{"id":"fotospiel-app-579","title":"Live Show: tests (backend + UI smoke)","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-05T11:11:57.246607374+01:00","created_by":"soeren","updated_at":"2026-01-05T11:11:57.246607374+01:00","dependencies":[{"issue_id":"fotospiel-app-579","depends_on_id":"fotospiel-app-539","type":"blocks","created_at":"2026-01-05T11:13:27.729131522+01:00","created_by":"soeren"},{"issue_id":"fotospiel-app-579","depends_on_id":"fotospiel-app-xg5","type":"blocks","created_at":"2026-01-05T11:13:37.425191011+01:00","created_by":"soeren"},{"issue_id":"fotospiel-app-579","depends_on_id":"fotospiel-app-qne","type":"blocks","created_at":"2026-01-05T11:13:46.257175231+01:00","created_by":"soeren"}]} +{"id":"fotospiel-app-579","title":"Live Show: tests (backend + UI smoke)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T11:11:57.246607374+01:00","created_by":"soeren","updated_at":"2026-01-05T19:37:35.590123482+01:00","closed_at":"2026-01-05T19:37:35.590123482+01:00","close_reason":"Closed","dependencies":[{"issue_id":"fotospiel-app-579","depends_on_id":"fotospiel-app-539","type":"blocks","created_at":"2026-01-05T11:13:27.729131522+01:00","created_by":"soeren"},{"issue_id":"fotospiel-app-579","depends_on_id":"fotospiel-app-xg5","type":"blocks","created_at":"2026-01-05T11:13:37.425191011+01:00","created_by":"soeren"},{"issue_id":"fotospiel-app-579","depends_on_id":"fotospiel-app-qne","type":"blocks","created_at":"2026-01-05T11:13:46.257175231+01:00","created_by":"soeren"}]} {"id":"fotospiel-app-5dl","title":"Paddle catalog sync: PaddleCatalogService scaffold","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T16:00:24.916655836+01:00","created_by":"soeren","updated_at":"2026-01-01T16:00:30.566084195+01:00","closed_at":"2026-01-01T16:00:30.566084195+01:00","close_reason":"Completed in codebase (verified)"} {"id":"fotospiel-app-5hk","title":"Fix staging coupon seed 500 for E2E","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T15:12:53.643644221+01:00","created_by":"soeren","updated_at":"2026-01-04T16:21:46.441797374+01:00","closed_at":"2026-01-04T16:21:46.441797374+01:00","close_reason":"Resolved elsewhere; staging coupon seed 500 no longer reproducible after recent backend changes."} -{"id":"fotospiel-app-5ie","title":"Help docs: Live Show how-to + recommended hardware (DE/EN)","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-05T11:12:05.973844187+01:00","created_by":"soeren","updated_at":"2026-01-05T11:30:44.911207413+01:00","dependencies":[{"issue_id":"fotospiel-app-5ie","depends_on_id":"fotospiel-app-vro","type":"blocks","created_at":"2026-01-05T11:13:54.925412888+01:00","created_by":"soeren"},{"issue_id":"fotospiel-app-5ie","depends_on_id":"fotospiel-app-539","type":"blocks","created_at":"2026-01-05T11:14:03.257649076+01:00","created_by":"soeren"}]} +{"id":"fotospiel-app-5ie","title":"Help docs: Live Show how-to + recommended hardware (DE/EN)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T11:12:05.973844187+01:00","created_by":"soeren","updated_at":"2026-01-05T19:42:44.39939087+01:00","closed_at":"2026-01-05T19:42:44.39939087+01:00","close_reason":"Closed","dependencies":[{"issue_id":"fotospiel-app-5ie","depends_on_id":"fotospiel-app-vro","type":"blocks","created_at":"2026-01-05T11:13:54.925412888+01:00","created_by":"soeren"},{"issue_id":"fotospiel-app-5ie","depends_on_id":"fotospiel-app-539","type":"blocks","created_at":"2026-01-05T11:14:03.257649076+01:00","created_by":"soeren"}]} {"id":"fotospiel-app-5iy","title":"Security review: confirm env/header defaults","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T16:03:20.808188183+01:00","created_by":"soeren","updated_at":"2026-01-01T16:03:26.388002115+01:00","closed_at":"2026-01-01T16:03:26.388002115+01:00","close_reason":"Completed in codebase (verified)"} {"id":"fotospiel-app-5s3","title":"Localized SEO: canonical/hreflang tags + localized navigation","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T16:02:03.909947355+01:00","created_by":"soeren","updated_at":"2026-01-01T16:02:09.550647107+01:00","closed_at":"2026-01-01T16:02:09.550647107+01:00","close_reason":"Completed in codebase (verified)"} {"id":"fotospiel-app-5zl","title":"Ensure checkout step 3 requires login for Paddle checkout","description":"Problem: Paddle checkout on step 3 fails when user is not logged in. Step 3 must enforce authentication before initializing Paddle checkout.\\n\\nSuggestions:\\n- Protect step 3 route/controller with auth middleware and redirect to login with intended return URL.\\n- Gate step 3 UI/CTA on auth state; show inline login prompt and disable Paddle until authenticated.\\n- Require auth in backend endpoint that creates Paddle transaction/session; return 401 and send user to login.\\n- Optionally preflight at end of step 2 to prompt login before advancing.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-04T12:31:43.215017311+01:00","created_by":"soeren","updated_at":"2026-01-04T12:42:45.088723058+01:00","closed_at":"2026-01-04T12:42:45.088723058+01:00","close_reason":"Closed"} diff --git a/.beads/last-touched b/.beads/last-touched index 96c31ba..cabf891 100644 --- a/.beads/last-touched +++ b/.beads/last-touched @@ -1 +1 @@ -fotospiel-app-539.5 +fotospiel-app-579 diff --git a/docs/help/de/admin/index.md b/docs/help/de/admin/index.md index 052f333..ae51724 100644 --- a/docs/help/de/admin/index.md +++ b/docs/help/de/admin/index.md @@ -19,6 +19,7 @@ Hier findest du alle Informationen, die du als Event-Admin für einen reibungslo | Konto & Team | Wie lade ich Mitarbeitende ein und setze Branding auf? | `tenant-dashboard-overview` | | Event-Vorbereitung | Welche Checkliste erledige ich vor Einlass? | `event-prep-checklist` | | Live-Betrieb | Wie überwache ich Uploads, moderiere Inhalte und sende Hinweise? | `live-ops-control` | +| Live Show | Wie richte ich den Live-Show-Player ein und spiele ihn ab? | `live-show-setup` | | Abschluss & Compliance | Wie funktionieren Export, Archiv und Datenschutz? | `post-event-wrapup` | | Troubleshooting | Was tun bei Upload-Problemen, Geräteverlust oder Billing-Fragen? | `admin-issue-resolution` | diff --git a/docs/help/de/admin/live-ops-control.md b/docs/help/de/admin/live-ops-control.md index 8a9f755..f0a70b5 100644 --- a/docs/help/de/admin/live-ops-control.md +++ b/docs/help/de/admin/live-ops-control.md @@ -13,6 +13,7 @@ owner: ops@fotospiel.app related: - slug: event-prep-checklist - slug: admin-issue-resolution + - slug: live-show-setup --- ## Dashboard-Widgets diff --git a/docs/help/de/admin/live-show-setup.md b/docs/help/de/admin/live-show-setup.md new file mode 100644 index 0000000..393592a --- /dev/null +++ b/docs/help/de/admin/live-show-setup.md @@ -0,0 +1,82 @@ +--- +title: "Live Show einrichten & abspielen" +locale: de +slug: live-show-setup +audience: admin +summary: "Schritt-für-Schritt-Anleitung für Live Show, Moderation, Effekte und Hardware-Setup am Beamer." +version_introduced: 2025.4 +requires_app_version: "^3.2.0" +status: draft +translation_state: aligned +last_reviewed_at: 2025-02-22 +owner: ops@fotospiel.app +related: + - slug: live-ops-control + - slug: admin-issue-resolution +--- + +> Diese Anleitung ist für Event-Admins, die eine Live Show auf einem Bildschirm oder Beamer abspielen möchten. + +## Wann ist dieser Artikel relevant? +- Du willst neue Uploads live auf einer großen Leinwand zeigen. +- Du brauchst einen stabilen Ablauf mit Moderation, Effekten und klarer Hardware-Empfehlung. + +## Live Show vorbereiten (Admin-App) +1. Öffne das Event und gehe zu **Live Show Einstellungen**. +2. Wähle den **Moderationsmodus**: + - **Aus**: jedes Foto erscheint sofort. + - **Manuell**: Fotos landen in der Live-Show-Warteschlange. + - **Trusted only**: nur freigegebene Quellen werden automatisch übernommen. +3. Lege **Tempo** (Auto oder feste Sekunden), **Layout** (Single/Split/Grid) und **Effekt-Preset** fest. +4. Speichere die Einstellungen. + +## Live Show Link öffnen +- Öffne den Live-Show-Link im Format `/show/` im Browser des Abspielgeräts. +- Teile den Link nur mit Personen, die die Show steuern dürfen. + +> Tipp: Der Live-Show-Player läuft ohne Login und ist read-only. + +## Moderation im Live-Betrieb +- Öffne die **Live Show Queue** im Admin und bestätige neue Fotos. +- Nutze **„Approve + Live“**, um Galerie und Live Show in einem Schritt freizugeben. +- Reagiere schnell bei sensiblen Inhalten (Policy: ≤10 Minuten). + +## Effekte & Layouts (empfohlene Defaults) +- **Film Cut** + **Blur last**: ruhiger, professioneller Look. +- **Shutter Flash**: mehr Dynamik für Party- und Gala-Events. +- **Grid Burst**: ideal bei vielen Uploads und großen Leinwänden. + +## Empfohlenes Setup für Beamer +**Minimal (funktioniert):** +- Laptop mit Chrome/Edge, 8 GB RAM +- HDMI-Kabel (5–10 m) +- Beamer ≥3000 ANSI Lumen, 1080p + +**Empfohlen (stabil):** +- Mini-PC oder Laptop mit dedizierter Grafikeinheit +- Ethernet-Verbindung (USB‑C → Ethernet Adapter) +- Beamer ≥4500 ANSI Lumen, 1080p/4K, 16:9 +- HDMI 2.0 + aktiver HDMI-Verlängerer (ab 10 m) + +**Optional:** +- HDMI-Splitter (zusätzliche Displays) +- Präsentationsklicker für schnellen Fokuswechsel + +## Beamer & Bildschirm richtig einstellen +1. Auflösung auf **16:9** setzen, Skalierung 100 %. +2. Vollbild aktivieren (Taste **F** im Player oder Browser-F11). +3. Energiesparmodus und Bildschirmsperre deaktivieren. +4. Benachrichtigungen im Betriebssystem ausschalten. + +## Netzwerk & Stabilität +- Nutze 5 GHz-WLAN oder (besser) Ethernet. +- Vermeide offene Gäste-WLANs für den Player. +- Stelle sicher, dass das Abspielgerät **dauerhaft online** bleibt. + +## Häufige Probleme +- **Fotos erscheinen nicht:** Moderationsmodus prüfen, Queue leeren, Live-Show-Link neu laden. +- **Ruckler:** Effekt-Intensität reduzieren, Layout auf Single wechseln, WLAN prüfen. +- **Schwarzer Bildschirm:** HDMI-Eingang am Beamer prüfen, Browser-Fullscreen deaktivieren/neu aktivieren. + +### Weitere Hilfe +Siehe `admin-issue-resolution` für Troubleshooting oder kontaktiere den Support. diff --git a/docs/help/en/admin/index.md b/docs/help/en/admin/index.md index 696c334..d81da00 100644 --- a/docs/help/en/admin/index.md +++ b/docs/help/en/admin/index.md @@ -19,6 +19,7 @@ This portal collects everything event admins need to configure customer accounts | Account Setup | How do I invite staff and configure branding? | `tenant-dashboard-overview` | | Event Preparation | What checklists should I complete before doors open? | `event-prep-checklist` | | Live Operations | How do I monitor uploads, moderate content, and trigger announcements? | `live-ops-control` | +| Live Show | How do I set up and run the Live Show player? | `live-show-setup` | | Wrap-up & Compliance | How are exports, archives, and privacy handled? | `post-event-wrapup` | | Troubleshooting | How to handle upload issues, device loss, billing, etc. | `admin-issue-resolution` | diff --git a/docs/help/en/admin/live-ops-control.md b/docs/help/en/admin/live-ops-control.md index d2afcf8..1fbf16c 100644 --- a/docs/help/en/admin/live-ops-control.md +++ b/docs/help/en/admin/live-ops-control.md @@ -13,6 +13,7 @@ owner: ops@fotospiel.app related: - slug: event-prep-checklist - slug: admin-issue-resolution + - slug: live-show-setup --- ## Dashboard widgets diff --git a/docs/help/en/admin/live-show-setup.md b/docs/help/en/admin/live-show-setup.md new file mode 100644 index 0000000..341a760 --- /dev/null +++ b/docs/help/en/admin/live-show-setup.md @@ -0,0 +1,82 @@ +--- +title: "Set up & run Live Show" +locale: en +slug: live-show-setup +audience: admin +summary: "Step-by-step guide for Live Show, moderation, effects, and recommended projector hardware." +version_introduced: 2025.4 +requires_app_version: "^3.2.0" +status: draft +translation_state: aligned +last_reviewed_at: 2025-02-22 +owner: ops@fotospiel.app +related: + - slug: live-ops-control + - slug: admin-issue-resolution +--- + +> This guide is for event admins who want to run Live Show on a big screen or projector. + +## When is this relevant? +- You want new uploads to appear live on a large display. +- You need a stable flow with moderation, effects, and hardware guidance. + +## Prepare Live Show (Admin app) +1. Open the event and go to **Live Show settings**. +2. Choose a **moderation mode**: + - **Off**: every photo appears immediately. + - **Manual**: photos are held in the Live Show queue. + - **Trusted only**: only approved sources are auto-added. +3. Set the **pace** (auto or fixed seconds), **layout** (single/split/grid), and **effect preset**. +4. Save the settings. + +## Open the Live Show link +- Open the Live Show URL in the format `/show/` on the playback device. +- Share the link only with staff who should control the show. + +> Tip: The Live Show player is read-only and works without login. + +## Moderation during the event +- Open the **Live Show queue** in the admin app and approve new photos. +- Use **"Approve + Live"** to publish to gallery and Live Show in one step. +- Act quickly on sensitive content (policy: ≤10 minutes). + +## Effects & layouts (recommended defaults) +- **Film Cut** + **Blur last**: calm, professional look. +- **Shutter Flash**: more energy for party and gala moments. +- **Grid Burst**: best for high-volume uploads and big screens. + +## Recommended projector setup +**Minimum (works):** +- Laptop with Chrome/Edge, 8 GB RAM +- HDMI cable (5–10 m) +- Projector ≥3000 ANSI lumens, 1080p + +**Recommended (stable):** +- Mini PC or laptop with dedicated GPU +- Ethernet connection (USB‑C → Ethernet adapter) +- Projector ≥4500 ANSI lumens, 1080p/4K, 16:9 +- HDMI 2.0 + active HDMI extender (10 m or more) + +**Optional:** +- HDMI splitter (additional displays) +- Presentation clicker for quick focus switching + +## Screen & projector tuning +1. Set resolution to **16:9**, scaling 100%. +2. Enable fullscreen (press **F** in the player or browser F11). +3. Disable sleep mode and screen lock. +4. Disable OS notifications. + +## Network & stability +- Use 5 GHz Wi‑Fi or (better) Ethernet. +- Avoid guest Wi‑Fi for the player device. +- Keep the playback device **online at all times**. + +## Common issues +- **Photos not showing:** check moderation mode, clear the queue, reload the Live Show link. +- **Stutter:** reduce effect intensity, switch to Single layout, check Wi‑Fi. +- **Black screen:** verify projector input, toggle browser fullscreen off/on. + +### Further help +See `admin-issue-resolution` for troubleshooting or contact support. diff --git a/tests/Feature/LiveShowRealtimeTest.php b/tests/Feature/LiveShowRealtimeTest.php index d7f05f5..50f2524 100644 --- a/tests/Feature/LiveShowRealtimeTest.php +++ b/tests/Feature/LiveShowRealtimeTest.php @@ -88,4 +88,49 @@ class LiveShowRealtimeTest extends TestCase $response->assertNotFound(); } + + public function test_live_show_updates_returns_settings_when_version_changes(): void + { + $event = Event::factory()->create([ + 'live_show_token' => str_repeat('c', 64), + 'settings' => [ + 'live_show' => [ + 'effect_preset' => 'film_cut', + ], + ], + ]); + + $state = $this->getJson("/api/v1/live-show/{$event->live_show_token}"); + $state->assertOk(); + $version = $state->json('settings_version'); + + $updates = $this->getJson("/api/v1/live-show/{$event->live_show_token}/updates?settings_version={$version}"); + $updates->assertOk(); + $updates->assertJsonPath('settings', null); + + $event->forceFill([ + 'settings' => [ + 'live_show' => [ + 'effect_preset' => 'shutter_flash', + ], + ], + ])->save(); + + $updates = $this->getJson("/api/v1/live-show/{$event->live_show_token}/updates?settings_version={$version}"); + $updates->assertOk(); + $updates->assertJsonMissing(['settings' => null]); + $updates->assertJsonPath('settings.effect_preset', 'shutter_flash'); + } + + public function test_live_show_updates_rejects_invalid_cursor(): void + { + $event = Event::factory()->create([ + 'live_show_token' => str_repeat('d', 64), + ]); + + $response = $this->getJson("/api/v1/live-show/{$event->live_show_token}/updates?after_approved_at=invalid&after_id=1"); + + $response->assertStatus(422); + $response->assertJsonPath('error', 'invalid_cursor'); + } } diff --git a/tests/ui/guest/live-show-player.test.ts b/tests/ui/guest/live-show-player.test.ts new file mode 100644 index 0000000..2324b8e --- /dev/null +++ b/tests/ui/guest/live-show-player.test.ts @@ -0,0 +1,14 @@ +import { test, expectFixture as expect, dismissConsentBanner } from '../helpers/test-fixtures'; + +const liveShowToken = process.env.E2E_LIVE_SHOW_TOKEN; + +test.describe('Live Show Player', () => { + test('loads the player shell', async ({ page }) => { + test.skip(!liveShowToken, 'Set E2E_LIVE_SHOW_TOKEN to a valid live show token.'); + + await page.goto(`/show/${liveShowToken}`); + await dismissConsentBanner(page); + + await expect(page.getByRole('button', { name: /Pause|Play|Weiter/i })).toBeVisible(); + }); +});