Commit graph

22 commits

Author SHA1 Message Date
Jesko Anschütz
787287b328 fix(restricted): Display-Box ausblenden; Sidebar zeigt nur eigene Screens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 21:43:51 +01:00
Jesko Anschütz
03ea3edb8b feat(handler): HandleCreateScreenUser liest role; UserRole ans Template übergeben
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 21:34:21 +01:00
Jesko Anschütz
bb30a75f5a fix(ui): Admin sieht /manage mit allen Screens statt Redirect 2026-03-27 20:53:23 +01:00
Jesko Anschütz
fc94f56162 feat(ui): per-Screen-Override in Übersichtskarte und Detailseite
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 20:24:21 +01:00
Jesko Anschütz
c263d97cca feat(ui): Übersichtsseite – globaler Override-Banner
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 20:21:06 +01:00
Jesko Anschütz
6cabaeca58 feat(manage): Schedule in ManageUI-Template-Daten 2026-03-27 07:23:07 +01:00
Jesko Anschütz
2a312cd61a feat(manage): DisplayState je Screen in ScreenOverview 2026-03-27 07:05:06 +01:00
Jesko Anschütz
c4f15d862c feat(manage): DisplayState in ManageUI-Template-Daten 2026-03-27 07:04:54 +01:00
Jesko Anschütz
052cf199ae fix(manage): HandleReorder gibt 400 bei Mismatch zurück, slog für 500-Fehler 2026-03-26 22:29:48 +01:00
Jesko Anschütz
4fab5fe28a fix(manage): HandleReorderUI gibt 400 bei Mismatch zurück 2026-03-26 22:27:07 +01:00
Alwin
e1506d5d2c fix(manage): HandleUpdateItemUI returns 204 for fetch callers 2026-03-25 07:32:18 +00:00
Jesko Anschütz
47f65da228 fix(csrf): CSRF-Token für User-Logout in Manage- und Tenant-Dashboard
- 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>
2026-03-24 14:26:52 +01:00
Jesko Anschütz
c470ec532b fix(backend): Error-Logging in Screen-User-Handlern + Tenant-Lookup-Refactoring
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>
2026-03-23 23:41:16 +01:00
Jesko Anschütz
d1d86126c8 Feature: Screen-User-Verwaltung mit rollenbasiertem Zugriff
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>
2026-03-23 22:06:05 +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
ae5dfbd210 Tenant-Feature Phase 5: Kontextsensitiver BackLink in Manage-UI
- manageData: BackLink/BackLabel Felder ergänzt
- HandleManageUI: ?from=tenant → "← Dashboard", sonst "← Admin"
- manageTmpl: hardcoded "← Admin" durch {{.BackLabel}}/{{.BackLink}} ersetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 19:12:43 +01:00
Jesko Anschütz
27c4562175 Tenant-Feature Phase 3b: Login-Redirect + Tenant-Context in Manage-UI
- reqcontext-Package: shared contextKey für httpapi und manage
- Login-Redirect: Tenant-User → /manage/<slug>, Admin → /admin
- GetUserByUsername: LEFT JOIN tenants für TenantSlug-Befüllung
- manage/ui.go: reqcontext.UserFromContext statt hardcoded "morz"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:00:02 +01:00
Jesko Anschütz
585cb83ed0 MQTT-Playlist-Push: Änderungen erreichen Client binnen 5 Sekunden
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>
2026-03-23 11:35:50 +01:00
Jesko Anschütz
fa74ceb5d8 UX Block 3: Upload-Fortschritt, Toggle-Switch, vars.yml-Download
- Upload-Fortschrittsbalken per XHR mit Progress-Event
- Checkbox-Toggle statt Ja/Nein-Select für Enabled-Feld
- vars.yml Download-Button im Provisioning-Workflow
- Alle UX-Aufgaben in TODO.md abgehakt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 11:06:27 +01:00
Jesko Anschütz
883a8146c5 UX Block 1: Flash-Messages, Screen-Status, Responsive-Tabellen, Navbar-Burger
- Flash-Messages nach allen Manage-Aktionen (Upload, Löschen, Speichern, Hinzufügen)
- Screen-Online/Offline-Status als farbiger Punkt in Admin-Tabelle
- overflow-x Wrapper für alle Tabellen (Admin, Playlist, Medienbibliothek)
- Navbar-Burger für mobile Viewports in Admin und Manage
- UX-Gestaltungsplan als Sektion in TODO.md eingetragen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 10:55:15 +01:00
Jesko Anschütz
12c10f0337 Admin-UI: Bildschirm einrichten mit Ansible-Anleitung (Variante A)
- POST /admin/screens/provision: legt Screen in DB an (Upsert) und zeigt
  eine 5-Schritt-Seite mit kopierbaren Code-Blöcken:
  1. inventory.yml Eintrag
  2. host_vars/{slug}/vars.yml Inhalt
  3. ssh-copy-id Befehl
  4. ansible-playbook Befehl (mit Vault-Passwort-Hinweis)
  5. Link zur Playlist-Verwaltung
- Admin-Formular: IP-Adresse + SSH-User Felder ergänzt
- Altes "nur anlegen"-Formular als aufklappbaren Details-Block versteckt
- Clipboard-Copy-Buttons für jeden Code-Block

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 06:07:14 +01:00
Jesko Anschütz
803f355220 Baue Ebene 2: PostgreSQL-Backend, Medien-Upload und Playlist-UI
- DB-Package mit pgxpool, Migrations-Runner und eingebetteten SQL-Dateien
- Schema: tenants, screens, media_assets, playlists, playlist_items
- Store-Layer: alle Repositories (TenantStore, ScreenStore, MediaStore, PlaylistStore)
- JSON-API: Screens, Medien, Playlist-CRUD, Player-Sync-Endpunkt
- Admin-UI (/admin): Screens anlegen, löschen, zur Playlist navigieren
- Playlist-UI (/manage/{slug}): Drag&Drop-Sortierung, Item-Bearbeitung,
  Medienbibliothek, Datei-Upload (Bild/Video/PDF) und Web-URL
- Router auf RouterDeps umgestellt; manage-Routen nur wenn Stores vorhanden
- parseOptionalTime akzeptiert nun RFC3339 und datetime-local HTML-Format

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