Erweitere Planung um Templates und Provisionierung

This commit is contained in:
Jesko Anschütz 2026-03-22 13:06:31 +01:00
parent de15ee2e63
commit ceaecaa234
8 changed files with 1161 additions and 2 deletions

View file

@ -76,6 +76,21 @@ Beispiel-Endpunkte:
- `GET /api/v1/screens/:screenId/status`
- `GET /api/v1/screens/:screenId/snapshots/latest`
### 3a. Provisionierung
Zweck:
- neue Screens im Admin-Backend anlegen und technisch ausrollen
- Provisionierungslaeufe starten, beobachten und auswerten
Beispiel-Endpunkte:
- `POST /api/v1/screens/provision`
- `GET /api/v1/provisioning-jobs`
- `GET /api/v1/provisioning-jobs/:jobId`
- `POST /api/v1/provisioning-jobs/:jobId/retry`
- `POST /api/v1/provisioning-jobs/:jobId/cancel`
### 4. Medien
Zweck:
@ -108,6 +123,28 @@ Beispiel-Endpunkte:
- `PATCH /api/v1/screens/:screenId/playlist/items/:itemId`
- `DELETE /api/v1/screens/:screenId/playlist/items/:itemId`
### 5a. Globale Templates und Kampagnen
Zweck:
- globale monitoruebergreifende Templates verwalten
- Kampagnen konfigurieren, aktivieren und deaktivieren
- Screens gezielt global uebersteuern
Beispiel-Endpunkte:
- `GET /api/v1/templates`
- `POST /api/v1/templates`
- `GET /api/v1/templates/:templateId`
- `PATCH /api/v1/templates/:templateId`
- `POST /api/v1/templates/:templateId/scenes`
- `PATCH /api/v1/templates/:templateId/scenes/:sceneId`
- `POST /api/v1/campaigns`
- `PATCH /api/v1/campaigns/:campaignId`
- `POST /api/v1/campaigns/:campaignId/activate`
- `POST /api/v1/campaigns/:campaignId/deactivate`
- `PUT /api/v1/campaigns/:campaignId/assignments`
### 6. Player-Sync
Zweck:
@ -120,6 +157,7 @@ Beispiel-Endpunkte:
- `POST /api/v1/player/register`
- `GET /api/v1/player/config`
- `GET /api/v1/player/playlist`
- `GET /api/v1/player/campaign`
- `GET /api/v1/player/media-manifest`
- `GET /api/v1/player/media/:mediaId/download`
- `POST /api/v1/player/status`
@ -139,6 +177,48 @@ Beispiel-Endpunkte:
- `POST /api/v1/screens/:screenId/commands/display-on`
- `POST /api/v1/screens/:screenId/commands/display-off`
## Provisionierungs-API
### `POST /api/v1/screens/provision`
Legt einen neuen Screen an und startet einen Provisionierungsjob.
Erwartete Eingaben mindestens:
- `screen_slug` oder `display_id`
- `screen_name`
- `tenant_id` optional, falls direkt zugeordnet werden soll
- `target_ip`
- `target_port` optional, Default 22
- `remote_user`, Default `root`
- `auth_mode`
- `password` oder `private_key_ref` fuer die Erstverbindung
- optionale technische Parameter wie `rotation`, `resolution`, `fallback_dir`
Serverseitiger Ablauf:
1. Screen-Datensatz anlegen
2. Provisionierungsjob anlegen
3. Secret nur kurzlebig oder referenziert speichern
4. Worker/Jobrunner startet Ansible- oder SSH-gestuetzten Rollout
5. nach Erfolg meldet sich der Screen kuenftig regulaer ueber seinen Agenten
Antwort mindestens:
- `screen_id`
- `provisioning_job_id`
- `status`
### `GET /api/v1/provisioning-jobs/:jobId`
Liefert:
- Jobstatus
- aktuelle Stage
- Zeitstempel
- letzte Meldungen
- Fehlerursache bei Fehlschlag
## API-Antworten fuer den Player
### `GET /api/v1/player/config`
@ -178,6 +258,37 @@ Jedes Item enthaelt mindestens:
- `valid_until`
- `enabled`
### `GET /api/v1/player/campaign`
Liefert die fuer den Screen aktuell relevante globale Uebersteuerung.
Liefert:
- `campaign_revision`
- `active_campaign` nullable
Wenn `active_campaign` gesetzt ist, enthaelt es mindestens:
- `campaign_id`
- `template_id`
- `name`
- `priority`
- `valid_from`
- `valid_until`
- `override_mode`
- `scenes[]`
Jede Scene enthaelt mindestens:
- `id`
- `type`
- `src`
- `duration_seconds`
- `load_timeout_seconds`
- `cache_policy`
- `on_error`
- `layout_json`
### `GET /api/v1/player/media-manifest`
Liefert:
@ -256,6 +367,7 @@ Payload-Beispiel:
Typische Events:
- `playlist_changed`
- `campaign_changed`
- `sync_completed`
- `sync_failed`
- `item_failed`
@ -327,6 +439,8 @@ Der Server signalisiert aktiv:
- es gibt neue Playlist-Daten
- fuehre einen Befehl aus
Die eigentliche Erstprovisionierung laeuft nicht ueber MQTT, sondern ueber einen serverseitigen Job mit SSH/Ansible.
Beispielablauf bei Playlist-Aenderung:
1. Benutzer speichert Playlist in der Web-UI
@ -336,6 +450,16 @@ Beispielablauf bei Playlist-Aenderung:
5. Player synchronisiert fehlende Medien
6. Player bestaetigt erfolgreichen Reload
Beispielablauf bei Aktivierung einer globalen Kampagne:
1. Admin aktiviert eine Kampagne
2. Server erhoeht `campaign_revision`
3. Server sendet Event oder Command `reload`
4. Player ruft `GET /api/v1/player/campaign` ab
5. Player synchronisiert kampagnenbezogene Medien
6. Player setzt den Inhaltsmodus auf `campaign`
7. Nach Deaktivierung oder Ablauf faellt der Player wieder auf `tenant_playlist` oder `fallback` zurueck
## Offline-Verhalten
### Wenn HTTPS ausfaellt

View file

