- ScreenScheduleStore.Upsert: override_on_until aus INSERT und ON CONFLICT
entfernt — verhindert stillen Datenverlust beim Speichern eines Zeitplans.
SetOverrideOnUntil bleibt alleinig zuständig für diese Spalte.
- README.md: GlobalOverrideStore, vier neue API-Routen, Wochenend-Sperre
und Migration 006_override.sql dokumentiert.
- override.go: Auth-Scope-Kommentar über HandleSetGlobalOverride ergänzt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ScheduleStore in RouterDeps, HandleUpdateSchedule-Handler, Scheduler-Goroutine
in app.Run(), ScreenStore.GetByID hinzugefügt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- playerstatus: look up screen by slug before UpsertDisplayState to pass UUID (not slug) and avoid FK violation
- router: switch display command route from authOnly to authScreen for proper permission enforcement
- display.go: remove redundant GetBySlug + requireScreenAccess (now handled by authScreen middleware), drop store dependency
- notifier: replace fmt.Sprintf %q with json.Marshal for correct JSON encoding of display command payload
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Template-Funktion `orientationLabel` in tenant/tenant.go ergänzt (fehlte nach UI-Refactoring)
- `depends_on: mosquitto` aus compose/server-stack.yml entfernt (Service ist auskommentiert)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server gibt bei POST /api/v1/player/status jetzt mqtt-Block zurück (broker,
username, password) wenn MORZ_INFOBOARD_MQTT_BROKER gesetzt ist. Agents
parsen die Response und verbinden sich bei Config-Änderung automatisch neu
(applyMQTTConfig mit Reconnect-Logik, thread-safe via Mutex).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- HandleManageUI übergibt CSRFToken korrekt ans Template (leeres Hidden-Field
blockierte JS-Inject-Snippet)
- HandleTenantDashboard setzt CSRF-Cookie und befüllt CSRFToken in Template-Daten
- tenant/csrf_helpers.go: setCSRFCookie im tenant-Package (Import-Cycle-Isolation)
- Logout-Formular in tenantDashTmpl hat jetzt statisches CSRF-Hidden-Field
- Doku: POST /logout und POST /login mit CSRF-Anforderungen dokumentiert
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
printf "%q" im Go-Template erzeugte Go-quoted Strings ("..."), die als
Teil der screen_id an die DB übergeben wurden. FK-Constraint schlug fehl,
weil die ID mit eingebetteten Quotes keiner screens-Zeile entsprach.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fehlende slog.Error-Aufrufe in HandleAddUserToScreen, HandleCreateScreenUser,
HandleDeleteScreenUser und HandleRemoveUserFromScreen ergänzt — DB-Fehler
wurden bisher komplett geschluckt und waren nicht diagnostizierbar.
Tenant-Lookup in EnsureAdminUser und CreateScreenUser aus SQL-Subqueries
in eigene Queries extrahiert für bessere Fehlermeldungen bei fehlendem Tenant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HandleLoginPost renderte Fehlerseiten (falsches Passwort, leere Felder) ohne
CSRFToken in den Template-Daten. Das hidden field <csrf_token> war leer, sodass
jeder weitere Submit-Versuch mit "Ungültiger CSRF-Token" scheiterte.
Fix: setCSRFCookie am Anfang des Handlers aufrufen und das Token in allen
renderError-Pfaden an das Template übergeben.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Neue Rolle screen_user: User können sich einloggen und nur ihre
zugeordneten Bildschirme verwalten. Admins behalten vollen Zugriff.
- Migration 003: users.role-Spalte + user_screen_permissions (M:N)
- Store: CreateScreenUser, ListScreenUsers, DeleteUser,
GetAccessibleScreens, HasUserScreenAccess,
AddUserToScreen, RemoveUserFromScreen, GetScreenUsers
- Middleware: RequireScreenAccess enforces screen-level access
für alle /manage/{screenSlug}-Routen
- 4 neue Admin-Handler: CreateScreenUser, DeleteScreenUser,
AddUserToScreen, RemoveUserFromScreen (+4 Routes)
- Admin-UI: Tab "Benutzer" (anlegen/löschen) + Screen-User-Modal
(User zuordnen/entfernen) direkt in der Bildschirm-Tabelle
- Login: screen_user wird nach Login zum ersten zugänglichen Screen
weitergeleitet; kein Zugang zu /admin
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Admin users continue to redirect to /manage/ as before. Tenant users
now land on their own dashboard at /tenant/{slug}/dashboard instead of
the incorrect /manage/{slug} path. The fix applies to both the
already-logged-in check in HandleLoginUI and the post-login switch in
HandleLoginPost.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Backend published auf signage/screen/{slug}/playlist-changed nach
Playlist-Mutationen (2s Debounce). Agent subscribed und fetcht
Playlist sofort (3s Debounce). 60s-Polling bleibt als Fallback.
Neue Packages: mqttnotifier (Backend), mqttsubscriber (Agent)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>