morz-infoboard/DEVELOPMENT.md
Jesko Anschütz 029fa39ffd Dokumentation: Security-Features und Upload-Konsolidierung (Phase 6)
Neue Packages und Module:
- fileutil: Shared Upload-Logik mit Tenant-Isolation
- httpapi/csrf.go: Double-Submit-Cookie CSRF-Schutz
- httpapi/ratelimit.go: Rate-Limiting für /login
- httpapi/uploads.go: neuteredFileSystem (kein Directory-Listing)
- httpapi/manage/csrf_helpers.go: CSRF-Helpers für Templates
- player/agent/internal/screenshot/screenshot.go: Periodische Screenshot-Erfassung

Neue Umgebungsvariablen:
- MORZ_INFOBOARD_REGISTER_SECRET: Pre-Shared-Secret für Agent-Registrierung
- MORZ_INFOBOARD_SCREENSHOT_EVERY: Screenshot-Intervall im Player-Agent (Sekunden)

Dokumentation aktualisiert:
- server/backend/README.md: Neue Packages und Env-Variable REGISTER_SECRET
- DEVELOPMENT.md: Beide neuen Env-Variablen mit Erklärungen
- docs/API-ENDPOINTS.md: Screenshot-Endpoint als "In Vorbereitung" dokumentiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 21:01:47 +01:00

394 lines
13 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`
- 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 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):
```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