### 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>
483 lines
17 KiB
Markdown
483 lines
17 KiB
Markdown
# Info-Board Neu - Aktivierungsoberflaeche fuer saisonale und temporaere Kampagnen
|
|
|
|
## Ziel
|
|
|
|
Die Aktivierungsoberflaeche ermoeglicht es dem Admin, Kampagnen zeitlich und gezielt auf Screens auszurollen — sofort oder geplant.
|
|
|
|
Dieses Dokument beschreibt:
|
|
|
|
- die Aktivierungs-Workflows im Admin-UI
|
|
- zeitgesteuerte Aktivierung (Scheduler)
|
|
- Screen-Zuordnung und Vorschau
|
|
- Status und Kontrolle waehrend der Laufzeit
|
|
|
|
Siehe auch `docs/TEMPLATE-EDITOR.md` fuer die Template-Verwaltung und `docs/TEMPLATE-KONZEPT.md` fuer konzeptionelle Grundlagen.
|
|
|
|
## 1. Aktivierungs-Workflows
|
|
|
|
### Workflow 1 — Schnelle Sofort-Aktivierung
|
|
|
|
**Szenario:** Admin hat ein Template und will es sofort starten.
|
|
|
|
**Weg:**
|
|
|
|
Admin → Templates → [Template] → "Aktivieren"
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ Kampagne starten: Weihnachtsmotiv 2025 │
|
|
├──────────────────────────────────────────┤
|
|
│ │
|
|
│ Kampagnen-Name (eindeutig) │
|
|
│ [ Weihnachten 2025 _________________] │
|
|
│ Vorschau: morz_campaign_xmas2025 │
|
|
│ │
|
|
│ Zielgruppe pruefen │
|
|
│ aus Template: Alle Screens (13) │
|
|
│ [Gruppe aendernx] [Screens aendernx] │
|
|
│ │
|
|
│ Dauer │
|
|
│ ⦿ Sofort starten │
|
|
│ gueltig ab jetzt │
|
|
│ ○ Geplant starten │
|
|
│ [Datum/Uhrzeit auswaehlen] │
|
|
│ │
|
|
│ Gueltig bis │
|
|
│ [Datum/Uhrzeit auswaehlen] │
|
|
│ oder [ ] unbegrenzt │
|
|
│ │
|
|
│ Prioritaet gegenueber Playlist │
|
|
│ [10____________] hoeher = wichtiger │
|
|
│ Standardwert: 1 │
|
|
│ │
|
|
│ Auto-Deaktivierung bei Ablauf? │
|
|
│ ⦿ Ja, danach Fallback zeigen │
|
|
│ ○ Nein, manuell deaktivieren │
|
|
│ │
|
|
│ Vorschau betroffener Screens │
|
|
│ [Screenshot-Vorschau mit Kampagnen- │
|
|
│ Inhalt fuer ausgew. Screens] │
|
|
│ │
|
|
│ [Aktivieren] [Abbrechen] │
|
|
└──────────────────────────────────────────┘
|
|
```
|
|
|
|
**Aktion:**
|
|
|
|
- Server speichert Kampagne mit `active = true`, `valid_from = NOW()`
|
|
- Server expandiert Zielgruppe in konkrete Screens
|
|
- Alle betroffenen Screens erhalten MQTT-Signal `playlist-changed` (obwohl Playlist gleich, aber Kampagnen-Prioritaet aendert sich)
|
|
- Screens synchonisieren und laden neue Kampagnen-Inhalte
|
|
|
|
### Workflow 2 — Geplante Aktivierung
|
|
|
|
**Szenario:** Admin bereitet eine Kampagne vor, soll aber erst am naechsten Tag 8:00 Uhr starten.
|
|
|
|
**Weg:**
|
|
|
|
Admin → Templates → [Template] → "Aktivieren" → "Geplant starten"
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ Geplante Aktivierung: Ostern 2025 │
|
|
├──────────────────────────────────────────┤
|
|
│ │
|
|
│ Kampagnen-Name │
|
|
│ [ Ostern_Dekoration_2025 ____________ ] │
|
|
│ │
|
|
│ Startdatum und -uhrzeit │
|
|
│ [2025-04-14] [08:00] [Kalender/Uhr] │
|
|
│ │
|
|
│ Enddatum und -uhrzeit (optional) │
|
|
│ [2025-04-21] [20:00] [Kalender/Uhr] │
|
|
│ oder [ ] Kein Enddatum │
|
|
│ │
|
|
│ Prioritaet │
|
|
│ [1_____________] │
|
|
│ │
|
|
│ Auto-Deaktivierung? │
|
|
│ ⦿ Ja │
|
|
│ ○ Nein │
|
|
│ │
|
|
│ Status │
|
|
│ ◯ GEPLANT — wird am 2025-04-14 08:00 │
|
|
│ aktiviert │
|
|
│ │
|
|
│ Erinnerung setzen (optional) │
|
|
│ [ ] Erinnerungs-Email 1 Tag vorher │
|
|
│ [ ] Erinnerungs-Email 1 Stunde vorher │
|
|
│ │
|
|
│ [Planen & Speichern] [Abbrechen] │
|
|
└──────────────────────────────────────────┘
|
|
```
|
|
|
|
**Aktion:**
|
|
|
|
- Server speichert Kampagne mit `active = false`, `valid_from = 2025-04-14 08:00`
|
|
- Server erstellt inneren Scheduler-Job
|
|
- Admin sieht Kampagne in Liste mit Status "GEPLANT"
|
|
- Um geplanten Zeitpunkt:
|
|
- Scheduler setzt `campaigns.active = true`
|
|
- MQTT-Signal an alle betroffenen Screens
|
|
- Optionale Erinnerungs-Email an Admin
|
|
|
|
### Workflow 3 — Schnelle Deaktivierung
|
|
|
|
**Szenario:** Kampagne laeuft, Admin will sie sofort stoppen.
|
|
|
|
**Weg:**
|
|
|
|
Admin → Kampagnen → [laufende Kampagne] → "Deaktivieren"
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ Kampagne deaktivieren? │
|
|
├──────────────────────────────────────────┤
|
|
│ │
|
|
│ Kampagne: Weihnachten 2025 │
|
|
│ Status: AKTIV seit 2025-12-01 09:00 │
|
|
│ Betroffene Screens: 13 │
|
|
│ │
|
|
│ Aktion: │
|
|
│ ⦿ Sofort deaktivieren │
|
|
│ Screens zeigen danach wieder │
|
|
│ Tenant-Playlist oder Fallback │
|
|
│ │
|
|
│ ○ Mit Verzoegerung (Fade-Out) │
|
|
│ [2 Min] [5 Min] [Uhr auswaehlen] │
|
|
│ Nuetzlich: Licht dimmen, Musik leiser │
|
|
│ etc. vor Inhalt-Wechsel │
|
|
│ │
|
|
│ [Ja, deaktivieren] [Abbrechen] │
|
|
└──────────────────────────────────────────┘
|
|
```
|
|
|
|
**Aktion:**
|
|
|
|
- Server setzt `campaigns.active = false`
|
|
- Server sendet MQTT-Signal an Screens
|
|
- Screens wechseln sofort (oder mit Verzoegerung) zu Fallback/Playlist
|
|
- Kampagne verschwindet aus "Aktive Kampagnen"-Liste
|
|
|
|
## 2. Zeitplanung und Scheduler
|
|
|
|
### Automatisierte Scheduler-Jobs
|
|
|
|
Der Server laeuft einen einfachen Scheduler als Goroutine oder als separaten Service.
|
|
|
|
```go
|
|
// Pseudocode
|
|
type CampaignScheduler interface {
|
|
RegisterJob(campaignID, activateAt, deactivateAt time.Time)
|
|
RunScheduler(ctx context.Context)
|
|
}
|
|
|
|
// Beim Starten
|
|
func init() {
|
|
scheduler := NewCampaignScheduler()
|
|
go scheduler.RunScheduler(ctx)
|
|
}
|
|
|
|
// Im Hintergrund
|
|
func (s *CampaignScheduler) RunScheduler(ctx context.Context) {
|
|
ticker := time.NewTicker(1 * time.Minute)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
// Checke alle geplanten Kampagnen
|
|
campaigns := db.GetScheduledCampaigns()
|
|
for _, c := range campaigns {
|
|
if time.Now() >= c.ValidFrom && !c.Active {
|
|
// Aktiviere die Kampagne
|
|
s.ActivateCampaign(c.ID)
|
|
}
|
|
if c.ValidUntil != nil && time.Now() >= *c.ValidUntil && c.Active {
|
|
// Deaktiviere die Kampagne
|
|
s.DeactivateCampaign(c.ID)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Persistenz ueber Restart
|
|
|
|
Scheduler-Jobs werden in der Datenbank gespeichert (Spalten `valid_from`, `valid_until`, `active` in `campaigns`-Tabelle).
|
|
|
|
Beim Neustart des Servers:
|
|
|
|
1. Server laedt alle geplanten/aktiven Kampagnen
|
|
2. Scheduler prueft bei jedem Takt (1 Min), ob eine Aktivierung/Deaktivierung faellig ist
|
|
3. Kein Datenverlust, kein komplexes Job-Persisting noetig
|
|
|
|
### Erinnerungen und Notifications
|
|
|
|
**Optional (Phase 2):**
|
|
|
|
- Email-Erinnerung N Stunden vor Aktivierung
|
|
- Webhook-Notification fuer externe Systeme
|
|
- In-App-Benachrichtigung im Admin-Dashboard
|
|
|
|
## 3. Screen-Zuordnung und Vorschau
|
|
|
|
### Interaktive Zielgruppen-Auswahl
|
|
|
|
Waehrend der Kampagnen-Erstellung kann der Admin entscheiden, welche Screens betroffen sein sollen.
|
|
|
|
```
|
|
Zielgruppe
|
|
⦿ Alle Screens
|
|
○ Nach Gruppe auswaehlen:
|
|
□ wall-all (9 Screens)
|
|
□ single-info (2 Screens)
|
|
□ vertretungsplan-all (2 Screens)
|
|
○ Einzelne Screens:
|
|
[ Suchfeld: "info" ]
|
|
□ info01 (portrait)
|
|
□ info02 (portrait)
|
|
☑ info03 (portrait)
|
|
□ info04 (portrait)
|
|
...
|
|
```
|
|
|
|
### Rendering-Vorschau
|
|
|
|
Admin sieht, wie die Kampagne auf verschiedenen Zielscreens aussieht:
|
|
|
|
```
|
|
Betroffene Screens: 4 ausgew.
|
|
|
|
┌─────────────────────────────────────┐
|
|
│ info01 (portrait, 1920x1080) │
|
|
│ ┌────────────────────────────────┐ │
|
|
│ │ │ │
|
|
│ │ [Kampagnen-Inhalt: Bild] │ │
|
|
│ │ (Portrait-Assets verwendet) │ │
|
|
│ │ │ │
|
|
│ └────────────────────────────────┘ │
|
|
└─────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────┐
|
|
│ info05 (landscape, 2560x1440) │
|
|
│ ┌────────────────────────────────┐ │
|
|
│ │ [Kampagnen-Inhalt: Bild] │ │
|
|
│ │ (Landscape-Assets verwendet) │ │
|
|
│ └────────────────────────────────┘ │
|
|
└─────────────────────────────────────┘
|
|
|
|
[Scrollen um weitere Screens zu sehen]
|
|
```
|
|
|
|
### Live-Uebersicht waehrend Laufzeit
|
|
|
|
Wenn eine Kampagne aktiv ist, zeigt das Admin-Dashboard:
|
|
|
|
```
|
|
Kampagne: Weihnachten 2025 einfuehrung
|
|
Status: AKTIV seit 2025-12-01 09:00
|
|
|
|
Betroffene Screens: 13
|
|
✓ Aktiv angezeigt: 11 (info01-info08, info10, info11, info13)
|
|
◯ Wartet auf Sync: 1 (info09)
|
|
✗ Offline: 1 (info12)
|
|
|
|
Zuletzt geprueft: vor 30 Sekunden
|
|
|
|
[Aktualisieren] [Deaktivieren] [Bearbeiten]
|
|
```
|
|
|
|
## 4. Kampagnen-Verwaltung waehrend Laufzeit
|
|
|
|
### Aktive Kampagnen — Haupt-Dashboard
|
|
|
|
**Seite:** Admin → Aktive Kampagnen (oder Campaigns)
|
|
|
|
```
|
|
┌─────────────────────────────────┐
|
|
│ Aktive Kampagnen │
|
|
├─────────────────────────────────┤
|
|
│ │
|
|
│ Weihnachten 2025 einfuehrung │ ▼
|
|
│ Template: Weihnachtsmotiv 2025 │
|
|
│ Aktiv seit: 2025-12-01 09:00 │
|
|
│ Aktiv bis: 2025-12-26 23:59 │
|
|
│ Betroffene: 13 Screens │
|
|
│ Status: ✓ Auf allen Screens ok │
|
|
│ │
|
|
│ [Vorschau] [Bearbeiten] │
|
|
│ [Deaktivieren] │
|
|
│ │
|
|
├─────────────────────────────────┤
|
|
│ │
|
|
│ Event-Tag 25.03 │
|
|
│ Template: screen_specific_scene │
|
|
│ Aktiv seit: 2025-03-25 00:00 │
|
|
│ Aktiv bis: 2025-03-25 23:59 │
|
|
│ Betroffene: 4 Screens │
|
|
│ Status: ◯ 1 Screen offline │
|
|
│ │
|
|
│ [Vorschau] [Bearbeiten] │
|
|
│ [Deaktivieren] │
|
|
│ │
|
|
└─────────────────────────────────┘
|
|
```
|
|
|
|
### Geplante Kampagnen
|
|
|
|
**Seite:** Admin → Kampagnen (Alle)
|
|
|
|
```
|
|
┌─────────────────────────────────┐
|
|
│ Geplante Kampagnen │
|
|
├─────────────────────────────────┤
|
|
│ │
|
|
│ Ostern-Dekoration 2025 │ ▼
|
|
│ Template: full_screen_media │
|
|
│ Status: GEPLANT │
|
|
│ Startet: 2025-04-14 08:00 │
|
|
│ Endet: 2025-04-21 20:00 │
|
|
│ Betroffene: 13 Screens │
|
|
│ Erinnerung: 1 Tag vorher │
|
|
│ │
|
|
│ [Vorschau] [Bearbeiten] │
|
|
│ [Jetzt aktivieren] [Loeschen] │
|
|
│ │
|
|
├─────────────────────────────────┤
|
|
│ │
|
|
│ Sommer-Kampagne │
|
|
│ Status: GEPLANT │
|
|
│ Startet: 2025-06-01 00:00 │
|
|
│ │
|
|
│ ... │
|
|
│ │
|
|
└─────────────────────────────────┘
|
|
```
|
|
|
|
### Abgelaufene Kampagnen
|
|
|
|
**Seite:** Admin → Kampagnen (Archiv)
|
|
|
|
```
|
|
Zeigt inaktive/abgelaufene Kampagnen fuer Audit-Trail.
|
|
|
|
[ Kampagne ] Zeitraum Status
|
|
Ostern 2025 2025-04-14—04-21 Auto-Deaktiviert
|
|
Karneval 2025-02-28—03-05 Manuell deaktiviert
|
|
Valentinstag 2025-02-14 Auto-Deaktiviert
|
|
```
|
|
|
|
## 5. Prioritaetsverwaltung
|
|
|
|
### Prio-Einstellung pro Kampagne
|
|
|
|
```
|
|
Prioritaet gegenueber Tenant-Playlist
|
|
┌─────────────────────────────────┐
|
|
│ Schieber oder Zahlenfeld │
|
|
│ │
|
|
│ [|━━━━━━━━━━━| ] 10 │
|
|
│ 1 5 10 100 │
|
|
│ │
|
|
│ Bedeutung: │
|
|
│ 1 = normale Kampagne │
|
|
│ 10 = hohe Prioritaet (Standard) │
|
|
│ 100 = Notfall / absolut wichtig │
|
|
│ │
|
|
│ Diese Prioritaet wird ueber │
|
|
│ alle Tenant-Playlists gestellt │
|
|
│ (falls mehrere Kampagnen) │
|
|
│ verwendet die mit hoechster │
|
|
│ Prioritaet │
|
|
└─────────────────────────────────┘
|
|
```
|
|
|
|
### Konflikt-Management (mehrere Kampagnen gleichzeitig)
|
|
|
|
Falls mehrere Kampagnen fuer denselben Screen aktiv sind:
|
|
|
|
1. Sortierende nach Prioritaet (hoechste gewinnt)
|
|
2. Bei gleicher Prioritaet: nach Start-Zeitstempel (neueste gewinnt)
|
|
3. Admin sieht im Status-Dashboard einen Warning: "2 Kampagnen fuer info01 aktiv"
|
|
|
|
Empfehlung: Admin sollte Zeitraeume von Kampagnen nicht ueberlappen lassen.
|
|
|
|
## 6. Fehlerbehandlung
|
|
|
|
### Was, wenn ein Screen offline ist?
|
|
|
|
```
|
|
Kampagne wird aktiviert, aber Screen info03 ist gerade offline:
|
|
|
|
1. Server weiss, dass info03 Ziel der Kampagne ist
|
|
2. Server loggt: "Kampagne XYZ kann nicht auf info03 ausgeliefert werden (offline)"
|
|
3. Info03 hat letzte gueltige Kampagne gecacht
|
|
4. Sobald info03 wieder online kommt:
|
|
- Player synchonisiert
|
|
- Server sagt: "Kampagne XYZ ist aktiv"
|
|
- Player ladet und rendert
|
|
5. Status im Dashboard: "info03 — Offline, wird synchronisiert sobald online"
|
|
```
|
|
|
|
### Rollback bei fehlgeschlagener Aktivierung
|
|
|
|
Falls eine Kampagne fehlerhaft ist (kaputtes Video, Renderingfehler):
|
|
|
|
```
|
|
1. Screen zeigt Fehler-Overlay
|
|
2. Admin ist informiert (Status-API zeigt Fehler)
|
|
3. Admin Aktion 1: Template korrigieren
|
|
- Fehlerhaftes Asset austauschen
|
|
- Kampagne aktualisieren
|
|
- Screens neu synchonisieren
|
|
4. Admin Aktion 2: Schnelle Deaktivierung
|
|
- Kampagne abschalten
|
|
- Fallback/Playlist kehrt zurueck
|
|
```
|
|
|
|
## 7. Datenschutz und Audit
|
|
|
|
### Audit-Trail
|
|
|
|
Alle Kampagnen-Aenderungen werden protokolliert:
|
|
|
|
```json
|
|
{
|
|
"ts": "2025-03-25T14:22:00Z",
|
|
"event": "campaign_activated",
|
|
"campaign_id": "uuid-...",
|
|
"campaign_name": "Ostern-Dekoration",
|
|
"triggered_by_user_id": "admin123",
|
|
"triggered_by_email": "admin@example.com",
|
|
"details": {
|
|
"valid_from": "2025-04-14T08:00:00Z",
|
|
"valid_until": "2025-04-21T20:00:00Z",
|
|
"target_screens_count": 13
|
|
}
|
|
}
|
|
```
|
|
|
|
Diese Logs sind fuer Compliance und Forensik wichtig.
|
|
|
|
### Sichtbarkeitsbeschraenkung
|
|
|
|
Nur Benutzer mit Admin-Rolle koennen:
|
|
|
|
- Kampagnen erstellen/aendernx
|
|
- Templates bearbeiten
|
|
- Aktivierung planen
|
|
|
|
Tenant-User sehen keine Kampagnen-Verwaltung.
|
|
|
|
## 8. Zusammenfassung
|
|
|
|
Die Aktivierungsoberflaeche:
|
|
|
|
- **ist einsteigerfreundlich** — Multi-Step Formulare mit Vorschau
|
|
- **unterstuetzt Sofort und Planung** — spontan oder Wochen im Voraus
|
|
- **ist sichtbar** — Live-Status und Fehler-Reporting
|
|
- **ist automatisiert** — Scheduler kuemmert sich um Auf-/Abschalten
|
|
- **ist sicher** — Audit-Trail und Rollback-Moeglichkeiten
|
|
- **ist robust** — Offline-Screens werden spaeter synchronisiert
|