Commit graph

21 commits

Author SHA1 Message Date
Jesko Anschütz
b4f36639bf fix(kiosk): Chromium-Stop beschleunigen (90s → 10s)
Chromium reagiert im Kiosk-Modus nicht auf SIGTERM, sodass systemd
90 Sekunden auf den TimeoutStop wartete und dann SIGKILL senden musste.
ExecStop killt Chromium jetzt explizit per pkill, TimeoutStopSec=10.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 16:06:10 +02:00
Jesko Anschütz
522f15c3cd fix(ansible): cloud-init deinstallieren und Verzeichnisse entfernen 2026-03-27 22:10:19 +01:00
Jesko Anschütz
3c7f5ce725 fix(ansible): network-online.target entfernen, network.target reicht 2026-03-27 22:09:27 +01:00
Jesko Anschütz
4996ff6def feat(ansible): agent-Build unterstützt armv7 (Raspi 2) via agent_goarch/agent_goarm
Build-Task in signage_player/tasks/main.yml aufgeteilt: ohne GOARM (default arm64,
bestehende Hosts unverändert) und mit GOARM für armv7-Hosts. Neue host_vars und
Inventory-Einträge für raspi2a und raspi2b (Platzhalterwerte, TODO-Kommentare).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 21:08:06 +01:00
Jesko Anschütz
96135266f1 fix(ansible): DPMS aktivieren für Display-Steuerung 2026-03-26 23:31:00 +01:00
Jesko Anschütz
37a56903f2 Set Chromium to allow third-party cookies 2026-03-26 18:48:05 +01:00
Jesko Anschütz
15fe9580f7 feat(ansible): info11-dev und info12-dev auf infoscreen.morz.de zeigen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:35:31 +01:00
Jesko Anschütz
b3fd512d25 feat(deploy): manuelles Deploy-Verzeichnis für dockerbox.morz.de
- deploy/docker-compose.yml: Produktions-Stack (Backend, Postgres, Mosquitto)
  Backend bindet nur auf 127.0.0.1:8080 (HTTPS via Reverse Proxy)
- deploy/.env.example: Vorlage für Produktions-Umgebungsvariablen
- deploy/mosquitto/config/mosquitto.conf: Mosquitto mit Passwort-Auth
- ansible/group_vars: morz_server_base_url auf https://dockerbox.morz.de
- ansible/inventory.yml: debi entfernt, dev-Hosts info11/info12 ergänzt
- .gitignore: !.env.example als Ausnahme ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 17:36:39 +01:00
Jesko Anschütz
cfc450a9e7 fix(ansible): DISPLAY und XAUTHORITY im morz-agent-Service setzen
scrot braucht X11-Zugang für Screenshots. Der systemd-Service hatte
keine DISPLAY-Variable, weshalb alle Screenshot-Versuche fehlschlugen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 16:44:55 +01:00
Jesko Anschütz
15c159456a fix(ansible): Screenshot-Dependencies und MQTT-Variablennamen korrigieren
scrot, imagemagick und x11-apps werden jetzt automatisch auf allen
signage_players installiert. Außerdem MQTT_USER/PASS in compose auf
MQTT_USERNAME/PASSWORD korrigiert (passt zu den Backend-Env-Var-Namen).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 16:22:52 +01:00
Jesko Anschütz
1357dbe773 fix(ansible): morz-agent nach Binary-Build neu starten
go build hatte changed_when: true aber kein notify — Handler wurde
nie ausgelöst, neues Binary blieb ohne Dienst-Neustart wirkungslos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 14:43:43 +01:00
Jesko Anschütz
b73da77835 feat(screens): Screen-Übersicht mit On-Demand-Screenshots für Multi-Screen-User
- GET /manage: neue Übersichtsseite mit Bulma-Karten für screen_user mit ≥2 Screens
- handleScreenUserRedirect leitet bei ≥2 Screens auf /manage statt auf ersten Screen
- On-Demand-Screenshot-Flow via MQTT:
  - Backend publiziert signage/screen/{slug}/screenshot-request beim Seitenaufruf
  - Player-Agent empfängt Topic, ruft TakeAndSendOnce() auf
  - Player POST /api/v1/player/screenshot → Backend speichert in ScreenshotStore (RAM)
  - GET /api/v1/screens/{screenId}/screenshot liefert gespeichertes Bild (authOnly)
- ScreenshotStore: In-Memory, thread-safe, kein Persistenz-Overhead
- JS-Retry nach 4s in Templates (Screenshot braucht 1-3s für MQTT-Roundtrip)
- manageTmpl zeigt Screenshot-Thumbnail beim Einzelscreen-Aufruf
- Doku: neue Endpoints, MQTT-Topics, Screenshot-Flow in SERVER-KONZEPT.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 14:27:10 +01:00
Jesko Anschütz
dd3ec070f7 Security-Review + Phase 6: CSRF, Rate-Limiting, Tenant-Isolation, Screenshot, Ansible
### Security-Fixes (K1–K6, W1–W4, W7, N1, N5–N6, V1, V5–V7)
- K1: CSRF-Schutz via Double-Submit-Cookie (httpapi/csrf.go + csrf_helpers.go)
- K2: requireScreenAccess() in allen manage-Handlern (Tenant-Isolation)
- K3: Tenant-Check bei DELETE /api/v1/media/{id}
- K4: requirePlaylistAccess() + GetByItemID() für JSON-API Playlist-Routen
- K5: Admin-Passwort nur noch als [gesetzt] geloggt
- K6: POST /api/v1/screens/register mit Pre-Shared-Secret (MORZ_INFOBOARD_REGISTER_SECRET)
- W1: Race Condition bei order_index behoben (atomare Subquery in AddItem)
- W2: Graceful Shutdown mit 15s Timeout auf SIGTERM/SIGINT
- W3: http.MaxBytesReader (512 MB) in allen Upload-Handlern
- W4: err.Error() nicht mehr an den Client
- W7: Template-Execution via bytes.Buffer (kein partial write bei Fehler)
- N1: Rate-Limiting auf /login (5 Versuche/Minute pro IP, httpapi/ratelimit.go)
- N5: Directory-Listing auf /uploads/ deaktiviert (neuteredFileSystem)
- N6: Uploads nach Tenant getrennt (uploads/{tenantSlug}/)
- V1: Upload-Logik konsolidiert in internal/fileutil/fileutil.go
- V5: Cookie-Name als Konstante reqcontext.SessionCookieName
- V6: Strukturiertes Logging mit log/slog + JSON-Handler
- V7: DB-Pool wird im Graceful-Shutdown geschlossen

