morz-infoboard/DEVELOPMENT.md
Jesko Anschütz bbcf0a1228 Baue Ebene 1: Player-UI, Kiosk-Display und vollstaendiges Ansible-Deployment
Player-UI (playerserver):
- Lokale Kiosk-Seite unter /player mit orientierungsgerechtem Splash-Bild
- Splash-PNGs (Portrait/Landscape) eingebettet via go:embed
- Unteres-Drittel-Overlay mit erweiterbaren Sysinfo-Items (Hostname, Uptime)
- /api/now-playing und /api/sysinfo JSON-Endpunkte
- iframe-Overlay fuer spaetere Inhalts-URL

Ansible-Rolle signage_display (neu):
- Pakete: xserver-xorg-core, xinit, openbox, chromium, unclutter
- Kiosk-Skript mit openbox als WM (noetig fuer korrektes --kiosk-Vollbild)
- systemd-Unit mit Conflicts=getty@tty1 (behebt TTY-Blockierung beim Start)
- Chromium Managed Policy: TranslateEnabled=false, Notifications/Geolocation blockiert
- --lang=de Flag gegen Sprachauswahl-Dialog

Ansible-Rolle signage_player (erweitert):
- Legt signage_user an falls nicht vorhanden
- PlayerListenAddr und PlayerContentURL in Konfiguration
- journald volatile Storage (SD-Karten-Schonung)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 22:34:16 +01:00