@ -111,6 +111,64 @@ Zweck:
- sichere Kommunikation mit API und Broker
- technische Inventarisierung
### `provisioning_job`
Repraesentiert einen Provisionierungslauf fuer einen neuen oder neu aufzubauenden Screen.
Felder:
- `id`
- `screen_id`
- `requested_by_user_id`
- `target_ip`
- `target_port`
- `remote_user`
- `auth_mode` (`password`, `key`)
- `provided_secret_ref`
- `ssh_key_fingerprint` nullable
- `status` (`queued`, `running`, `succeeded`, `failed`, `cancelled`)
- `stage` (`connect`, `bootstrap`, `key_install`, `package_install`, `deploy`, `verify`, `done`)
- `log_excerpt` nullable
- `error_message` nullable
- `started_at` nullable
- `finished_at` nullable
- `created_at`
- `updated_at`
Regeln:
- das eigentliche Passwort wird nicht im Klartext in der Datenbank gespeichert
- `provided_secret_ref` verweist auf einen kurzlebigen oder extern geschuetzten Secret-Eintrag
- pro Job soll klar erkennbar sein, in welchem Schritt ein Fehler aufgetreten ist
### `screen_group`
Optionale logische Gruppierung von Screens.
Felder:
- `id`
- `slug`
- `name`
- `description`
- `created_at`
- `updated_at`
### `screen_group_member`
Zuordnung eines Screens zu einer Gruppe.
Felder:
- `id`
- `screen_group_id`
- `screen_id`
- `created_at`
Zweck:
- praktische Zielauswahl fuer Kampagnen und Provisionierungsaktionen
### `media_asset`
Repraesentiert ein verwaltetes Medium.
@ -163,6 +221,95 @@ Regeln:
- pro Screen gibt es in v1 genau eine aktive Playlist
- spaeter koennen mehrere Playlists mit Umschaltung moeglich werden
### `display_template`
Repraesentiert ein globales Admin-Template zur monitoruebergreifenden Orchestrierung.
Beispiele:
- Schriftzug ueber mehrere Monitore
- saisonales Motiv auf allen Monitoren
- Veranstaltungslayout fuer einen befristeten Zeitraum
Felder:
- `id`
- `slug`
- `name`
- `description`
- `template_type` (`message_wall`, `full_screen_media`, `screen_specific_scene`)
- `enabled`
- `created_by_user_id`
- `created_at`
- `updated_at`
### `template_scene`
Repraesentiert die konkrete Auspraegung eines Templates fuer einen oder mehrere Screens.
Felder:
- `id`
- `display_template_id`
- `screen_id` nullable
- `screen_slot` nullable
- `type` (`image`, `video`, `pdf`, `web`, `html`)
- `src`
- `duration_seconds`
- `load_timeout_seconds`
- `cache_policy`
- `on_error`
- `layout_json`
- `created_at`
- `updated_at`
Hinweise:
- `screen_id` erlaubt die direkte Zuweisung zu einem konkreten Monitor
- `screen_slot` erlaubt spaeter abstrakte Wand-Slots wie `row1-col2`
- `layout_json` kann z. B. Textpositionen, Farben oder Teilbereiche des Gesamtmotivs beschreiben
### `campaign`
Repraesentiert eine aktivierbare globale Kampagne auf Basis eines Templates.
Felder:
- `id`
- `display_template_id`
- `name`
- `description`
- `priority`
- `active`
- `valid_from` nullable
- `valid_until` nullable
- `override_mode` (`replace_tenant_content`, `replace_all`, `merge_reserved_slots`)
- `created_by_user_id`
- `created_at`
- `updated_at`
Regeln:
- Kampagnen ueberschreiben in v1 standardmaessig den Firmencontent
- nach Ende oder Deaktivierung greift automatisch wieder der tenantbezogene Normalbetrieb
### `template_assignment`
Repraesentiert die Zuordnung einer Kampagne oder eines Templates zu einem oder mehreren Screens.
Felder:
- `id`
- `campaign_id`
- `screen_id`
- `enabled`
- `created_at`
- `updated_at`
Zweck:
- Auswahl einzelner Monitore, Gruppen oder aller Monitore
### `playlist_item`
Repraesentiert einen einzelnen Eintrag in einer Playlist.
@ -226,6 +373,8 @@ Felder:
- `last_sync_at`
- `current_playlist_id`
- `current_playlist_item_id` nullable
- `current_content_source` (`campaign`, `tenant_playlist`, `fallback`)
- `current_campaign_id` nullable
- `current_item_type` nullable
- `current_item_label` nullable
- `current_item_started_at` nullable
@ -312,6 +461,11 @@ Zweck:
- ein `tenant` hat viele `media_assets`
- ein `screen` hat genau eine aktive `playlist` in v1
- eine `playlist` hat viele `playlist_items`
- ein `display_template` hat viele `template_scenes`
- ein `display_template` hat viele `campaigns`
- eine `campaign` hat viele `template_assignments`
- ein `screen` hat viele `provisioning_jobs`
- eine `screen_group` hat viele `screen_group_members`
- ein `screen` hat genau einen aktuellen `screen_status`
- ein `screen` hat viele `screen_snapshots`
- ein `screen` hat viele `device_commands`
@ -353,12 +507,31 @@ Sinnvoll sind mindestens:
- `playlist_revision`
- `media_revision`
- `config_revision`
- `campaign_revision`
Der Player kann damit erkennen:
- ob neue Konfiguration vorliegt
- ob Medien nachgeladen werden muessen
- ob die lokale Kopie noch gueltig ist
- ob sich globale Uebersteuerungen geaendert haben
## Prioritaetsmodell der Inhaltsauswahl
Der Player wertet Inhalte in dieser Reihenfolge aus:
1. aktive Kampagne mit gueltigem Zeitfenster und Assignment fuer den Screen
2. aktive tenantbezogene Playlist des Screens
3. Fallback-Verzeichnis
Eine Kampagne ist aktiv, wenn:
- `active = true`
- `valid_from` leer oder erreicht ist
- `valid_until` leer oder noch nicht abgelaufen ist
- eine `template_assignment` fuer den Screen aktiv ist
Dadurch ist die globale Uebersteuerung ein Kernbestandteil und kein nachtraeglicher Sonderfall.
## Beispiel fuer aktive Playlist-Auswertung

