# Info-Board Neu - MQTT-Vertrag Vertrag zwischen Backend und Agent für die Echtzeit-Synchronisation von Playlist-Änderungen und Gerätebefehlen. --- ## Überblick Das Messaging-System nutzt MQTT für: - **Playlist-Mutations-Benachrichtigungen**: Backend → Agent - **Device-Commands**: Backend → Agent (zukünftig: reload, restart_player, reboot, display_on/off) - **Heartbeat & Status**: Agent → Backend (siehe `PLAYER-STATUS-HTTP.md`) Alle Topics folgen dem Naming-Pattern: `signage/{component}/{screenSlug}/{event}` --- ## Topics ### Backend publishes #### `signage/screen/{screenSlug}/playlist-changed` **Publisher:** Backend **Subscriber:** Agent Wird nach jeder Mutation der Playlist gepublished (Add, Remove, Reorder, Enable/Disable Item). **Payload:** ```json { "ts": 1711268440000 } ``` - `ts`: Unix-Zeitstempel in Millisekunden des Änderungsereignisses auf dem Backend **Verhalten:** - Backend debounced Änderungen über **2 Sekunden** - Mehrere schnelle Mutationen werden zu einem Event zusammengefasst - Garantiert mindestens ein Event pro logischer Änderung **Agent-Reaktion:** - Agent empfängt das Event - Agent debounced die Verarbeitung über **3 Sekunden** - Agent startet sofortiges Playlist-Fetch via HTTP `GET /api/v1/screens/{screenSlug}/playlist` - Agent speichert die Playlist lokal und signalisiert dem Browser einen Reload **Implementierung (Agent):** ```go // Pseudocode func OnPlaylistChanged(msg PlaylistChangedMessage) { if debounceTimer.running { debounceTimer.reset() } else { debounceTimer.start(3 * time.Second) } } func onDebounceExpire() { playlist := fetchPlaylistViaHTTP() saveToLocalCache(playlist) signalBrowserReload() } ``` --- ## Zukünftige Topics Die folgenden Topics sind **geplant** für Phase 5 (Prototyping) und später: ### `signage/screen/{screenSlug}/device-command` **Publisher:** Backend **Subscriber:** Agent Befehl-Queue für Device-Steuerung. **Payload:** ```json { "cmd_id": "uuid", "command": "reload|restart_player|reboot|display_on|display_off", "ts": 1711268440000 } ``` **Agent-Reaktion:** - Befehl ausführen - ACK via HTTP POST zu `PUT /api/v1/screens/{screenSlug}/command-ack` --- ## Beispiel-Flow: Playlist-Update ``` Admin: Click "Speichern" in Playlist-UI ↓ Backend: Playlist-Mutation in DB schreiben ↓ Backend: `playlist-changed` mit ts=now nach 2s Debounce publifyen ↓ Agent: Event empfangen, 3s Debounce starten ↓ Agent: Nach 3s → HTTP GET /api/v1/screens/{slug}/playlist ↓ Backend: Aktuelle Playlist zurückgeben ↓ Agent: Lokal speichern, Browser signalisieren "reload" ↓ Browser: Neuer Content geladen und abgespielt ``` --- ## MQTT-Verbindungspezifikation (Siehe `PLAYER-KONZEPT.md` und Provisioning-Variablen für Broker-URL, Authentifizierung und Retry-Logik) - **Broker-Adresse:** Über Provisioning konfigurierbar (Standard: `tcp://backend:1883`) - **Client-ID:** `{tenantSlug}/{screenSlug}` (eindeutig pro Screen) - **Username/Password:** Device-spezifische Credentials (OAuth-ähnlich) - **QoS-Level:** 1 (At-Least-Once für Critical-Events) - **Retain:** nein (Event-Natur, nicht State) - **Heartbeat:** Separat via HTTP (siehe `PLAYER-STATUS-HTTP.md`) --- ## Notizen für Implementierer 1. **Replay bei Reconnect:** Topics haben `retain: false`, daher entfallen keine Events bei Trennung. Der Agent synchronisiert sich nach Reconnect via regulärem Status-Endpoint. 2. **Ordering:** Mehrere Events zu einem Screen sind ordered; Ordering über Screen-Grenzen hinweg ist nicht garantiert. 3. **Fehlerbehandlung:** Fehlgeschlagene Playlisten-Fetches werden vom Agent nach Standard-Retry-Logik wiederholt. 4. **Version der Spec:** v1.0 (März 2026)