morz-infoboard/DEVELOPMENT.md
Jesko Anschütz 8e0501a012 Doku: Screen-Usserverwaltung (Phase 8)
Aktualisiert Dokumentation für Screen-User Management nach Backy's Implementierung:

docs/SCHEMA.md:
- users.role erweitert: 'admin' | 'screen_user' | 'tenant'
- Neue Tabelle: user_screen_permissions (user_id, screen_id, created_at, unique constraint, FK mit CASCADE)
- AuthStore: CreateScreenUser, ListScreenUsers, DeleteUser
- ScreenStore: GetAccessibleScreens, HasUserScreenAccess, AddUserToScreen, RemoveUserFromScreen, GetScreenUsers

docs/API-ENDPOINTS.md:
- POST /admin/users — Screen-User anlegen
- POST /admin/users/{userID}/delete — Screen-User löschen
- POST /admin/screens/{screenID}/users — User zu Screen hinzufügen
- POST /admin/screens/{screenID}/users/{userID}/remove — User von Screen entfernen

server/backend/README.md:
- AuthStore und ScreenStore Methoden dokumentiert
- Middleware RequireScreenAccess erklärt
- Migration 003_user_screen_permissions.sql erwähnt

DEVELOPMENT.md:
- users.role Werte dokumentiert (admin, screen_user, tenant)

Co-Authored-By: Backy (Screen-User Implementation) <noreply@anthropic.com>
2026-03-23 22:07:32 +01:00

13 KiB
Raw Blame History

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
  • funktionales Go-Backend (server/backend) mit REST-API, PostgreSQL-Anbindung und Datenverwaltung
  • funktionaler Go-Agent (player/agent) mit Server-Registrierung, Playlist-Management und Heartbeat-Sync
  • vollstaendiger Compose-Stack in compose/server-stack.yml mit PostgreSQL, Mosquitto und Backend-Service

Noch nicht vorhanden:

  • produktives SSL/TLS-Handling fuer Deployment
  • Docker-Secret-Integration fuer MORZ_INFOBOARD_ADMIN_PASSWORD
  • Ansible-Variable morz_admin_password als Vault-Variable (Phase 6)

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:

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

cd server/backend
go build ./...

Agent bauen

cd player/agent
go build ./...

Alternativ ueber Makefile

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

Lokale Entwicklung mit Login

Seit der Implementierung des Tenant-Features ist das Backend durch eine Session-basierte Authentifizierung geschuetzt. Fuer den lokalen Entwicklungsbetrieb muessen zwei zusaetzliche Umgebungsvariablen gesetzt werden:

  • MORZ_INFOBOARD_ADMIN_PASSWORD legt das Passwort des initialen Admin-Users fest. Beim Backend-Start wird automatisch ein User admin angelegt (bzw. dessen Passwort aktualisiert), der dem Standard-Tenant morz zugeordnet ist. Bleibt die Variable leer, wird kein Admin angelegt und der Login-Bereich ist nicht nutzbar.
  • MORZ_INFOBOARD_DEV_MODE setzt das Session-Cookie ohne das Secure-Flag, sodass er auch ueber unverschluesseltes HTTP (lokales localhost) uebertragen wird. Ohne dieses Flag wird der Cookie nur ueber HTTPS gesetzt und der Login schlaegt im lokalen Betrieb still fehl.

Empfohlener Start fuer die lokale Entwicklung:

cd server/backend
MORZ_INFOBOARD_ADMIN_PASSWORD=dev \
MORZ_INFOBOARD_DEV_MODE=true \
go run ./cmd/api

Danach ist der Login unter http://localhost:8080/login mit admin / dev erreichbar.

Hinweis: MORZ_INFOBOARD_DEV_MODE=true darf niemals in einer produktiven Umgebung gesetzt werden, da der Cookie dort ausschliesslich ueber HTTPS uebertragen werden soll.


Lokaler Start

Backend lokal starten

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
  • MORZ_INFOBOARD_ADMIN_PASSWORD Passwort fuer den initialen Admin-User (leer = kein EnsureAdminUser-Lauf)
  • MORZ_INFOBOARD_DEFAULT_TENANT Slug des Standard-Tenants, dem der Admin-User zugeordnet wird (Standard: morz)
  • MORZ_INFOBOARD_REGISTER_SECRET Pre-Shared-Secret fuer POST /api/v1/screens/register; leer = offen fuer alle
  • MORZ_INFOBOARD_DEV_MODE wenn true: Session-Cookie wird ohne Secure-Flag gesetzt (nur fuer lokale Entwicklung)

Hinweis zu users.role:

  • admin — hat Zugriff auf alle Admin-Funktionen und Screens
  • screen_user — hat Zugriff nur auf Screens, fuer die explizit ein Eintrag in user_screen_permissions existiert
  • tenant — hat Zugriff auf alle Screens seines Tenants (veraltet, noch nicht vollstaendig implementiert)

Beispiele:

MORZ_INFOBOARD_HTTP_ADDR=:18080 go run ./cmd/api
MORZ_INFOBOARD_HTTP_ADDR=:8080 \
MORZ_INFOBOARD_STATUS_STORE_PATH=/tmp/screen-status.json \
go run ./cmd/api