117
PLAN.md
View file

@ -12,6 +12,7 @@ Ziele:
- Fallback auf sequentielle Anzeige aller Medien aus einem konfigurierten Verzeichnis
- mandantenfaehige Pflegeoberflaeche pro Monitor/Firma
- Admin-Oberflaeche fuer Gesamtsteuerung aller Monitore
- globale Admin-Templates zur monitoruebergreifenden Orchestrierung
- autonomer Offline-Betrieb bei Serverausfall
- einfache Verteilung per Ansible
- moeglichst geringe Abhaengigkeit vom Unterbau innerhalb Debian-/Raspberry-Pi-OS-Welt
@ -36,6 +37,14 @@ Ziele:
- Player: kein Voll-Docker-Ansatz fuer den Grafikpfad in Version 1
- Player besser als native Dienste mit systemd + Chromium-Kiosk
### Sprach- und Laufzeitstrategie
- `Go` ist die bevorzugte Sprache fuer systemnahe und portable Komponenten
- insbesondere gilt das fuer den `player-agent` und nach Moeglichkeit auch fuer zentrale Backend-Komponenten
- Ziel ist eine geringe Zahl externer Laufzeitabhaengigkeiten und moeglichst einfache Verteilung per Ansible
- fuer Browser-Oberflaechen bleibt JavaScript/TypeScript im Frontend natuerlich zulaessig
- falls einzelne Server-Bausteine spaeter aus pragmatischen Gruenden anders umgesetzt werden, soll das begruendet und dokumentiert werden
## Gesamtarchitektur
Das System besteht aus zwei Hauptteilen:
@ -89,6 +98,49 @@ Funktionen:
- Dienste neu starten
- Monitore rebooten
- Monitore an- und ausschalten
- globale Templates erstellen, testen und aktivieren
- temporaere Kampagnen fuer mehrere oder alle Monitore einschalten und wieder abschalten
- neue Monitore initial provisionieren und betriebsbereit ausrollen
### Globale Template-Orchestrierung
Die Admin-Seite bekommt zusaetzlich einen globalen Orchestrierungsbereich.
Ziele:
- grossformatige monitoruebergreifende Botschaften wie `SCHOENE FERIEN` oder `MORZ-INFO`
- saisonale oder veranstaltungsbezogene globale Motive, z. B. Weihnachten
- schnelles temporäres Ueberstimmen des Firmencontents
- Rueckkehr zum normalen Firmencontent auf Knopfdruck
Grundprinzip:
- globale Templates sind administrative Kampagnen mit hoeherer Prioritaet als tenantbezogene Inhalte
- sie koennen auf einzelne Monitore, Monitorgruppen oder alle Monitore angewendet werden
- sie sind zeitlich planbar oder manuell aktivierbar
- nach Deaktivierung faellt der Bildschirm automatisch auf seine normale tenantbezogene Playlist zurueck
### Automatische Screen-Provisionierung
Die Admin-Oberflaeche soll neue Bildschirme nicht nur fachlich anlegen, sondern technisch in Betrieb nehmen koennen.
Zielablauf:
- Admin gibt `display_id`, Ziel-IP und initiale Root-Zugangsdaten an
- das System stellt per SSH eine Erstverbindung her
- ein Deploy-Key oder dedizierter Verwaltungsschluessel wird hinterlegt
- noetige Pakete und Komponenten werden installiert
- Konfiguration fuer den neuen Screen wird ausgerollt
- der Player wird gestartet und meldet sich selbststaendig am Server an
Der Vorgang soll moeglichst als gefuehrter Provisionierungs-Workflow im Admin-Backend verfuegbar sein.
Wichtige Randbedingungen:
- Root-Passwoerter duerfen nicht dauerhaft im Klartext gespeichert werden
- Provisionierungsdaten sind nur fuer Admins sichtbar
- jeder Provisionierungslauf muss nachvollziehbar protokolliert werden
- die eigentliche Ausbringung soll auf einem automatisierbaren Ansible- oder SSH-Workflow basieren, nicht auf ad-hoc-Shellmagie im Browser
## Datenmodell
@ -100,6 +152,10 @@ Funktionen:
- `media_asset`
- `playlist`
- `playlist_item`
- `display_template`
- `template_scene`
- `template_assignment`
- `campaign`
- `screen_status`
- `screen_snapshot`
- `device_command`
@ -193,6 +249,23 @@ Eigenschaften:
- medientypgerechte Anzeigezeiten
- funktioniert komplett lokal aus dem Cache oder Dateisystem
### Prioritaetsregel fuer globale Templates
Die Inhaltsauswahl pro Screen folgt in v1 einer klaren Prioritaetskette:
1. aktive globale Kampagne bzw. aktives Admin-Template
2. normale tenantbezogene Playlist des Monitors
3. lokaler Fallback aus dem konfigurierten Verzeichnis
Das verhindert spaeteres Anflanschen und macht die Uebersteuerung von Beginn an explizit.
Wichtige Regeln:
- globale Templates sind immer explizit aktiv oder inaktiv
- sie koennen `valid_from` und `valid_until` besitzen
- sie koennen manuell sofort deaktiviert werden
- nach Ablauf oder Deaktivierung setzt der Screen automatisch beim normalen Inhalt fort
## Offline- und Cache-Strategie
Offline-Betrieb ist Pflicht.
@ -244,6 +317,12 @@ Empfohlene Umsetzung:
- Anzeige des letzten Screenshots in Admin- und Firmen-Oberflaeche
- ergaenzt durch strukturierte Statusdaten
Die Vorschau soll auch sichtbar machen, ob ein Screen gerade:
- tenantbezogenen Normalbetrieb zeigt
- von einer globalen Kampagne uebersteuert wird
- im Fallback-Modus laeuft
Statusdaten:
- aktuelles Item
@ -309,6 +388,11 @@ Aufgaben:
- Screenshot-Erzeugung
- Ueberwachung lokaler Dienste
Technische Vorgabe:
- Implementierung bevorzugt in `Go`
- Auslieferung moeglichst als einzelnes Binary
### `player-ui`
Aufgaben:
@ -330,6 +414,18 @@ Aufgaben:
- Datenbank
- Media-Storage
Zusaetzliche fachliche Server-Faehigkeiten:
- Verwaltung globaler Templates
- Konfiguration monitoruebergreifender Layouts und Szenen
- Aktivierung, Deaktivierung und Zeitplanung globaler Kampagnen
- technische Provisionierung neuer Screens ueber einen gefuehrten Admin-Workflow
Technische Vorgabe:
- Backend bevorzugt in `Go`, sofern die Entwicklungsdynamik nicht klar dagegen spricht
- Frontends als Web-Anwendungen mit ueblichem Browser-Stack
### Betriebsform
- bevorzugt per Docker Compose
@ -344,7 +440,7 @@ Bevorzugt:
- Raspberry Pi OS Lite
- Xorg-Minimalstack
- Chromium
- ein eigenes Player-Binary oder eine sehr schlanke Laufzeit
- ein eigenes Player-Binary in `Go` oder eine gleichwertig schlanke Laufzeit
- systemd
Vermeiden:
@ -361,6 +457,21 @@ Vermeiden:
- `signage_player`
- `signage_display`
- `signage_server`
- `signage_provision`
### Provisionierungsmodell
Die Erstinstallation eines neuen Screens soll auf Ansible aufsetzen.
Vorgesehener Ablauf:
1. Screen im Admin-Backend anlegen
2. einmalige technische Zugangsdaten fuer die Erstverbindung angeben
3. Backend startet einen Provisionierungsjob
4. der Job nutzt SSH/Ansible fuer Basis-Setup, Key-Deployment, Paketinstallation und Konfiguration
5. nach erfolgreicher Provisionierung verwendet der Screen nur noch den hinterlegten Verwaltungsschluessel und seine technische Geraeteidentitaet
Damit wird die GUI zur komfortablen Steuerschicht ueber einem reproduzierbaren Automatisierungsprozess.
### Konfigurationspfade auf dem Client
@ -383,6 +494,10 @@ Vermeiden:
9. Einen Pilotmonitor migrieren
10. Restliche Monitore sukzessive migrieren
Parallel von Anfang an mitdenken:
- globale Template-Orchestrierung darf kein Nachbau sein, sondern muss im Inhalts- und Prioritaetsmodell direkt vorgesehen werden
## Teststrategie
Zu testen sind mindestens:

