# signage01 — Inbetriebnahme am Mini-PC

Kurz-Anleitung für das Digital-Signage-Gerät **signage01**. Server-Seite und API:
`docs/SYMFONY-INTEGRATION-SIGNAGE-DPOHL.md`. Verwaltung: `/signage`.

## Kenndaten

| | |
|---|---|
| Gerätekennung | `signage01` (muss so in der Verwaltung angelegt sein) |
| VPN (OpenVPN) | Tunnel-Adresse **`192.168.55.30`** |
| Erreichbares LAN | `192.168.1.0/24` über den Tunnel |
| Webserver (LAN) | `192.168.1.3` |
| Geräte-API | `https://dp-smartsolutions.de/ksbdueren/public/signage/api/v1` |
| Allowlist Server | `SIGNAGE_PLAYER_ALLOWED_IPS` = `192.168.55.0/24` (Absender = VPN-IP) |

Grundsatz: Die Webseite schickt keine Befehle. Das Gerät holt den Sollzustand ab
(`desired-state` alle ~15 s, Heartbeat alle ~30 s). Offline spielt es die zuletzt
übernommene Version weiter.

**Hinweis Sync-Modul:** Lokal laufen Zeitplan und Wiedergabe. Die **Server-Synchronisation
im Player** (Abruf der Geräte-API) muss im Player-Projekt noch gebaut bzw. aktiviert sein.
Ohne sie greifen Einrichtungscode und Veröffentlichungen auf dem Gerät nicht.

---

## 1. Vorbedingungen auf dem Server (erledigt, zur Kontrolle)

- [x] Deploy + Migration `Version20261026170000`
- [x] `ffmpeg` / `ffprobe` installiert
- [x] `shared/var/signage` beschreibbar für www-data
- [x] Gerät `signage01` in `/signage` angelegt
- [ ] Mindestens ein Video, eine Playlist, Standard-Playlist, **eine Veröffentlichung**
- [ ] Einrichtungscode erzeugt (siehe Schritt 3)

---

## 2. Netz und Name auf signage01

VPN muss verbunden sein. Test:

```bash
ping -c 2 192.168.1.3
ip -4 addr show | grep 192.168.55
# erwartet u. a. 192.168.55.30
```

**Hosts-Eintrag**, damit der API-Hostname zum öffentlichen Zertifikat passt, der Verkehr
aber über VPN/LAN geht (nicht über das öffentliche Internet):

```bash
# /etc/hosts — IP des Webservers aus Sicht des Tunnels
192.168.1.3   dp-smartsolutions.de
```

Prüfen:

```bash
getent hosts dp-smartsolutions.de
# → 192.168.1.3

curl -sI https://dp-smartsolutions.de/ksbdueren/public/signage/api/v1/player/desired-state | head -5
# ohne Token: 401 (Firewall/TLS ok)
# von außerhalb 192.168.55.0/24: 403
```

Erscheint im Apache-Access-Log eine andere Absender-IP als `192.168.55.30`
(NAT/Proxy), `SIGNAGE_PLAYER_ALLOWED_IPS` in `shared/.env.local` anpassen und Cache leeren.

---

## 3. Inhalte in der Verwaltung vorbereiten

Unter `https://dp-smartsolutions.de/ksbdueren/public/signage` (Rolle Signage: Inhalte/Admin):

1. **Medien** — Video hochladen, warten bis Prüfung (sha256 + ffprobe) durch ist.
2. **Playlists** — Playlist anlegen, Videos einreihen, Lautstärke 0–100.
3. Gerät **signage01** — Modus (meist `mirror`), **Standard-Playlist** setzen.
4. Optional: Kalender-Termine.
5. **Veröffentlichen** — erst danach gibt es eine `release_version` für den Player.
6. Am Gerät **Einrichtungscode erzeugen** (24 h gültig, **einmal** nutzbar, wird nur einmal angezeigt).

---

## 4. Gerät anmelden (enroll)

Einmalig, solange der Code gültig ist:

```http
POST https://dp-smartsolutions.de/ksbdueren/public/signage/api/v1/player/enroll
Content-Type: application/json

{
  "enrollment_code": "<CODE-AUS-VERWALTUNG>",
  "hostname": "signage01",
  "player_version": "0.1.0"
}
```

Erfolg **201**:

```json
{"device_id": "signage01", "token": "<geheim, 256 Bit>"}
```

- Token dauerhaft und geschützt speichern (nur Hash liegt auf dem Server).
- Einlösen widerruft alle bisherigen Tokens dieses Geräts.
- Ungültig / abgelaufen / schon benutzt → **403**.

Ab dann alle Aufrufe:

```http
Authorization: Bearer <token>
```

---

## 5. Laufender Betrieb (Player-Sync)

| Intervall | Aufruf | Zweck |
|---|---|---|
| ~15 s | `GET …/player/desired-state` | Soll-Version + Sofortaufträge (`ETag` / 304) |
| bei neuer Version | `GET …/player/releases/{version}` | Manifest unverändert |
| bei fehlenden Dateien | `GET …/player/media/{sha256}` | Download inkl. Range/`206` |
| ~30 s | `POST …/player/heartbeat` | Status; ohne Heartbeat 120 s → „nicht erreichbar“ in der UI |
| bei Sofortauftrag | `POST …/player/command-results` | `accepted` / `running` / `finished` / … |

Version wird erst aktiv, wenn Manifest und alle Medien vollständig und geprüft sind.
Fehler: alte Version bleibt, Meldung im nächsten Heartbeat / Geräteübersicht.

---

## 6. Schnelldiagnose

| Symptom | Prüfung |
|---|---|
| **403** auf `/signage/api/…` | Absender-IP nicht in Allowlist; VPN / `SIGNAGE_PLAYER_ALLOWED_IPS` |
| **401** | Token fehlt, falsch oder widerrufen → neuen Einrichtungscode |
| Keine neue Version am Gerät | In der UI veröffentlicht? Sync-Modul aktiv? Heartbeat sichtbar? |
| Zertifikatsfehler | Hosts zeigt wirklich `dp-smartsolutions.de` → `192.168.1.3`? |
| Upload hängt / 504 | PHP-FPM-/Proxy-Timeouts (Abschluss rechnet sha256 + ffprobe synchron) |

Access-Log (Webserver):

```bash
grep 'signage/api' /var/log/apache2/*access*.log | tail -20
```

In der Geräteübersicht nach dem ersten erfolgreichen Heartbeat: Adresse unter
„Letzte Rückmeldung … von“.

---

## 7. Checkliste Abnahme (Gerät)

- [ ] VPN oben, Ping `192.168.1.3` ok
- [ ] Hosts-Eintrag gesetzt, `curl` auf die API liefert 401 ohne Token
- [ ] Einrichtungscode eingelöst, Token gespeichert
- [ ] Veröffentlichung erscheint nach ≤ 15 s + Downloadzeit
- [ ] Geräteübersicht zeigt aktive Version erst nach Heartbeat
- [ ] VPN kurz trennen: Wiedergabe der letzten Version läuft weiter
- [ ] Token widerrufen: API 401, lokale Wiedergabe bleibt

Vollständige Abnahmeliste: Abschnitt 8 in `SYMFONY-INTEGRATION-SIGNAGE-DPOHL.md`.