Agent lokal starten

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_REGISTER_SECRET Pre-Shared-Secret fuer Selbstregistrierung; muss mit Server-Konfiguration uebereinstimmen
  • MORZ_INFOBOARD_SCREENSHOT_EVERY Intervall fuer periodische Screenshots in Sekunden (z.B. 300 fuer 5 Minuten; 0 oder leer = deaktiviert)
  • 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:

MORZ_INFOBOARD_SCREEN_ID=info01-dev \
MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080 \
go run ./cmd/agent

Beispiel mit MQTT:

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:

ansible-vault create ansible/group_vars/signage_players/vault.yml

Inhalt:

vault_mqtt_username: "benutzername"
vault_mqtt_password: "passwort"

In vars.yml referenzieren:

morz_mqtt_username: "{{ vault_mqtt_username }}"
morz_mqtt_password: "{{ vault_mqtt_password }}"

Deployment ausfuehren

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

Die Punkte 14 der urspruenglichen Liste (Fehlerformat, Routing, Status, MQTT) sind umgesetzt. Offene Punkte aus Phase 6 des Tenant-Feature-Plans (docs/TENANT-FEATURE-PLAN.md):

  1. Docker-Secret fuer MORZ_INFOBOARD_ADMIN_PASSWORD in compose/ einrichten
  2. Ansible-Variable morz_admin_password als Vault-Variable definieren
  3. Code-Review durch Larry (SQL-Injection, Session-Fixation, bcrypt-Cost, Middleware-Reihenfolge)
  4. End-to-End-Test-Checkliste in docs/TEST-CHECKLIST-DEV.md durchlaufen
  5. Deployment: Image bauen, Migration 002_auth.sql pruefen, Logs kontrollieren
  6. Langfristig: Netzwerk-, Sync- und Kommandopfade produktionsnah ausbauen

End-to-End-Entwicklungstest (Backend + Agent)

Backend und Agent koennen lokal gegeneinander laufen. Reihenfolge:

  1. Backend starten (Terminal 1):
cd server/backend
MORZ_INFOBOARD_STATUS_STORE_PATH=/tmp/screen-status.json go run ./cmd/api
  1. Agent starten (Terminal 2):
cd player/agent
MORZ_INFOBOARD_SCREEN_ID=info01-dev \
MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080 \
go run ./cmd/agent
  1. Status pruefen:
# 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:

Backend-REST-API (statusseite.py, playerstatus.go, messagewall.go):

  • message_wall-Resolver im Backend fuer Szenen-Aufloesung
  • Basisendpunkte und message_wall-Validierung im Backend testseitig breiter abgedeckt
  • POST /api/v1/player/status mit Laufzeit-, Stale- und Server-Konnektivitaets-Tracking
  • Player-Status wird im Backend pro Screen in-memory vorgehalten und ueber Endpunkte lesbar gemacht
  • GET /api/v1/screens/status fuer Gesamt-Uebersicht mit Query-Filtern
  • GET /api/v1/screens/{screenId}/status fuer Einzelscreen-Details
  • DELETE /api/v1/screens/{screenId}/status zum Loeschen von Screen-Eintraegen
  • HTML-Diagnoseseite unter /status mit Auto-Refresh, Filterung und JSON-Drill-down
  • Query-Parameter: q= (Screen-ID-Substring), derived_state=, server_connectivity=, stale=, updated_since=, limit=
  • derived_state (online / degraded / offline) aus stale, server_connectivity und status abgeleitet
  • JSON-Persistenz optional in Datei (MORZ_INFOBOARD_STATUS_STORE_PATH)

Backend-Datenverwaltung (manage/register.go, manage/playlist.go, manage/media.go):

  • PostgreSQL-Anbindung mit DATABASE_URL-Konfiguration
  • Agent-Selbstregistrierung ueber POST /api/v1/manage/register
  • Playlist-Verwaltung und -Abruf (GET /api/v1/manage/playlists/...)
  • Medien-Upload und Speicherverwaltung in MORZ_INFOBOARD_UPLOAD_DIR
  • Admin-UI mit HTML-Templates fuer Playlist und Medien-Management

Agent-Funktionalitaeten (player/agent/):

  • dateibasierte Agent-Konfiguration (config.json) zusaetzlich zu Env-Overrides
  • strukturierte Agent-Logs mit internem Health-Snapshot und signalgesteuertem Shutdown
  • periodischer HTTP-Status-Reporter fuer Server-Registrierung
  • Server-Connectivity-Zustand (unknown, online, degraded, offline)
  • HTTP-Statuspfad transportiert status und server_connectivity
  • MQTT-Heartbeat (optional; wird uebersprungen wenn kein Broker konfiguriert)
  • MQTT-Authentifizierung mit Username und Password
  • Player-UI unter /player (HTML-Kiosk) und /api/now-playing (JSON)
  • Playlist-Rotation und lokale Playlist-Verwaltung

Infrastruktur und Deployment:

  • vollstaendiger Compose-Stack (compose/server-stack.yml) mit PostgreSQL 17, Mosquitto, Backend-Service und Health-Checks
  • Ansible-Rollen signage_player und signage_display fuer vollstaendiges Deployment
  • journald auf volatile Storage konfiguriert (SD-Karte schonen)
  • Cross-Compile fuer ARM64 im Ansible-Playbook
  • systemd-Units fuer Agent und Kiosk-Display

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