View file

@ -14,11 +14,23 @@ Die Trennung von `/srv/docker/infoboard-netboot` ist sinnvoll, damit:
- Umsetzungs-Todo: `TODO.md`
- Datenmodell: `DATENMODELL.md`
- API- und MQTT-Vertrag: `API-MQTT-VERTRAG.md`
- Technologieentscheidungen: `TECH-STACK.md`
- Template-/Kampagnenkonzept: `docs/TEMPLATE-KONZEPT.md`
- Provisionierungskonzept: `docs/PROVISIONIERUNGSKONZEPT.md`
## Empfohlene spaetere Struktur
## Projektstruktur
- `docs/` fuer weitere Architektur- und Betriebsdokumente
- `server/` fuer Backend, Frontends und Compose-Dateien
- `player/` fuer Agent, UI und lokale Startlogik
- `ansible/` fuer Rollen, Inventories und Deployments
- `compose/` fuer Container-Definitionen und Stack-Bausteine
- `scripts/` fuer Hilfsskripte
## Naechste sinnvolle Inhalte in der Struktur
- `docs/` fuer weitere technische Detaildokumente
- `server/` fuer API, Admin-UI und Tenant-UI
- `player/` fuer `player-agent`, `player-ui` und lokale Startlogik
- `ansible/` fuer Rollen und Inventories
- `compose/` fuer den zentralen Server-Stack

147
TECH-STACK.md Normal file
View file

