Drei Zielgruppen, ein Produkt, null gemeinsame Annahmen.
Ein OOH-Werbenetzwerk hat drei unterschiedliche Nutzer mit nichts Gemeinsamem. Venue-Besitzer wollen wissen, was auf ihren Bildschirmen läuft und wann. Werbetreibende wollen Slots kaufen, nach Standort targetieren und Impression-Zahlen sehen. Die Bildschirme selbst sind überhaupt keine Nutzer — sie sind Geräte, die Zeitpläne zuverlässig empfangen und sie ohne menschliches Zutun abspielen müssen.
Der Kunde hatte ein funktionierendes Konzept und ein enges Launch-Fenster. Er brauchte ein Marketplace-Backend für Werbetreibenden-Freigaben, Abrechnung und Kampagnenplanung. Eine Konsole, in der Betreiber und Venue-Besitzer Slots in einen Kalender ziehen. Und eine Player-Laufzeit, die auf Android-Tablets hinter einer Hotelrezeption, Linux-Kiosken in einem Verkehrsknoten und Windows-Set-Top-Boxen in einer Einzelhandelskette laufen kann — ohne auf jedem eine andere Codebasis auszurollen.
Die bequeme Standardwahl für den Player war Electron. Electron bündelt eine Chromium-Instanz und eine Node-Laufzeit und läuft überall. Es wiegt aber auch Hunderte von Megabyte, aktualisiert sich unvorhersehbar selbst und fügt einer Sache, die ein Media-Player sein sollte, die Komplexität eines ganzen Browsers hinzu. Auf eingeschränkter Kiosk-Hardware war der Footprint entscheidend. Die Update-Frage war es noch mehr.
Ein Marketplace-Backend, eine Drag-and-drop-Konsole und ein nativer Player, der auf vier Betriebssystemen läuft.
Das Backend ist eine mandantenfähige Laravel-12-Anwendung, die alles abwickelt, was der Marketplace braucht: Werbetreibenden-Onboarding und -Freigaben, Kampagnenplanung mit Day-Parting und Geo-Targeting, Stripe-Abrechnungsabgleich, Medien-Upload und -Transkodierung, in die Wege geleitet über die Background-Job-Schicht von Laravel, und ein Impression-Aggregationsmodell, das das Reporting speist. Sanctum übernimmt die API-Authentifizierung. Assets liegen auf S3.
Die Betreiberkonsole ist eine Next.js-16-Admin-Oberfläche mit einem Drag-and-drop-Scheduler auf Basis von @dnd-kit. Venue-Besitzer sehen ihre Bildschirme und ihre Slots. Werbetreibende sehen ihre Kampagnen und ihre Reichweite. Die Admin-Rolle sieht alles. Alle drei sind dieselbe Anwendung, abgesichert nach Rolle.
Der Player ist Qt 6 und C++20. Er läuft auf macOS, Linux, Windows und Android aus einer einzigen CMake-Codebasis mit Presets pro Plattform. Beim Start verbindet er sich über WebSockets mit Supabase und abonniert seinen Zeitplan-Kanal. Wenn der Betreiber einen Slot in der Konsole verschiebt, trifft die Änderung in Echtzeit am Bildschirm ein — kein Polling, kein Aktualisierungszyklus. Fällt das Netz aus, greift der Player auf seinen lokal zwischengespeicherten Zeitplan und seine Medien zurück. Der Bildschirm spielt weiter.
- F · 01Mandantenfähige Konsole
- Venue-Besitzer, Werbetreibende und Admin in einer Oberfläche, abgesichert nach Rolle. Keine getrennten Portale, keine duplizierten Codebasen.
- F · 02Drag-and-drop-Scheduler
- Slots, Geo-Fences und Day-Parts in einem Kalender auf Basis von @dnd-kit angeordnet. Betreiber sehen Konflikte, bevor sie speichern.
- F · 03Echtzeit-Player-Synchronisation
- Zeitplanänderungen werden in dem Moment, in dem der Betreiber speichert, über Supabase-WebSockets an die Player-Flotte übertragen. Kein Polling, kein Neustart.
- F · 04Offline-fähiger Player
- Qt Sql mit SQLite cached den aktuellen Zeitplan und die Medien lokal. Ein WLAN-Ausfall lässt den Bildschirm nicht leer werden.
- F · 05Plattformübergreifendes natives Binary
- Eine CMake-Codebasis, vier Zielplattformen: macOS, Linux, Windows, Android. Jeder Build ist ein eigenständiges natives Binary — kein Chromium, kein V8.
- F · 06Marketplace-Abrechnung
- Stripe-Abrechnungsabgleich und Impression-Aggregation im Laravel-Backend. Werbetreibende zahlen für bestätigte Impressions.
Die Qt-Entscheidung, und was sie gegenüber dem Electron-Standard kostete.
Electron war die naheliegende Wahl. Das ganze Team konnte JavaScript. Die Admin-Konsole war bereits in TypeScript. Ein Electron-Player hätte ein Drittel seiner Codebasis mit der Web-Oberfläche geteilt. Wir schlossen ihn in der ersten Woche aus.
Die Deployment-Realität war der ausschlaggebende Faktor. Die Zielhardware reichte von Android-Tablets im 4G über Windows-Mini-PCs im Unternehmens-WLAN bis zu Linux-Kiosken mit abgeriegelten OS-Images. Der Chromium-Footprint von Electron — typischerweise 150–300 MB installiert — war ein klares Nein für die eingeschränkten Geräte. Das Auto-Update-Verhalten von Chromium, das mit den Richtlinien abgeriegelter Kiosk-Betriebssysteme in Konflikt gerät, war ein noch klareres Nein für die Unternehmens-Deployments.
Qt 6 mit C++20 liefert ein natives Binary pro Plattform, kompiliert auf rund 15 MB unter Linux und unter 30 MB unter Windows und Android. Der Update-Pfad ist ein Dateiaustausch, orchestriert vom Player selbst. Es gibt keine Browser-Engine, kein V8, keinen Electron-Protokoll-Broker. Die WebSocket-Verbindung zu Supabase läuft über Qt Network; die Medienwiedergabe läuft über Qt Multimedia. Der Offline-Cache nutzt Qt Sql mit SQLite. Jede Abhängigkeit wird im Binary ausgeliefert.
Ein Player, der zur Hardware passt, schlägt einen Player, der zum Team passt.
Der Preis war Kontextwechsel. Das Team betrieb drei Laufzeiten — PHP, TypeScript, C++ — parallel. Laufzeitübergreifende Integrationstests erforderten mehr Gerüst als ein Single-Language-Stack. Die CMake-Build-Matrix für vier Zielplattformen fügte CI-Komplexität hinzu. GitHub Actions führt vier Player-Build-Jobs pro Push aus; der Docker-basierte Linux-Build erwies sich als zuverlässigste Basislinie für die Reproduzierbarkeit.
Eine dreistufige OOH-Plattform, in unter einem Monat ausgeliefert.
Die erste Version aller drei Oberflächen war in 27 Tagen produktionsreif: 223 Commits über drei Repos, Multi-Plattform-CI bei jedem Push, Player-Binaries auf allen vier Zielbetriebssystemen vor dem finalen Review bestätigt. Das Marketplace-Backend wickelt den Abrechnungsabgleich der Werbetreibenden und die Impression-Aggregation ab. Die Konsole übernimmt die Planung ohne Tabellenkalkulation. Der Player übersteht Netzausfälle, ohne den Bildschirm leer zu lassen.
Die Plattform ist live. Die Betreiberkonsole ist das System of Record für Bildschirm-Zeitpläne im gesamten Netzwerk. Die Player-Flotte erhält Updates in Echtzeit über Supabase-WebSockets — in der Konsole vorgenommene Zeitplanänderungen propagieren auf physische Bildschirme ohne Neustart oder manuelle Synchronisation.
Die Moral der Stack-Entscheidung ist einfach. Electron ist die richtige Antwort, wenn der Komfort des Teams und die Liefergeschwindigkeit die bindenden Zwänge sind. Hier war es nicht die richtige Antwort. Wähle die Player-Laufzeit, die zu deiner Hardware passt, nicht die, die zur Komfortzone deines Teams passt.
Wir sagten ihnen, der Player müsse auf allem laufen, was wir bereits gekauft hatten. Sie kamen mit einem Binary zurück, das genau das tat.
