# 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:

```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

## 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:

```bash
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

```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
- `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)

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_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:

```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

Die Punkte 1–4 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):

```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:

**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