@ -0,0 +1,147 @@
# Info-Board Neu - Tech Stack
## Ziel
Dieses Dokument zieht die Technologieentscheidungen verbindlich zusammen, damit sie nicht nur verteilt in Plan und Todo-Liste stehen.
Leitlinien:
- moeglichst wenige Laufzeitabhaengigkeiten
- gute Portabilitaet zwischen Raspberry Pi OS und Debian
- einfache Verteilung per Ansible
- robuste Offline-Faehigkeit
- moeglichst wenig Ballast auf den Playern
## Verbindliche Entscheidungen
### Betriebssysteme
- Player: aktuelles Raspberry Pi OS Lite auf Debian-13-Basis
- Server: Debian-artiges System, bevorzugt mit Docker Compose betrieben
### Display-Stack auf dem Player
- Version 1 basiert auf X11
- keine volle Desktop-Umgebung
- kein LXDE, kein LightDM als Pflichtbestandteil
- Chromium laeuft im Kiosk-Modus gegen eine lokale Player-Oberflaeche
Begruendung:
- X11 ist fuer Chromium-Kiosk auf Raspberry Pi aktuell konservativer und besser vorhersehbar als Wayland
- weniger Ueberraschungen bei Screenshot-Erzeugung, Display-Steuerung und Watchdog-Verhalten
### Programmiersprachen
- `Go` ist die bevorzugte Sprache fuer systemnahe Komponenten
- `Go` ist die Standardwahl fuer den `player-agent`
- `Go` ist die bevorzugte Sprache fuer das Server-Backend, solange keine zwingenden Gruende dagegensprechen
- Browser-Oberflaechen werden mit einem normalen Web-Frontend-Stack umgesetzt
Begruendung:
- statische oder weitgehend selbstgenuegsame Binaries
- geringe Laufzeitabhaengigkeiten
- gute Cross-Compile- und Deploy-Eigenschaften
- passend fuer Debian- und Raspberry-Pi-Umgebungen
### Frontend-Stack
- Admin-UI: Web-Anwendung
- Tenant-/Monitor-UI: Web-Anwendung
- Player-UI: lokale Web-Anwendung fuer den Renderer
Noch offen, aber bewusst klein zu halten:
- Framework-Auswahl fuer Server-UIs, bevorzugt leichtgewichtig
- keine unnötig schwere Fullstack-Plattform nur aus Gewohnheit
### Server-Betrieb
- zentrale Komponenten bevorzugt in Docker Compose
- getrennte Services fuer Backend, Datenbank, MQTT und Reverse Proxy
- persistente Daten ausserhalb fluechtiger Container-Dateisysteme
- Provisionierungsjobs laufen serverseitig ueber einen dedizierten Worker oder Jobrunner
### Player-Betrieb
- keine Voll-Containerisierung des Grafikpfads in Version 1
- native systemd-Dienste fuer `player-agent` und Browser-Startlogik
- lokale Verzeichnisse fuer Cache, Medien, Status und Logs
### Provisionierung und Deployment
- die technische Erstinstallation neuer Screens wird ueber SSH + Ansible umgesetzt
- das Admin-Backend ist die steuernde Oberflaeche, aber nicht der Ort fuer eigentliche Shell-Logik
- Root-Passwoerter dienen nur als Bootstrap-Mittel und sollen nicht dauerhaft gespeichert werden
- nach der Erstinstallation erfolgt die weitere Verwaltung schluesselbasiert
## Zielkomponenten
### Player
- `player-agent` in `Go`
- `player-ui` als lokale Web-Oberflaeche
- Chromium als Renderer
- Xorg-Minimalstack
- systemd fuer Start, Neustart und Watchdog-Integration
### Server
- Backend-API in `Go`
- Admin-UI als Web-Frontend
- Tenant-UI als Web-Frontend
- PostgreSQL
- MQTT-Broker, bevorzugt Mosquitto
- Reverse Proxy
- Dateispeicher fuer Uploads, Caches und Screenshots
## Kommunikationsstack
- HTTPS fuer API, Upload, Download, Authentifizierung und Screenshots
- MQTT fuer Heartbeat, Status, Kommandos und Acknowledgements
Nicht vorgesehen:
- Medienuebertragung ueber MQTT
- permanente Spezial-Streams fuer den Regelbetrieb
## Laufzeit-Minimum auf dem Player
Anzustreben sind nur diese grossen Bausteine:
- Raspberry Pi OS Lite
- Xorg-Minimalstack
- Chromium
- eigenes `Go`-Binary fuer den Agenten
- systemd
Moeglichst zu vermeiden:
- komplette Desktop-Umgebungen
- mehrere externe Viewer wie `feh`, `vlc`, `wmctrl`, `xdg-open`
- umfangreiche Python- oder Node-Laufzeitstapel direkt auf dem Player
## Build- und Deployment-Richtung
- `Go`-Binaries sollen zentral gebaut und per Ansible verteilt werden koennen
- Konfiguration soll dateibasiert und gut templatisierbar sein
- Frontend-Artefakte sollen versioniert und reproduzierbar baubar sein
## Architekturfolgen aus diesen Entscheidungen
- der Player bleibt moeglichst nah an einem Appliance-Modell
- Browserfehler duerfen nicht direkt die eigentliche Logik bestimmen
- Renderer und Systemlogik bleiben getrennt
- Serverlogik ist zentralisiert, Playerlogik minimal und robust
## Bewusst vertagte Entscheidungen
- moeglicher spaeterer Wechsel auf Wayland
- exakte Frontend-Framework-Wahl
- genaue Auspraegung des Build-Systems fuer Frontend-Artefakte
- eventuelle Objekt-Storage-Einfuehrung statt einfachem Dateispeicher
## Aktueller technischer Grundsatz
Wenn zwei Varianten funktional gleichwertig sind, wird die Variante mit weniger Laufzeitabhaengigkeiten, einfacherem Deployment und besserem Offline-Verhalten bevorzugt.

17
TODO.md
View file

@ -7,6 +7,7 @@
- [ ] Dokumentationsstruktur fuer Architektur, Betrieb und Deployment anlegen
- [ ] Entscheidung fuer Server-Tech-Stack dokumentieren
- [ ] Entscheidung fuer Player-Implementierung dokumentieren
- [ ] Sprachentscheidung dokumentieren: `Go` als bevorzugte Sprache fuer Agent und moeglichst viele Backend-Komponenten
## Phase 1 - Fachliches Fundament
@ -16,6 +17,8 @@
- [ ] Fallback-Regel fuer ungeplante oder leere Inhalte verbindlich definieren
- [ ] Statusmodell fuer Online/Offline/Degraded/Error definieren
- [ ] Kommandokatalog fuer Admin-Aktionen finalisieren
- [ ] Template- und Kampagnenmodell fuer globale monitoruebergreifende Uebersteuerung finalisieren
- [ ] Prioritaetsregel `campaign > tenant_playlist > fallback` verbindlich festschreiben
## Phase 2 - Technische Zielarchitektur
@ -26,6 +29,9 @@
- [ ] Screenshot-/Vorschaustrategie spezifizieren
- [ ] Offline- und Cache-Strategie bis auf Dateiebene festlegen
- [ ] Sicherheitsmodell fuer Uploads, Login und Rechte pruefen
- [ ] API fuer Templates, Kampagnen, Aktivierung und Deaktivierung ausarbeiten
- [ ] Provisionierungs-Workflow fuer neue Screens technisch durchplanen
- [ ] Secret-Handling fuer initiale Root-Passwoerter oder Bootstrap-Zugaenge definieren
## Phase 3 - Player-Design
@ -49,6 +55,11 @@
- [ ] Authentifizierungskonzept festlegen
- [ ] Mandantentrennung im Datenmodell und in den APIs absichern
- [ ] Logging- und Monitoring-Konzept definieren
- [ ] Template-Editor fuer globale Kampagnen fachlich schneiden
- [ ] Aktivierungsoberflaeche fuer saisonale oder temporäre Kampagnen planen
- [ ] Gruppierung oder Slot-Modell fuer monitoruebergreifende Layouts planen
- [ ] Provisionierungs-UI fuer neue Screens fachlich und technisch schneiden
- [ ] Jobrunner-Konzept fuer Ansible-gestuetzte Erstinstallation planen
## Phase 5 - Prototyping
@ -60,6 +71,8 @@
- [ ] `valid_from`/`valid_until` im Prototyp pruefen
- [ ] Offline-Sync mit lokalem Cache pruefen
- [ ] MQTT-Kommandos `reload`, `restart_player`, `reboot`, `display_on`, `display_off` testweise durchspielen
- [ ] globale Kampagne testen, die tenantbezogenen Content temporär ueberschreibt
- [ ] Rueckfall auf Normalbetrieb nach manueller Deaktivierung pruefen
## Phase 6 - Betriebsfaehigkeit
@ -76,10 +89,12 @@
- [ ] Rolle `signage_player` erstellen
- [ ] Rolle `signage_display` erstellen
- [ ] Rolle `signage_server` erstellen
- [ ] Rolle `signage_provision` erstellen
- [ ] Inventar-/Variablenmodell fuer mehrere Monitore entwerfen
- [ ] Screen-spezifische Variablen wie `screen_id`, Rotation und Aufloesung abbilden
- [ ] Erstinstallation eines neuen Players automatisieren
- [ ] Update-Rollout eines bestehenden Players automatisieren
- [ ] Bootstrap ueber Root-Passwort auf SSH-Key und dauerhafte Verwaltung umstellen
## Phase 8 - Pilotbetrieb
@ -88,8 +103,10 @@
- [ ] Verbindung zum Zentralserver herstellen
- [ ] Upload- und Playlist-Pflege mit einem Testmandanten pruefen
- [ ] Admin-Funktionen am Pilotmonitor pruefen
- [ ] globale Template-Aktivierung fuer einen oder mehrere Monitore im Pilot testen
- [ ] Offline-Betrieb real testen
- [ ] Browser-/Renderer-Stabilitaet ueber laengeren Zeitraum beobachten
- [ ] komplette Neu-Provisionierung eines frischen Test-Screens aus dem Admin-Backend pruefen
## Phase 9 - Migration der Bestandsmonitore

