177 lines
5.2 KiB
Markdown
177 lines
5.2 KiB
Markdown
# Info-Board Neu - Architekturentscheidungen vor dem ersten Code
|
|
|
|
## Ziel
|
|
|
|
Dieses Dokument sammelt die Punkte, die vor dem Einstieg in die Implementierung bewusst entschieden werden mussten.
|
|
|
|
Es geht nicht um offene Detailfragen fuer spaeter, sondern um Entscheidungen mit Einfluss auf Datenmodell, API, Player-Verhalten und Admin-UI.
|
|
|
|
Stand: Diese Punkte sind fuer v1 entschieden.
|
|
|
|
## 1. `message_wall`-Rendering
|
|
|
|
### Frage
|
|
|
|
Wer berechnet die Aufteilung eines Gesamtmotivs oder Schriftzugs auf die beteiligten Displays?
|
|
|
|
Moegliche Varianten:
|
|
|
|
- serverseitig beim Aktivieren einer Kampagne
|
|
- playerseitig anhand von Slot-Metadaten
|
|
|
|
### Entscheidung
|
|
|
|
Fuer v1 wird `message_wall` serverseitig in konkrete Screen-Szenen aufgeloest.
|
|
|
|
### Begruendung
|
|
|
|
- weniger Komplexitaet im Player
|
|
- identische Berechnung fuer alle beteiligten Screens
|
|
- einfachere Vorschau im Admin-Backend
|
|
- Kampagnen werden vor Aktivierung bereits in konkrete Zielinhalte ueberfuehrt
|
|
|
|
### Konsequenz
|
|
|
|
- `message_wall` wird im Backend oder Worker in konkrete `template_scenes` pro Slot/Screen transformiert
|
|
- der Player bekommt nur noch seinen eigenen fertigen Ausschnitt
|
|
- `layout_json` muss trotzdem klar definiert werden, dient dann aber primaer der Serverlogik und UI-Vorschau
|
|
|
|
## 2. Secret-Handling fuer Provisionierung
|
|
|
|
### Frage
|
|
|
|
Wie werden initiale Root-Passwoerter oder Bootstrap-Secrets verarbeitet, ohne sie unkontrolliert in der Datenbank liegen zu lassen?
|
|
|
|
### Entscheidung
|
|
|
|
Separate Secret-Verwaltung mit kurzer Lebensdauer:
|
|
|
|
- Secret nicht direkt in `provisioning_jobs`
|
|
- stattdessen separater Secret-Eintrag mit TTL
|
|
- verschluesselt mit App-Key
|
|
- automatische Loeschung nach Abschluss oder Abbruch des Jobs
|
|
|
|
### V1-Loesung fuer dieses Projekt
|
|
|
|
- Tabelle fuer kurzlebige Provisionierungs-Secrets
|
|
- AES-verschluesselte Speicherung via Server-App-Key
|
|
- Referenz ueber `provided_secret_ref`
|
|
- Cleanup-Job entfernt Secrets nach erfolgreicher Provisionierung oder nach Ablauf
|
|
|
|
## 3. ACK-Timeout fuer Kommandos
|
|
|
|
### Frage
|
|
|
|
Wann wird ein `device_command` ohne ACK als fehlgeschlagen oder abgelaufen markiert?
|
|
|
|
### Entscheidung
|
|
|
|
Ein serverseitiger Worker uebernimmt Timeouts und Statusuebergaenge.
|
|
|
|
Vorgeschlagenes Verhalten:
|
|
|
|
- `queued` -> `sent`
|
|
- falls innerhalb eines konfigurierten Zeitfensters kein ACK kommt: `expired`
|
|
- falls technische Zustellung fehlschlaegt: `failed`
|
|
|
|
### Startwerte fuer v1
|
|
|
|
- `reload`, `refresh_snapshot`: 30 Sekunden
|
|
- `restart_player`, `display_on`, `display_off`: 60 Sekunden
|
|
- `reboot`: 120 Sekunden
|
|
|
|
Wenn nach Ablauf kein ACK eingegangen ist, wird der Befehl auf `expired` gesetzt.
|
|
|
|
### Konsequenz
|
|
|
|
- es braucht einen periodischen Background-Job
|
|
- ACK-Timeouts werden nicht im Web-Request, sondern im Worker behandelt
|
|
|
|
## 4. Netzwerktopologie fuer Erstprovisionierung
|
|
|
|
### Frage
|
|
|
|
Kann der zentrale Server die Zielgeraete bei der Erstinstallation direkt per SSH erreichen?
|
|
|
|
### Entscheidung
|
|
|
|
Das wird als harte Betriebsannahme explizit dokumentiert und geprueft.
|
|
|
|
Moegliche Betriebsmodelle:
|
|
|
|
- Server steht im selben Netz oder VLAN wie die Player
|
|
- Server erreicht die Player ueber Routing/Firewall-Freigaben
|
|
- Provisionierungs-Worker laeuft auf einem Jumphost im richtigen Netz
|
|
|
|
V1-Entscheidung:
|
|
|
|
- die Provisionierung wird so gebaut, dass der Worker auch auf einem separaten Jumphost laufen kann
|
|
- direkte SSH-Erreichbarkeit vom Hauptserver ist erlaubt, aber nicht vorausgesetzt
|
|
- die Netzposition des Workers wird als Betriebsparameter behandelt
|
|
|
|
### Konsequenz
|
|
|
|
Die Provisionierungsarchitektur ist erst dann belastbar, wenn klar ist:
|
|
|
|
- wo der Worker laeuft
|
|
- welche Netze er erreicht
|
|
- ob SSH direkt moeglich ist
|
|
- ob spaeter ein Jumphost-Konzept benoetigt wird
|
|
|
|
## 5. Kleine Modellbereinigung vor Implementierung
|
|
|
|
### `playlist_items.screen_id`
|
|
|
|
Aktuell ist das Feld fachlich redundant, weil das Item bereits ueber die Playlist einem Screen zugeordnet ist.
|
|
|
|
Entscheidung:
|
|
|
|
- das Feld wird aus dem finalen Implementierungsschema entfernt
|
|
- die Screen-Zuordnung laeuft ausschliesslich ueber `playlists.screen_id`
|
|
|
|
### `template_assignments`
|
|
|
|
Aktuell ist das Schema auf konkrete Screens ausgelegt.
|
|
|
|
Entscheidung:
|
|
|
|
- fuer v1 werden Gruppen serverseitig in Einzelzuordnungen expandiert
|
|
- laufende Kampagnen werden bei spaeteren Gruppenänderungen nicht automatisch neu berechnet
|
|
- falls das spaeter anders gewuenscht ist, braucht es ein bewusstes Reconciliation-Konzept
|
|
|
|
## 6. API-Fehlermodell
|
|
|
|
### Frage
|
|
|
|
Wie sehen konsistente API-Fehlerantworten aus?
|
|
|
|
### Entscheidung
|
|
|
|
Ein gemeinsamer Fehlerumschlag fuer alle API-Endpunkte.
|
|
|
|
Beispiel:
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"code": "screen_not_found",
|
|
"message": "Screen existiert nicht",
|
|
"details": null
|
|
}
|
|
}
|
|
```
|
|
|
|
### Konsequenz
|
|
|
|
- Backend, Frontends und Player koennen Fehler einheitlich behandeln
|
|
- Logging und Monitoring werden einfacher
|
|
|
|
## Ergebnis fuer v1
|
|
|
|
1. `message_wall` wird serverseitig aufgeloest
|
|
2. Provisionierungs-Secrets werden kurzlebig und verschluesselt referenziert gespeichert
|
|
3. ACK-Timeouts werden vom Worker ausgewertet und setzen Kommandos auf `expired`
|
|
4. Provisionierung wird worker-basiert und jumperfaehig geplant
|
|
5. `playlist_items.screen_id` wird im finalen Schema entfernt
|
|
6. Gruppen werden bei Kampagnen in Einzel-Assignments expandiert
|
|
7. API-Fehler verwenden einen einheitlichen Fehlerumschlag
|