# 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