View file

@ -0,0 +1,294 @@
# Info-Board Neu - Provisionierungskonzept
## Ziel
Neue Displays sollen aus dem Admin-Backend heraus technisch in Betrieb genommen werden koennen.
Der Workflow soll mindestens leisten:
- neuen Screen fachlich anlegen
- initiale Verbindung per IP und Bootstrap-Zugang herstellen
- SSH-Key fuer dauerhafte Verwaltung hinterlegen
- noetige Komponenten installieren
- Screen-spezifische Konfiguration ausrollen
- Display in lauffaehigen Zustand versetzen
Das Konzept ist ausdruecklich nicht auf 9 Monitore begrenzt. Es muss auch kuenftige Einzelanzeigen wie Vertretungsplan-Displays sauber abbilden.
## Grundprinzip
Die Admin-Oberflaeche ist der Einstiegspunkt, aber die eigentliche Ausbringung erfolgt reproduzierbar ueber einen serverseitigen Provisionierungsjob.
Technische Leitlinie:
- GUI sammelt Eingaben und zeigt Fortschritt
- Backend erzeugt Provisionierungsjob
- Jobrunner fuehrt SSH-/Ansible-Schritte aus
- Ergebnis wird protokolliert und in der UI sichtbar gemacht
## Eingaben fuer einen neuen Screen
Mindestens erforderlich:
- `display_id` bzw. `screen_slug`
- Anzeigename
- Ziel-IP-Adresse
- Bootstrap-Benutzer, Default `root`
- Bootstrap-Passwort oder alternativer Initial-Key
- gewuenschte Orientierung
- optionale Rotation
- Screen-Klasse oder Geraetetyp
- Tenant-Zuordnung, falls direkt bekannt
Optional sinnvoll:
- Aufloesung
- Fallback-Verzeichnis
- Snapshot-Intervall
- Zugehoerigkeit zu Gruppen
- Standortbeschreibung
## Orientierung und Rotationsmodell
Die Ausrichtung ist von Anfang an ein Pflichtfeld.
### Fachliche Orientierung
- `portrait`
- `landscape`
### Technische Rotation
- `0`
- `90`
- `180`
- `270`
Grundregel:
- die Orientierung ist die fachliche Voreinstellung fuer Templates und Layouts
- die Rotation ist die technische Ableitung fuer den Display-Stack auf dem Geraet
Beispiele:
- Infowand-Displays: typischerweise `portrait`
- Vertretungsplan-Displays: typischerweise `landscape`
Diese Werte muessen in Provisionierung, Player-Konfiguration und Kampagnenlogik gleichermassen sichtbar sein.
## Screen-Klassen
Um skalierbar zu bleiben, sollte die Provisionierung mit Klassen oder Profilen arbeiten.
Empfohlene Startklassen:
- `info_wall_display`
- `single_info_display`
- `vertretungsplan_display`
Diese Klassen koennen Defaults liefern fuer:
- Orientierung
- Rotation
- Aufloesung
- Gruppenmitgliedschaften
- Fallback-Verzeichnis
- spezielle UI- oder Template-Voreinstellungen
## Provisionierungsablauf
### 1. Fachliches Anlegen
Im Admin-Backend wird der Screen angelegt mit:
- Name
- ID
- Klasse
- Orientierung
- Tenant-Zuordnung
- Standort
### 2. Start des Provisionierungsjobs
Der Admin gibt die technischen Zugangsdaten fuer die Erstverbindung an.
Wichtig:
- Passwort nur fuer den aktuellen Job verwenden
- keine dauerhafte Klartextspeicherung
### 3. Verbindungsaufbau
Der Jobrunner versucht per SSH die Verbindung herzustellen.
Pruefpunkte:
- Erreichbarkeit
- SSH-Port
- gueltige Zugangsdaten
- Architektur und Betriebssystem grob erkennen
### 4. Bootstrap
Auf dem Zielsystem werden vorbereitet:
- Verwaltungsschluessel installieren
- optional dedizierten Verwaltungsbenutzer anlegen
- Basisverzeichnisse anlegen
- Systemvoraussetzungen pruefen
### 5. Basisinstallation
Installiert werden mindestens:
- noetige Systempakete
- X11-Minimalstack
- Chromium
- Player-Agent
- Player-UI oder deren Artefakte
- systemd-Units
### 6. Screen-Konfiguration
Ausgerollt werden mindestens:
- `screen_id`
- Server-URL
- MQTT-Parameter
- Orientierung und Rotation
- Snapshot-Intervall
- Fallback-Verzeichnis
- Gruppen oder Zielprofile
### 7. Verifikation
Der Job prueft mindestens:
- Dienste laufen
- lokaler Player-Endpunkt ist erreichbar
- Agent registriert sich am Server
- Heartbeat kommt an
- Screenshot oder Statusmeldung funktioniert
### 8. Abschluss
Der Provisionierungsjob wird als erfolgreich markiert und der Screen ist regulär verwaltbar.
## Sicherheitsmodell
### Bootstrap-Geheimnisse
Regeln:
- Root-Passwoerter nicht dauerhaft im Klartext speichern
- wenn Speicherung noetig ist, nur kurzlebig und stark geschuetzt
- besser: nur Referenz auf temporären Secret-Speicher
### Verwaltung nach Erstinstallation
Nach erfolgreicher Provisionierung gilt:
- weitere Verwaltung nur noch per SSH-Key
- der Screen besitzt eine technische Geraeteidentitaet
- API- und MQTT-Zugangsdaten sind geraetebezogen
### Protokollierung
Jeder Provisionierungslauf muss auditierbar sein.
Mindestens sichtbar:
- wer den Job gestartet hat
- wann er gestartet wurde
- fuer welchen Screen
- gegen welche Ziel-IP
- welche Stage aktiv war
- ob Fehler auftraten
## Skalierung ueber die bestehende Wand hinaus
Das Modell muss von Anfang an mit mehreren Geraetetypen umgehen koennen.
### Heute
- 9 Displays in der Infowand, Hochformat
### Perspektivisch
- mindestens 4 zusaetzliche Vertretungsplan-Anzeigen, Querformat
- eventuell weitere Einzelanzeigen
Konsequenz:
- Provisionierung darf nicht implizit von einer 3x3-Wand ausgehen
- Gruppen, Klassen, Orientierung und technische Defaults muessen explizit modelliert werden
## Ansible-Rolle `signage_provision`
Die Provisionierung sollte auf einer eigenen Rolle oder einem eigenen Playbook aufbauen.
Sinnvolle Teilbereiche:
- `bootstrap`
- `base`
- `display`
- `player`
- `verify`
Damit bleibt die Erstinstallation klar getrennt von spaeteren Updates.
## Fehlerfaelle
Der Jobrunner soll Fehler moeglichst frueh und verstaendlich melden.
Typische Fehlerfaelle:
- Host nicht erreichbar
- falsches Passwort
- SSH blockiert
- unpassendes Betriebssystem
- Paketinstallation fehlgeschlagen
- Chromium oder X11 startet nicht
- Player-Agent registriert sich nicht
Zu jedem Fehler soll sichtbar sein:
- Stage
- kurzer Fehlertext
- ob Retry sinnvoll ist
## Zielbild im Admin-Backend
Die UI fuer neue Screens sollte mindestens enthalten:
- Screen anlegen
- Klasse waehlen
- Orientierung waehlen
- Rotation festlegen oder automatisch vorbelegen
- Tenant zuordnen
- IP und Bootstrap-Zugang angeben
- Provisionierungsjob starten
- Fortschritt live oder halb-live sehen
- Erfolg/Fehler mit Details sehen
## Spaetere Erweiterungen
Moegliche Ausbaustufen:
- Provisionierung ohne Passwort nur mit Bootstrap-Key
- Zero-touch-Registrierung ueber vorbereitete Images
- automatische Gruppenzuordnung nach Klasse
- Massenprovisionierung mehrerer Screens
- Neu-Provisionierung oder Rebuild eines bestehenden Screens
## Fazit
Provisionierung ist nicht nur Deployment, sondern ein eigener fachlicher Workflow.
Wesentliche Grundpfeiler sind:
- Admin-gesteuerter Start
- Ansible-/SSH-basierte reproduzierbare Ausbringung
- explizite Orientierung und Rotation pro Screen
- Unterstuetzung fuer Wand-Screens und Einzelanzeigen
- sichere Umstellung von Bootstrap-Zugang auf dauerhafte schluesselbasierte Verwaltung

