Triff verbindliche Architekturentscheidungen
This commit is contained in:
parent
ae183d399e
commit
7befa61805
7 changed files with 246 additions and 1 deletions
|
|
@ -20,6 +20,7 @@ Die Trennung von `/srv/docker/infoboard-netboot` ist sinnvoll, damit:
|
|||
- Provisionierungskonzept: `docs/PROVISIONIERUNGSKONZEPT.md`
|
||||
- Player-Konzept: `docs/PLAYER-KONZEPT.md`
|
||||
- Server-Konzept: `docs/SERVER-KONZEPT.md`
|
||||
- Offene Architekturfragen: `docs/OFFENE-ARCHITEKTURFRAGEN.md`
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
|
|
|
|||
6
TODO.md
6
TODO.md
|
|
@ -19,6 +19,8 @@
|
|||
- [ ] Kommandokatalog fuer Admin-Aktionen finalisieren
|
||||
- [ ] Template- und Kampagnenmodell fuer globale monitoruebergreifende Uebersteuerung finalisieren
|
||||
- [ ] Prioritaetsregel `campaign > tenant_playlist > fallback` verbindlich festschreiben
|
||||
- [x] Entscheidung dokumentieren, dass `playlist_items.screen_id` entfernt wird
|
||||
- [x] Entscheidung dokumentieren, dass Gruppen bei Kampagnen serverseitig in Einzel-Assignments expandiert werden
|
||||
|
||||
## Phase 2 - Technische Zielarchitektur
|
||||
|
||||
|
|
@ -32,6 +34,10 @@
|
|||
- [ ] 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
|
||||
- [x] API-Fehlermodell und gemeinsame Fehlerantworten festlegen
|
||||
- [x] ACK-Timeout-Strategie fuer `device_command` festlegen
|
||||
- [x] `message_wall`-Rendering serverseitig verbindlich entscheiden
|
||||
- [x] Netzwerktopologie fuer SSH-basierte Erstprovisionierung als Worker-/Jumphost-faehiges Modell festlegen
|
||||
|
||||
## Phase 3 - Player-Design
|
||||
|
||||
|
|
|
|||
177
docs/OFFENE-ARCHITEKTURFRAGEN.md
Normal file
177
docs/OFFENE-ARCHITEKTURFRAGEN.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# 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
|
||||
|
|
@ -26,6 +26,12 @@ Technische Leitlinie:
|
|||
- Jobrunner fuehrt SSH-/Ansible-Schritte aus
|
||||
- Ergebnis wird protokolliert und in der UI sichtbar gemacht
|
||||
|
||||
Verbindliche Betriebsannahme:
|
||||
|
||||
- der Provisionierungs-Worker muss das Zielgeraet per SSH erreichen koennen
|
||||
- falls die Player in getrennten Netzen stehen, ist ein Jumphost- oder Routing-Konzept erforderlich
|
||||
- die Provisionierung wird so gebaut, dass ein separater Worker oder Jumphost unterstuetzt wird
|
||||
|
||||
## Eingaben fuer einen neuen Screen
|
||||
|
||||
Mindestens erforderlich:
|
||||
|
|
@ -184,6 +190,12 @@ Regeln:
|
|||
- wenn Speicherung noetig ist, nur kurzlebig und stark geschuetzt
|
||||
- besser: nur Referenz auf temporären Secret-Speicher
|
||||
|
||||
Verbindliche v1-Loesung:
|
||||
|
||||
- separate kurzlebige Secret-Verwaltung
|
||||
- verschluesselte Speicherung mit App-Key
|
||||
- automatische Loeschung nach Jobabschluss oder TTL-Ablauf
|
||||
|
||||
### Verwaltung nach Erstinstallation
|
||||
|
||||
Nach erfolgreicher Provisionierung gilt:
|
||||
|
|
@ -251,6 +263,14 @@ Typische Fehlerfaelle:
|
|||
- Chromium oder X11 startet nicht
|
||||
- Player-Agent registriert sich nicht
|
||||
|
||||
## Verbindliche Vorgabe fuer den Betrieb
|
||||
|
||||
Vor der produktiven Einfuehrung ist umzusetzen oder zu klaeren:
|
||||
|
||||
- ob der Server selbst in allen relevanten Player-Netzen steht
|
||||
- ob ein dedizierter Provisionierungs-Worker in einem passenden Netz benoetigt wird
|
||||
- ob spaeter mehrere Standorte oder VLANs zu erwarten sind
|
||||
|
||||
Zu jedem Fehler soll sichtbar sein:
|
||||
|
||||
- Stage
|
||||
|
|
|
|||
|
|
@ -264,7 +264,6 @@ Spalten:
|
|||
```sql
|
||||
id uuid primary key
|
||||
playlist_id uuid not null references playlists(id) on delete cascade
|
||||
screen_id uuid not null references screens(id) on delete cascade
|
||||
media_asset_id uuid null references media_assets(id) on delete set null
|
||||
order_index integer not null
|
||||
type text not null
|
||||
|
|
@ -380,6 +379,7 @@ updated_at timestamptz not null
|
|||
Zweck:
|
||||
|
||||
- explizite Zielzuordnung einer Kampagne
|
||||
- Gruppen werden in v1 serverseitig in konkrete Screen-Zuordnungen expandiert
|
||||
|
||||
Spalten:
|
||||
|
||||
|
|
@ -539,3 +539,9 @@ Ein Playlist-Item ist aktiv, wenn:
|
|||
- Medienkonvertierung oder serverseitige Derivate
|
||||
- mehrere aktive Kampagnen mit Kollisionsregeln
|
||||
- Slot-Topologien fuer unterschiedlich grosse Wandsysteme
|
||||
|
||||
## Verbindliche Architekturentscheidungen fuer v1
|
||||
|
||||
- `playlist_items` enthalten keinen direkten `screen_id`-Fremdschluessel
|
||||
- Kampagnengruppen werden serverseitig in `template_assignments` auf konkrete Screens expandiert
|
||||
- `message_wall` wird nicht im Player segmentiert, sondern serverseitig aufbereitet
|
||||
|
|
|
|||
|
|
@ -231,6 +231,12 @@ Stattdessen:
|
|||
- dedizierter Worker/Jobrunnner arbeitet ihn ab
|
||||
- Fortschritt wird in DB gespeichert
|
||||
|
||||
Zusaetzlich fuer v1 festzulegen:
|
||||
|
||||
- ACK-Timeout-Handling fuer `device_commands` ueber Worker
|
||||
- Secret-Handling fuer Provisionierungs-Bootstrap ueber kurzlebige Secret-Referenzen
|
||||
- physische Netzposition des Workers fuer SSH-Erreichbarkeit als Betriebsparameter
|
||||
|
||||
## Docker-Compose-Zielbild
|
||||
|
||||
Sinnvolle Komponenten in `compose/`:
|
||||
|
|
@ -248,6 +254,22 @@ Sinnvolle Komponenten in `compose/`:
|
|||
- alle Admin-Kommandos auditieren
|
||||
- Tenant-Trennung strikt serverseitig erzwingen
|
||||
|
||||
## API-Fehlermodell
|
||||
|
||||
Vor Implementierungsbeginn gilt ein einheitlicher Fehlerumschlag.
|
||||
|
||||
Empfehlung:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "screen_not_found",
|
||||
"message": "Screen existiert nicht",
|
||||
"details": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Zielstruktur im Repo
|
||||
|
||||
Empfohlene Unterstruktur fuer den Server:
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ Technische Anforderungen:
|
|||
- definierte Zielgruppe von Screens
|
||||
- klare Zuordnung `welcher Ausschnitt auf welchem Screen`
|
||||
|
||||
Verbindliche Entscheidung fuer v1:
|
||||
|
||||
- serverseitige Aufloesung in konkrete Screen-Szenen statt playerseitiger Segmentberechnung
|
||||
- der Player erhaelt nur den fuer ihn fertigen Ausschnitt
|
||||
|
||||
### `full_screen_media`
|
||||
|
||||
Dieser Typ dient fuer ein identisches oder pro Zielgeraet passend skaliertes Vollbildmotiv.
|
||||
|
|
@ -275,3 +280,11 @@ Von Beginn an mitzudenken sind:
|
|||
- moegliche getrennte Assets fuer Portrait und Landscape
|
||||
|
||||
Damit ist die globale Orchestrierung ein tragender Bestandteil des Systems und kein nachtraeglicher Sonderbau.
|
||||
|
||||
## Verbindliche Vorgabe fuer v1
|
||||
|
||||
Vor der UI- und Render-Implementierung gilt:
|
||||
|
||||
- `message_wall` wird serverseitig in konkrete Zielinhalte aufgeloest
|
||||
- `layout_json` beschreibt die serverseitige Segmentlogik und Admin-Vorschau
|
||||
- Slots werden geometrisch serverseitig interpretiert, nicht im Player berechnet
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue