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>
394 lines
13 KiB
Markdown
394 lines
13 KiB
Markdown
# 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
|