### Phase 6: Screenshot-Erzeugung
- player/agent/internal/screenshot/screenshot.go erstellt
- Integration in app.go mit MORZ_INFOBOARD_SCREENSHOT_EVERY Config

### UX: PDF.js Integration
- pdf.min.js + pdf.worker.min.js als lokale Assets eingebettet
- Automatisches Seitendurchblättern im Player

### Ansible: Neue Rollen
- signage_base, signage_server, signage_provision erstellt
- inventory.yml und site.yml erweitert

### Konzept-Docs
- GRUPPEN-KONZEPT.md, KAMPAGNEN-AKTIVIERUNG.md, MONITORING-KONZEPT.md
- PROVISION-KONZEPT.md, TEMPLATE-EDITOR.md, WATCHDOG-KONZEPT.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 21:06:35 +01:00
Jesko Anschütz
f11bd4f6c4 Bugfixes: Player-UI Content-Rendering, Backend-URL Dev-Display, MIME-Type-Erkennung
- Player-UI: Content-Type-Handling (image/video/web statt alles-iframe),
  Fast-Retry-Polling beim Start, Splash wird korrekt ausgeblendet,
  Fallback-Anzeige bei X-Frame-Options-Blockade
- Dev-Display: Backend-URL auf 192.168.64.1 für Multipass-Netz korrigiert
- Media-Upload: Typ wird aus MIME-Type abgeleitet statt blind aus Formular
- TODO: Daten-Bug dokumentiert

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 10:50:17 +01:00
Jesko Anschütz
e03948f25d Kopplung Agent↔Backend: Selbstregistrierung + Playlist-Rotation
Backend:
- ScreenStore.Upsert(): idempotentes INSERT ON CONFLICT für Self-Registration
- POST /api/v1/screens/register: Agent registriert sich beim Start (upsert)
- manage/register.go: neuer Handler, immer unter Tenant "morz"

Agent:
- config: screen_name + screen_orientation (mit Fallback auf screen_id / landscape)
- app.go: registerScreen() — POST /api/v1/screens/register beim Start (Retry 30s)
- app.go: pollPlaylist() — GET /api/v1/screens/{slug}/playlist alle 60s
- app.go: nowFn liefert Playlist statt statischer URL; PlayerContentURL als Fallback
- playerserver: PlaylistItem-Struct in NowPlaying; JS rotiert Items per duration_seconds
- JS: Playlist-Fingerprint verhindert Reset laufender Rotation bei unverändertem Stand

Ansible:
- config.json.j2: screen_name + screen_orientation ergänzt
- host_vars/info10: screen_name + screen_orientation
- host_vars/info01-dev: screen_name + screen_orientation

Kopplung per Konvention: screen_id (config.json) = slug (DB)
Beim ersten Neustart der Agents erscheinen die Bildschirme automatisch im Admin-UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 05:57:58 +01:00
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
Jesko Anschütz
d461abc3f5 Reduziere SD-Karten-Schreiblast: leiser Agent + journald volatile
- Agent loggt im Normalfall nichts mehr (kein heartbeat_tick, kein
  mqtt_heartbeat_sent, kein status_report_sent)
- nur noch Fehler und Zustandsaenderungen werden geloggt
- Ansible: journald auf Storage=volatile + RuntimeMaxUse=20M (RAM-only,
  automatisches Verdraengen alter Eintraege bei vollem Puffer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:13:23 +01:00
Jesko Anschütz
b111cf8421 Fuege Ansible-Rolle signage_player fuer Agent-Deployment hinzu
- Rolle signage_player: baut Binary lokal (linux/arm64), deployt es,
  schreibt config.json per Template, installiert und aktiviert systemd-Unit
- inventory.yml mit Host info10 (10.0.0.200)
- group_vars/signage_players: getrennte vars.yml (oeffentlich) und
  vault.yml (Secrets, gitignored) fuer MQTT-Credentials
- host_vars/info10: ansible_host, ansible_user, screen_id
- site.yml zeigt auf signage_players-Gruppe und signage_player-Rolle
- Binaries und vault.yml in .gitignore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:09:54 +01:00
Jesko Anschütz
bf993a5945 Baue Layout-Resolver und lokale Entwicklungsgerueste aus 2026-03-22 16:03:21 +01:00
Jesko Anschütz
6a65505304 Lege Entwicklungsleitfaden und Go-Gerueste an 2026-03-22 13:42:00 +01:00
Jesko Anschütz
3dc82bf4f7 Ergaenze Player- und Serverkonzept 2026-03-22 13:10:09 +01:00