# CABINET Digital Signage System - Projektdokumentation **Stand:** Februar 2026 | **Version:** 1.3 --- ## 1. Projektübersicht Das CABINET Digital Signage System ist ein In-Store-Display-System für den CABINET Store in Bielefeld. Es besteht aus zwei eigenständigen Modulen, die auf hochkant montierten Displays (9:16 Seitenverhältnis, 1080x1920px) im Store laufen: | Modul | Datei | Live-URL | Zweck | |-------|-------|----------|-------| | **Video-Display** | `index.html` | `cabinet.b2in.eu` | Zeigt eine Endlos-Playlist von Videos mit rotierenden Footer-Inhalten (Headline, Subline, QR-Code) | | **Angebots-Display** | `offers/player.html` | (noch nicht live) | Zeigt statische Produkt-Slides (Angebote, Preise, Details) als Slide-Rotation | | **Info-Tablet** | (in Planung) | `cabinet.b2in.eu/info` | Zeigt Store-Status, Öffnungszeiten, Termine im Schaufenster | Alle Inhalte werden uber das B2in-Backend (Admin-Portal unter `portal.b2in.test`) gepflegt. --- ## 2. Architektur ``` public/_cabinet/ ├── index.html # LIVE: Video-Display (Hauptseite) ├── index_1.html # Ältere Version ├── index_2.html # Ältere Version ├── index-dynamic.html # Dynamische Variante ├── index-static-backup.html # Statisches Fallback ├── index copy.html # Kopie/Backup │ ├── offer.html # Prototyp: Angebots-Slides (all-in-one) ├── offers/ # NEU: Modulares Angebots-System │ ├── player.html # Slide-Player (lädt config.json + iFrames) │ ├── config.json # Slide-Konfiguration (Reihenfolge, Dauer, Inhalte) │ ├── shared-styles.css # Gemeinsame CSS-Styles für alle Slides │ ├── slide-0-intro.html # Intro-Slide (Store-Vorstellung) │ ├── slide-1-goya-hero.html # Produkt-Slide: GOYA Sideboard (Hero) │ ├── slide-2-goya-details.html# Produkt-Slide: GOYA Details/Konditionen │ └── slide-3-tando.html # Produkt-Slide: TANDO Spiegel (Impuls) │ ├── assets/ # Medien-Dateien │ ├── *.mp4 # Videos (Saison-Spots) │ ├── *.jpg # Produkt-/Hintergrundbilder │ └── cabinet-intro.jpg # Intro-Bild │ ├── go.php # QR-Code Redirect + Klick-Tracking ├── logger.php # Remote-Logging-Endpoint (CORS-fähig) ├── view-logs.php # Web-basierter Log-Viewer ├── setup-logging.sh # Logging-Setup-Skript ├── test-logging.html # Test-Seite für Logging ├── logs/ # Log-Dateien (nach Level + Datum) ├── clicks.log # QR-Code-Klick-Log │ ├── logo-cabinet-300.png # CABINET Logo (300px) ├── logo-cabinet.png.webp # CABINET Logo (WebP) ├── .htaccess.example # Apache-Konfigurationsvorlage │ ├── infotablet.md # Konzept: Info-Tablet für Schaufenster ├── offer.md # Notizen zum Angebots-System ├── QUICK_START.md # Bedienungsanleitung ├── KIOSK_MODE_SETUP.md # Anleitung Kiosk-Modus (Fully Browser) ├── LOGGING_README.md # Logging-Dokumentation ├── VIDEO_OPTIMIZATION_README.md# Video-Optimierungstipps └── CABINET_PROJECT.md # Diese Datei ``` --- ## 3. Modul A: Video-Display (`index.html`) ### Funktionsweise - Lädt die Konfiguration (Video-Playlist + Footer-Inhalte) per API vom Backend - Spielt Videos nacheinander in einer Endlosschleife ab - Footer rotiert unabhängig alle 30 Sekunden (Headline + Subline + QR-Code) ### API-Anbindung - **Endpoint:** `GET /api/display/config` (auf `b2in.eu`) - **Response:** ```json { "videoPlaylist": [ { "src": "assets/fruehjahr_2025.mp4", "position": 25 } ], "footerContent": [ { "headline": "Text", "subline": "Subtext", "url": "https://..." } ] } ``` - **Polling:** Alle 5 Minuten wird die Config neu geladen - **Präventiver Reload:** Alle 6 Stunden kompletter Page-Reload ### Robustheit - **Video-Watchdog:** Prüft alle 5 Sek. ob Video läuft, Recovery bei Stuck - **Start-Timeout:** 10 Sek. Timeout, dann Skip zum nächsten Video - **Memory-Management:** Cleanup nach jedem Video, Monitoring alle 10 Min. - **Error-Recovery:** Nach 3 aufeinanderfolgenden Fehlern → Page-Reload - **Remote-Logging:** Alle Events werden an `logger.php` gesendet ### Layout ``` ┌─────────────────┐ │ │ │ VIDEO-BEREICH │ flex-grow: 1 (nimmt restliche Höhe ein) │ (object-fit: │ │ cover) │ │ │ ├──────────────────┤ │ ▬▬▬ Progress ▬▬ │ 3px Progress-Bar │ CTA-TEXT │ QR │ ~10% Höhe │ Headline │Code │ Footer mit rotierendem Inhalt │ Subline │ │ └─────────────────┘ ``` --- ## 4. Modul B: Angebots-Display (`offers/`) ### Funktionsweise - `player.html` ist der Haupt-Player - Lädt `config.json` für Slide-Konfiguration - Jeder Slide ist ein eigenständiges HTML-Dokument, eingebettet per iFrame - Slides rotieren automatisch mit konfigurierbarer Dauer (8-12 Sek.) - Fade-Transition (0.6s) zwischen Slides ### Slide-Typen | Typ | Beschreibung | Beispiel | |-----|-------------|---------| | `intro` | Store-Vorstellung, allgemeiner Willkommenstext | slide-0-intro.html | | `product-hero` | Produkt mit Hero-Bild, Preis, UVP | slide-1-goya-hero.html | | `product-details` | Produkt-Details mit Bullet-Liste | slide-2-goya-details.html | | `product-impulse` | Impulskauf-Produkt ("Jetzt mitnehmen") | slide-3-tando.html | ### Slide-Layout (shared-styles.css) ``` ┌─────────────────────────────┐ │ HEADER │ Logo + Tagline │ [CABINET Logo] [Tagline] │ ├─────────────────────────────┤ │ │ │ HERO-BILD │ flex: 1 (nimmt Hauptfläche ein) │ (Produktfoto) │ │ [Badge] │ │ │ ├──────────────┬──────────────┤ │ INFO-BOX │ QR-BOX │ Unterer Bereich │ Eyebrow │ Titel │ │ Titel │ QR-Code │ │ Preis/UVP │ Kontakt │ │ Bullets │ │ └──────────────┴──────────────┘ ``` ### Design-System - **Schrift:** IBM Plex Sans (Google Fonts) - **Akzentfarbe:** `#009FE3` (Cabinet Blau) - **Safe-Area:** 64px Padding - **Max. Auflösung:** 1080x1920px (9:16) - **QR-Codes:** Werden live per `api.qrserver.com` generiert ### Status Die Angebots-Slides sind **fertig entwickelt aber noch nicht live**. Die Inhalte (Produkte, Preise, Bilder) sind statisch in den HTML-Dateien hinterlegt. Eine Backend-Anbindung (wie beim Video-Display) fehlt noch. --- ## 5. Modul C: Info-Tablet (in Planung) Konzept dokumentiert in `infotablet.md`. Ein kleines Tablet im Schaufenster zeigt: - Store-Status (Geöffnet/Hinweis/Geschlossen) - Öffnungszeiten (Wochenansicht, heutiger Tag hervorgehoben) - Nächster freier Beratungstermin - Kontakt + QR-Code **API geplant:** `GET /api/cabinet-tablet/status` --- ## 6. Backend-Anbindung ### Datenbank-Tabellen **`display_videos`** - Video-Playlist | Spalte | Typ | Beschreibung | |--------|-----|-------------| | id | bigint | Primary Key | | filename | varchar | Dateiname (z.B. `fruehjahr_2025.mp4`) | | title | varchar | Anzeige-Titel (optional) | | position | int | Vertikale Position des Videos (0-100, für `object-position`) | | sort_order | int | Reihenfolge in der Playlist | | is_active | tinyint | Aktiv/Inaktiv | **`display_footer_contents`** - Footer-Inhalte (CTA-Texte + QR-Codes) | Spalte | Typ | Beschreibung | |--------|-----|-------------| | id | bigint | Primary Key | | headline | varchar | Überschrift (z.B. "JETZT TERMIN BUCHEN") | | subline | varchar | Unterzeile (z.B. "Beratung vor Ort...") | | url | varchar | Ziel-URL für QR-Code (optional) | | short_code | varchar | 6-stelliger Code für Redirect (unique) | | clicks | int | Klick-Zähler (via go.php) | | sort_order | int | Reihenfolge | | is_active | tinyint | Aktiv/Inaktiv | ### Backend-Komponenten | Komponente | Pfad | Funktion | |-----------|------|----------| | API-Controller | `app/Http/Controllers/Api/DisplayConfigController.php` | Liefert JSON-Config für Video-Display | | Video-Model | `app/Models/DisplayVideo.php` | Eloquent-Model mit `active()` Scope | | Footer-Model | `app/Models/DisplayFooterContent.php` | Model mit Short-Code-Generierung + Short-URL | | Admin-Seite | `app/Livewire/Admin/Cms/CabinetDisplay.php` | Livewire-Verwaltung für Videos + Footer | | Admin-Route | `/admin/cms/cabinet` | Admin-Portal-Seite | | API-Route | `GET /api/display/config` | Öffentlicher API-Endpoint | ### QR-Code / Redirect-System 1. Backend generiert automatisch einen 6-stelligen `short_code` pro Footer-Inhalt 2. QR-Code im Display zeigt URL wie `cabinet.b2in.eu/go.php?z=abc123` 3. `go.php` schlägt den Code in der DB nach, erhöht den Klick-Zähler, und leitet weiter 4. Fallback: Alte Legacy-Codes (t, t1, p, i, f) für Rückwärtskompatibilität --- ## 7. Logging & Monitoring ### Remote-Logging (`logger.php`) - Empfängt POST-Requests mit JSON-Logdaten vom Display - CORS-aktiviert für Cross-Origin-Zugriff - Speichert Logs in drei Formaten: - Pro Level: `logs/info_2026-02-27.log`, `logs/error_2026-02-27.log` - Alle zusammen: `logs/all_2026-02-27.log` - JSON: `logs/json_2026-02-27.log` - Automatische Log-Rotation: Dateien > 30 Tage werden gelöscht ### Was wird geloggt - Video-Lifecycle: Start, Ende, Error, Stuck, Timeout - Heartbeat alle 5 Minuten ("Display läuft") - Memory-Status alle 10 Minuten - Online/Offline-Status - JavaScript-Fehler (global error handler) - Resource-Loading-Fehler (Bilder, Videos) ### Log-Viewer (`view-logs.php`) Web-basierte Oberfläche zum Lesen der Logs mit Auto-Refresh und Farbcodierung. --- ## 8. Deployment & Betrieb ### Live-System - **Domain:** `cabinet.b2in.eu` (Subdomain von b2in.eu) - **Assets-URL:** `https://b2in.eu/_cabinet/assets/` - **API-URL:** `https://b2in.eu/api/display/config` ### Test-System - **URL:** `b2in.test/_cabinet/` - **API:** `b2in.test/api/display/config` ### Kiosk-Modus Empfohlen: **Fully Kiosk Browser** (Android) - Details in `KIOSK_MODE_SETUP.md` - Auto-Start bei Boot - Vollbild ohne Statusbar - Auto-Restart bei Crash - Zeitsteuerung (22:00 Standby, 07:00 Aufwachen) --- ## 9. Offene Punkte / TODO - [ ] **Offers-System Backend-Anbindung**: `offers/` Slides haben noch keine API-Anbindung - Inhalte sind statisch im HTML - [ ] **Offers live schalten**: Player + Slides auf Live-System deployen - [ ] **Info-Tablet umsetzen**: Konzept steht (infotablet.md), Implementierung offen - [ ] **Offers Config aus DB**: `config.json` sollte dynamisch vom Backend generiert werden - [ ] **Bilder-Upload**: Produktbilder für Offers werden noch manuell in `assets/` abgelegt