277
docs/TEMPLATE-KONZEPT.md Normal file
View file

@ -0,0 +1,277 @@
# Info-Board Neu - Template- und Kampagnenkonzept
## Ziel
Dieses Dokument konkretisiert die globale Orchestrierung im Admin-Backend.
Es geht um drei Kernpunkte:
1. Template-Typen und ihr fachlicher Zweck
2. Konfiguration und Bearbeitung dieser Templates
3. Zielmodell fuer Monitorwand, Einzelanzeigen und Aktivierung als Kampagne
Das Ziel ist, dass globale Inhalte von Anfang an sauber in das Systemmodell integriert sind und nicht spaeter als Sonderfall angebaut werden muessen.
## 1. Template-Typen
### `message_wall`
Dieser Typ dient fuer grosse monitoruebergreifende Botschaften.
Typische Beispiele:
- `SCHOENE FERIEN`
- `MORZ-INFO`
- `WEIHNACHTSFEIER`
Eigenschaften:
- ein Gesamtmotiv oder Gesamttext wird auf mehrere Displays verteilt
- jedes Display zeigt nur einen Ausschnitt oder einen zugewiesenen Teil des Gesamtlayouts
- sinnvoll vor allem fuer die bestehende Infowand mit hochkant montierten Bildschirmen
Technische Anforderungen:
- logisches Slot-Modell fuer die Wand
- definierte Zielgruppe von Screens
- klare Zuordnung `welcher Ausschnitt auf welchem Screen`
### `full_screen_media`
Dieser Typ dient fuer ein identisches oder pro Zielgeraet passend skaliertes Vollbildmotiv.
Typische Beispiele:
- Weihnachtsmotiv auf allen Screens
- Sommerferiengrafik
- Veranstaltungslogo
- identisches Informationsvideo auf mehreren Displays
Eigenschaften:
- alle ausgewaehlten Monitore zeigen denselben fachlichen Inhalt
- die technische Darstellung kann je nach Ausrichtung variieren
- ideal fuer schnelle globale Uebersteuerungen
Technische Anforderungen:
- medientypgerechte Darstellung fuer Hoch- und Querformat
- optionale getrennte Assets pro Orientierungsgruppe
- einfache Aktivierung/Deaktivierung im Admin-Backend
### `screen_specific_scene`
Dieser Typ dient fuer kampagnenweite, aber monitorindividuelle Szenen.
Typische Beispiele:
- auf der Infowand ein Schriftzug
- auf zusaetzlichen Vertretungsplan-Anzeigen parallel ein passendes Seitenlayout
- auf bestimmten Screens ein Veranstaltungsprogramm, auf anderen ein Wegweiser
Eigenschaften:
- ein Template besteht aus mehreren gezielten Szenen
- jede Szene ist bestimmten Screens, Gruppen oder Slots zugeordnet
- hoechste Flexibilitaet fuer spaetere Ausbaustufen
Technische Anforderungen:
- Zuordnung zu konkreten Screens oder Gruppen
- getrennte Assets je Zielgeraet moeglich
- definierte Prioritaet gegenueber tenantbezogenem Content
## 2. Template-Konfiguration im Admin-Backend
### Grundaufbau eines Templates
Ein Template besteht mindestens aus:
- technischem Namen (`slug`)
- Anzeigenamen
- Template-Typ
- Beschreibung
- Zieldefinition
- einem oder mehreren Szenen-/Medieneintraegen
- optionalen Standardwerten fuer Dauer, Timeouts und Fehlerverhalten
### Konfigurierbare Felder
Pro Template sollen mindestens pflegbar sein:
- `name`
- `slug`
- `description`
- `template_type`
- Standarddauer
- Standard-Timeout
- Standard-Fehlerstrategie
- Zielmenge (`alle Screens`, `Screen-Gruppe`, `einzelne Screens`, `Wall-Slots`)
### Szenen-/Asset-Konfiguration
Pro Szene oder Teilbereich sollen mindestens konfigurierbar sein:
- Medientyp (`image`, `video`, `pdf`, `web`, `html`)
- Quelle oder Asset
- Dauer
- `valid_from`
- `valid_until`
- Fehlerverhalten
- Zielscreen oder Zielslot
- Layout-Metadaten
### Aktivierung als Kampagne
Templates werden nicht direkt abgespielt, sondern als Kampagnen aktiviert.
Eine Kampagne ist die operative Auspraegung eines Templates und enthaelt:
- Name der Kampagne
- referenziertes Template
- Prioritaet
- Aktiv-Status
- `valid_from`
- `valid_until`
- Zielmenge
- Override-Modus
### Wichtige Admin-Funktionen
Im Admin-Backend soll es dafuer geben:
- Template-Liste
- Template-Editor
- Kampagnenliste
- Aktivieren/Deaktivieren auf Knopfdruck
- Zeitgesteuerte Aktivierung
- Vorschau, welche Screens betroffen sind
- Anzeige, welche Screens aktuell von einer Kampagne uebersteuert werden
## 3. Zielmodell fuer Monitorwand und Einzelanzeigen
## Ausgangslage
Das System darf nicht auf die aktuelle 9er-Infowand beschraenkt bleiben.
Perspektivisch sind mindestens zwei Klassen von Displays zu erwarten:
- Infowand-Screens im Hochformat
- zusaetzliche Einzelanzeigen wie Vertretungsplan-Displays im Querformat
Deshalb wird von Anfang an zwischen logischem Ziel und physischer Darstellung unterschieden.
### Screen-Klassen
Sinnvolle fachliche Klassen:
- `info_wall`
- `single_info_display`
- `vertretungsplan_display`
Diese Klassen koennen spaeter fuer Voreinstellungen, Templates und Provisionierung genutzt werden.
### Orientierung als Kernattribut
Jeder Screen braucht von Anfang an eine fest definierte Orientierung.
Mindestens:
- `portrait`
- `landscape`
Optional spaeter:
- exakte Rotation `0`, `90`, `180`, `270`
Warum das wichtig ist:
- Assets muessen passend skaliert oder getrennt gepflegt werden
- globale Kampagnen koennen fuer Hoch- und Querformat unterschiedliche Szenen brauchen
- Provisionierung und Display-Setup muessen die Orientierung kennen
### Gruppen- und Slot-Modell
Es werden zwei Zielmodelle parallel unterstuetzt.
#### Gruppenmodell
Gruppen fassen Screens logisch zusammen, z. B.:
- `all`
- `wall-all`
- `wall-row-1`
- `vertretungsplan-all`
Dieses Modell ist ideal fuer:
- globale Motive
- saisonale Kampagnen
- Massenaktionen im Admin-Bereich
#### Slot-Modell
Slots beschreiben feste Positionen innerhalb einer Monitorwand.
Beispiele:
- `wall-r1-c1`
- `wall-r1-c2`
- `wall-r1-c3`
- `wall-r2-c1`
Dieses Modell ist ideal fuer:
- verteilte Schriftzuege
- zusammengesetzte Grossmotive
- geordnete Layouts ueber mehrere Screens
### Empfohlene Grundregel fuer Kampagnen
Jede Kampagne definiert ihren Zielraum explizit:
- `all_screens`
- `screen_group`
- `specific_screens`
- `wall_slots`
Die Inhaltsprioritaet bleibt dabei immer:
1. aktive Kampagne
2. tenantbezogene Playlist
3. Fallback
### Beispiel 1 - Schriftzug ueber die Infowand
- Template-Typ: `message_wall`
- Ziel: Gruppe `wall-all`
- Layout: Text wird in neun Segmente geteilt
- jeder Slot bekommt seinen Ausschnitt
- die 4 kuenftigen Vertretungsplan-Screens bleiben unberuehrt
### Beispiel 2 - Weihnachtsmotiv auf allen Screens
- Template-Typ: `full_screen_media`
- Ziel: Gruppe `all`
- fuer Portrait-Screens wird Portrait-Asset verwendet
- fuer Landscape-Screens wird Landscape-Asset verwendet
### Beispiel 3 - Veranstaltungstag mit gemischten Anzeigen
- Template-Typ: `screen_specific_scene`
- Infowand zeigt Event-Motto
- Vertretungsplan-Screens zeigen Programm oder Wegweiser
- alles als eine Kampagne administrierbar
## Auswirkung auf Datenmodell und Implementierung
Von Beginn an mitzudenken sind:
- Template-Typen
- Kampagnen als aktivierbare Instanzen
- Gruppenmodell
- Slot-Modell fuer die Wand
- Orientierung pro Screen
- moegliche getrennte Assets fuer Portrait und Landscape
Damit ist die globale Orchestrierung ein tragender Bestandteil des Systems und kein nachtraeglicher Sonderbau.