348 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Info-Board Neu - Entwicklung
## Ziel
Dieses Dokument soll den Einstieg auf einem anderen Entwicklungsrechner moeglichst reibungsfrei machen.
Es beschreibt:
- minimale Voraussetzungen
- wichtige Verzeichnisse
- Build- und Run-Kommandos
- aktuelle Annahmen fuer den lokalen Entwicklungsbetrieb
## Repository
- Remote: `git.az-it.net:az/morz-infoboard.git`
- Standard-Branch: `main`
Projektwurzel:
- `/srv/docker/info-board-neu`
## Wichtige Verzeichnisse
- `docs/` fuer Architektur- und Fachkonzepte
- `server/backend/` fuer das zentrale Go-Backend
- `player/agent/` fuer den Go-basierten Player-Agent
- `ansible/` fuer Deployment und Provisionierung
- `compose/` spaeter fuer den zentralen Server-Stack
## Aktueller Entwicklungsstand
Bereits vorhanden:
- fachliche Architektur- und Betriebskonzepte
- relationaler Schema-Entwurf in `docs/SCHEMA.md`
- erstes Go-Geruest fuer `server/backend`
- erstes Go-Geruest fuer `player/agent`
Noch nicht vorhanden:
- produktive API-Endpunkte mit Datenbankanbindung
- Player-Sync und Playlist-Management
- Compose-Stack fuer lokale Serverdienste (Grundgeruest liegt in `compose/`)
## Voraussetzungen auf dem Entwicklungsrechner
Mindestens empfohlen:
- `git`
- `go` in Version `1.24.x`
- `make`
Spaeter zusaetzlich sinnvoll:
- `docker` und `docker compose`
- `postgresql-client`
- `mosquitto-clients`
- `golangci-lint`
Fuer Container-Builds liegen erste Dockerfiles in:
- `server/backend/Dockerfile`
- `player/agent/Dockerfile`
## Schnellstart
Repository klonen:
```bash
git clone git.az-it.net:az/morz-infoboard.git
cd morz-infoboard
```
Dokumentationsbasis lesen:
1. `README.md`
2. `PLAN.md`
3. `TECH-STACK.md`
4. `docs/SCHEMA.md`
5. `docs/OFFENE-ARCHITEKTURFRAGEN.md`
6. `docs/LAYOUT-JSON.md`
## Build-Kommandos
### Backend bauen
```bash
cd server/backend
go build ./...
```
### Agent bauen
```bash
cd player/agent
go build ./...
```
### Alternativ ueber Makefile
```bash
make build
```
Aktuell bedeutet das:
- `make build` baut Backend und Agent
- `make build-backend` baut nur `server/backend`
- `make build-agent` baut nur `player/agent`
- `make run-backend` startet das Backend
- `make run-agent` startet den Agenten
- `make fmt` formatiert beide Go-Module
- `make lint` prueft beide Go-Module mit `golangci-lint`
Hinweis:
- auf dem aktuellen System dieser Session sind `make` und `go` nicht installiert; die Befehle sind fuer den Entwicklungsrechner vorbereitet
## Lokaler Start
### Backend lokal starten
```bash
cd server/backend
go run ./cmd/api
```
Standard:
- HTTP-Adresse: `:8080`
- Health-Endpunkt: `GET /healthz`
- Basis-Endpunkt: `GET /api/v1`
Konfigurierbar ueber:
- `MORZ_INFOBOARD_HTTP_ADDR` HTTP-Adresse (Standard: `:8080`)
- `MORZ_INFOBOARD_STATUS_STORE_PATH` Pfad zur JSON-Datei fuer persistenten Status-Store; leer lassen fuer reinen In-Memory-Betrieb
Beispiele:
```bash
MORZ_INFOBOARD_HTTP_ADDR=:18080 go run ./cmd/api
```
```bash
MORZ_INFOBOARD_HTTP_ADDR=:8080 \
MORZ_INFOBOARD_STATUS_STORE_PATH=/tmp/screen-status.json \
go run ./cmd/api
```
### Agent lokal starten
```bash
cd player/agent
go run ./cmd/agent
```
Standardwerte:
- `MORZ_INFOBOARD_SCREEN_ID=unset-screen`
- `MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080`
- `MORZ_INFOBOARD_MQTT_BROKER=` (leer = MQTT wird uebersprungen)
- `MORZ_INFOBOARD_PLAYER_ADDR=127.0.0.1:8090`
- `MORZ_INFOBOARD_PLAYER_CONTENT_URL=` (leer = kein Inhalt eingebettet)
Optional:
- `MORZ_INFOBOARD_MQTT_USERNAME` MQTT-Benutzername
- `MORZ_INFOBOARD_MQTT_PASSWORD` MQTT-Passwort
- `MORZ_INFOBOARD_CONFIG=/etc/signage/config.json` dateibasierte Konfiguration
Eine Beispielkonfiguration liegt in `player/config/config.example.json`.
Der Agent stellt unter `http://127.0.0.1:8090/player` eine lokale Kiosk-Seite bereit.
Beispiel ohne MQTT:
```bash
MORZ_INFOBOARD_SCREEN_ID=info01-dev \
MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080 \
go run ./cmd/agent
```
Beispiel mit MQTT:
```bash
MORZ_INFOBOARD_SCREEN_ID=info01-dev \
MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080 \
MORZ_INFOBOARD_MQTT_BROKER=tcp://127.0.0.1:1883 \
MORZ_INFOBOARD_MQTT_USERNAME=user \
MORZ_INFOBOARD_MQTT_PASSWORD=pass \
go run ./cmd/agent
```
## Ansible-Deployment auf einen Zielrechner
Der `ansible/`-Ordner enthaelt ein vollstaendiges Playbook fuer das Deployment auf einen Pi oder ein Debian-System.
### Voraussetzungen
- Ansible auf dem Entwicklungsrechner
- SSH-Key fuer den Zielrechner hinterlegt
- Ansible Vault fuer MQTT-Zugangsdaten
### Inventory und Konfiguration
- `ansible/inventory.yml` Hosts und Gruppen
- `ansible/host_vars/<host>/vars.yml` host-spezifische Variablen (`screen_id`, `ansible_host`, `ansible_user`)
- `ansible/group_vars/signage_players/vars.yml` globale Defaults
- `ansible/group_vars/signage_players/vault.yml` verschluesselte Zugangsdaten (gitignored)
Vault-Datei anlegen:
```bash
ansible-vault create ansible/group_vars/signage_players/vault.yml
```
Inhalt:
```yaml
vault_mqtt_username: "benutzername"
vault_mqtt_password: "passwort"
```
In `vars.yml` referenzieren:
```yaml
morz_mqtt_username: "{{ vault_mqtt_username }}"
morz_mqtt_password: "{{ vault_mqtt_password }}"
```
### Deployment ausfuehren
```bash
cd ansible
ansible-playbook site.yml -i inventory.yml --ask-vault-pass
```
Das Playbook erledigt:
1. Agent-Binary cross-kompilieren (lokal, `GOOS=linux GOARCH=arm64`)
2. Binary und Konfiguration auf den Zielrechner uebertragen
3. systemd-Unit fuer den Agent anlegen und starten
4. journald auf RAM-Speicherung konfigurieren (SD-Karte schonen)
5. X11-Paketstack und Chromium installieren
6. Kiosk-Startskript und systemd-Unit fuer die Anzeige anlegen
### Rollen
- `signage_player` Agent, Konfiguration, systemd-Unit, journald
- `signage_display` X11, Chromium, Kiosk-Service
## Aktuelle Architekturentscheidungen mit direkter Auswirkung auf Entwicklung
- `message_wall` wird serverseitig in konkrete Screen-Szenen aufgeloest
- Kampagnengruppen werden serverseitig in konkrete Screen-Assignments expandiert
- `playlist_items` haben im finalen Implementierungsschema keinen direkten `screen_id`-Fremdschluessel
- Provisionierung wird worker-/jumphost-faehig geplant
- API-Fehler sollen einen einheitlichen Fehlerumschlag nutzen
## Empfohlene naechste Implementierungsschritte
1. Backend: einheitliches Fehlerformat und Routing-Grundstruktur anlegen
2. Backend: Konfigurations- und App-Lifecycle stabilisieren
3. Agent und Backend: den HTTP-Statuspfad als Grundlage fuer Identitaet, Persistenz und spaetere Admin-Vorschau erweitern
4. Agent: danach MQTT-spezifische Reachability und feinere Connectivity-Schwellenlogik aufsetzen
5. Danach die Netzwerk-, Sync- und Kommandopfade schrittweise produktionsnah ausbauen
## End-to-End-Entwicklungstest (Backend + Agent)
Backend und Agent koennen lokal gegeneinander laufen. Reihenfolge:
1. Backend starten (Terminal 1):
```bash
cd server/backend
MORZ_INFOBOARD_STATUS_STORE_PATH=/tmp/screen-status.json go run ./cmd/api
```
2. Agent starten (Terminal 2):
```bash
cd player/agent
MORZ_INFOBOARD_SCREEN_ID=info01-dev \
MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080 \
go run ./cmd/agent
```
3. Status pruefen:
```bash
# JSON-Uebersicht
curl http://127.0.0.1:8080/api/v1/screens/status
# HTML-Diagnoseseite
open http://127.0.0.1:8080/status
# Einzelner Screen
curl http://127.0.0.1:8080/api/v1/screens/info01-dev/status
# Screen loeschen
curl -X DELETE http://127.0.0.1:8080/api/v1/screens/info01-dev/status
```
Die Datei `/tmp/screen-status.json` enthaelt nach dem ersten Heartbeat den persistierten Status-Store.
## Ergaenzt seit dem ersten Geruest:
- `message_wall`-Resolver im Backend
- Basisendpunkte und `message_wall`-Validierung im Backend testseitig breiter abgedeckt
- erster `POST /api/v1/player/status`-Endpunkt im Backend
- letzter bekannter Player-Status wird im Backend pro Screen in-memory vorgehalten und lesbar gemacht
- Backend ergaenzt den Read-Pfad um `received_at` und eine einfache `stale`-Ableitung
- Backend bietet zusaetzlich eine kleine Uebersicht aller zuletzt meldenden Screens
- Backend validiert den Statuspfad jetzt enger auf erlaubte Lifecycle-/Connectivity-Werte und leitet `stale` aus dem gemeldeten Intervall ab
- Backend leitet im Read-Pfad zusaetzlich ein kompaktes `derived_state` fuer Diagnosekonsumenten ab
- Backend liefert unter `/status` eine erste sichtbare HTML-Diagnoseseite auf Basis derselben Statusdaten, inklusive Auto-Refresh, leichten Filtern und JSON-Drill-down
- Backend unterstuetzt `q=` (Screen-ID-Substring), `derived_state=`, `server_connectivity=`, `stale=`, `updated_since=`, `limit=` als Query-Filter
- Backend leitet `derived_state` (online / degraded / offline) aus `stale`, `server_connectivity` und `status` ab
- Backend erlaubt das Loeschen einzelner Screen-Eintraege via `DELETE /api/v1/screens/{screenId}/status`
- Backend persistiert den Status-Store optional in einer JSON-Datei (`MORZ_INFOBOARD_STATUS_STORE_PATH`)
- dateibasierte Agent-Konfiguration zusaetzlich zu Env-Overrides
- strukturierte Agent-Logs mit internem Health-Snapshot und signalgesteuertem Shutdown
- erster periodischer HTTP-Status-Reporter im Agent
- Server-Connectivity-Zustand im Agent (`unknown`, `online`, `degraded`, `offline`) auf Basis der Report-Ergebnisse
- der HTTP-Statuspfad transportiert jetzt neben `status` auch `server_connectivity`
- lokales Compose-Grundgeruest fuer PostgreSQL und Mosquitto
- MQTT-Heartbeat im Agent (optional; wird uebersprungen wenn kein Broker konfiguriert)
- MQTT-Authentifizierung mit Username und Password
- Player-UI im Agent (`/player` HTML-Kiosk, `/api/now-playing` JSON)
- Ansible-Rollen `signage_player` und `signage_display` fuer vollstaendiges Deployment
- journald auf volatile Storage konfiguriert (SD-Karte schonen)
## Arbeitsweise
Empfohlen:
- kleine, klar umrissene Commits
- zuerst Konzepte anpassen, dann Code
- Schema und API-Vertrag synchron halten
- neue Fachentscheidungen immer in `docs/` dokumentieren
## Hinweise fuer einen zweiten Entwicklungsrechner
- vor Arbeitsbeginn `git pull --rebase` oder gleichwertig den aktuellen Stand holen
- bei paralleler Arbeit zuerst in den Dokumenten pruefen, ob neue Architekturentscheidungen getroffen wurden
- falls lokale Tools abweichen, mindestens `go version` und `make --version` pruefen