# Info-Board Neu - Template-Editor fuer globale Kampagnen

## Ziel

Der Template-Editor ist ein Bereich des Admin-UI fuer die fachliche Erstellung und Verwaltung globaler Templates und deren operativen Aktivierungen als Kampagnen.

Dieses Dokument definiert:

- Welche Schritte ein Admin unternimmt, um ein Template zu erstellen
- Welche Felder und Optionen der Editor anbietet
- Wie Templates zu Kampagnen aktiviert werden
- Wie die Abbildung im Datenmodell aussieht

Grundlagen zu Template-Typen, Slot-Modell und Message-Wall finden sich in `docs/TEMPLATE-KONZEPT.md`.

## 1. Template-Verwaltung

### Template-Liste

**Seite:** Admin → Templates

**Anzeige:**

Tabelle mit allen Templates:

| Name | Typ | Zielgruppe | Szenen | Erstellt | Status |
|---|---|---|---|---|---|
| Weihnachtsmotiv 2025 | full_screen_media | alle | 1 | 2025-01-15 | draft |
| Schriftzug Infowand | message_wall | wall-all | 9 | 2025-02-01 | active |
| Event-Tag 25.03 | screen_specific_scene | [info01, info02, ...] | 2 | 2025-03-01 | draft |

**Aktionen pro Zeile:**

- "Bearbeiten" — öffnet Template-Editor
- "Kopieren" — dupliziert als neue Draft
- "Löschen" — nur wenn keine aktiven Kampagnen
- "Vorschau" — zeigt Layout (fuer message_wall) oder Asset-Galerien
- "Aktivieren" — schneller Weg zu Kampagne starten

### Template-Editor (Erstellung/Bearbeitung)

#### Phase 1 — Grunddaten

```
┌─────────────────────────────────────────┐
│ Neues Template erstellen                │
├─────────────────────────────────────────┤
│                                         │
│ Name *                                  │
│ [ Weihnachtsmotiv 2025_______________ ]│
│ technischer slug wird automatisch       │
│                                         │
│ Template-Typ *                          │
│ ⦿ full_screen_media                    │
│ ○ message_wall                         │
│ ○ screen_specific_scene                │
│                                         │
│ Beschreibung                            │
│ [ Weihnachtliche Grafik fuer alle___  ] │
│   [ Screens __________________________ ]│
│                                         │
│ Zielgruppe / Screens *                  │
│ ⦿ Alle Screens                         │
│ ○ Nach Gruppe auswaehlen               │
│   [Dropdown: wall-all, single-all, ...] │
│ ○ Einzelne Screens auswaehlen          │
│   [Checkbox-Liste mit Filterung]       │
│                                         │
│ [Weiter >]  [Abbrechen]                │
└─────────────────────────────────────────┘
```

**Validierung:**

- Name ist erforderlich
- Name ist eindeutig
- Template-Typ ist erforderlich
- Zielgruppe ist erforderlich (keine leere Zuweisung)

#### Phase 2 — Szenen/Inhalte

Fuer `full_screen_media`:

```
┌─────────────────────────────────────────┐
│ Szenen und Inhalte                      │
├─────────────────────────────────────────┤
│                                         │
│ Szene 1: Vollbild-Grafik                │
│                                         │
│ Medientyp *                             │
│ ○ Bild                                  │
│ ○ Video                                 │
│ ○ PDF                                   │
│ ⦿ Webseite (HTML)                      │
│                                         │
│ Portrait-Asset (Hochformat)             │
│ [Upload oder URL]                       │
│ [ Datei auswaehlen ]  [Neue URL]        │
│ oder vorher gemanagte Assets: [Liste]   │
│                                         │
│ Landscape-Asset (Querformat) [optional] │
│ [ Datei auswaehlen ]  [Neue URL]        │
│                                         │
│ Anzeigedauer (Sekunden)                 │
│ [60_____] Standard: 10                  │
│                                         │
│ Load-Timeout (Sekunden)                 │
│ [10_____] Standard: 10                  │
│                                         │
│ gueltig ab                              │
│ [ 2025-03-25 ] [ 00:00 ]               │
│ (leer = sofort gueltig)                 │
│                                         │
│ gueltig bis                             │
│ [ 2025-04-01 ] [ 00:00 ]               │
│ (leer = unendlich)                      │
│                                         │
│ [+ Weitere Szene hinzufuegen]           │
│                                         │
│ [Zurueck <]  [Speichern & Aktivieren]  │
│             [Speichern]                 │
│             [Abbrechen]                 │
└─────────────────────────────────────────┘
```

Fuer `message_wall`:

```
┌─────────────────────────────────────────┐
│ Message-Wall Layout                     │
├─────────────────────────────────────────┤
│                                         │
│ Layout-Template                         │
│ [Dropdown: 3x3-Grid, 2x2-Grid, ...]    │
│                                         │
│ Anzeigedauer (Sekunden)                 │
│ [10_____]                              │
│                                         │
│ Gesamt-Grafik oder Text eingeben        │
│ [Rich-Text-Editor oder Bild-Upload]    │
│                                         │
│ Vorschau: [Zeigt Einteilung in Slots] │
│                                         │
│ Slot-Zuordnung: [Interaktive Zuordnung] │
│ Slot wall-r1-c1 → Screen info01        │
│ Slot wall-r1-c2 → Screen info02        │
│ ... (9 Slots insgesamt)                │
│                                         │
│ [+ Layout-Typ aendernx]  [Speichern]   │
│                                         │
│ [Zurueck <]  [Speichern & Aktivieren]  │
│             [Speichern]                 │
│             [Abbrechen]                 │
└─────────────────────────────────────────┘
```

Fuer `screen_specific_scene`:

```
┌─────────────────────────────────────────┐
│ Monitorindividuelle Szenen              │
├─────────────────────────────────────────┤
│                                         │
│ Szene 1: Infowand                       │
│                                         │
│ Zielgruppe                              │
│ ⦿ Gruppe: [Dropdown: wall-all]         │
│ ○ Einzelne Screens: [Checkboxen]       │
│                                         │
│ Asset                                   │
│ [Upload oder URL]                      │
│                                         │
│ Dauer, Timeout, gueltig_von/bis        │
│ [... wie oben ...]                      │
│                                         │
│ [+ Weitere Szene hinzufuegen]           │
│                                         │
│ [Zurueck <]  [Speichern & Aktivieren]  │
└─────────────────────────────────────────┘
```

## 2. Kampagnen-Verwaltung

Kampagnen sind die operativen Instanzen von Templates.

### Kampagnen-Liste

**Seite:** Admin → Kampagnen

**Anzeige:**

| Name | Template | Aktiv | Zielgruppe | gueltig von | gueltig bis | Betroffene Screens |
|---|---|---|---|---|---|---|
| Weihnachten Dekoration | Weihnachtsmotiv 2025 | ✓ | alle | 2025-12-01 | 2025-12-26 | 13 Screens |
| Schriftzug Januar | Schriftzug Infowand | ✗ | wall-all | 2025-01-06 | 2025-01-31 | 9 Screens |

**Aktionen:**

- "Bearbeiten" — Kampagnen-Eigenschaften aendern
- "Aktivieren/Deaktivieren" — Toggle sofort
- "Vorschau" — zeigt betroffene Screens mit Rendering
- "Duplizieugen" — als neue Kampagne mit anderem Template
- "Loeschen" — wenn inaktiv und abgelaufen

### Neue Kampagne starten

**Workflow Option 1 — Von Template aus:**

Template-Liste → [Template] → "Aktivieren"

```
┌─────────────────────────────────────────┐
│ Kampagne starten: Weihnachtsmotiv 2025 │
├─────────────────────────────────────────┤
│                                         │
│ Kampagnen-Name                          │
│ [ Weihnachten 2025 einfuehrung____ ]   │
│                                         │
│ Aktiv ab sofort?                        │
│ ⦿ Ja                                   │
│ ○ Geplant fuer: [Datum/Zeit auswaehlen]│
│   [ 2025-12-01 ] [ 09:00 ]             │
│                                         │
│ Gueltig von                             │
│ [ 2025-12-01 ]  [ 00:00 ]              │
│                                         │
│ Gueltig bis                             │
│ [ 2025-12-26 ]  [ 23:59 ]              │
│                                         │
│ Prioritaet (gegenueber Playlist)        │
│ [1 (hoehere Werte sind wichtiger)] ___ │
│                                         │
│ Auto-Deaktivierung bei Ablauf?          │
│ ⦿ Ja                                   │
│ ○ Nein (Kampagne bleibt inaktiv)       │
│                                         │
│ [Kampagne starten]  [Abbrechen]        │
└─────────────────────────────────────────┘
```

**Workflow Option 2 — Neue Kampagne ohne Template:**

Admin → Kampagnen → "+ Neue Kampagne"

```
[Template auswaehlen] → [Grunddaten] → [Aktivierung]
```

### Kampagnen-Detailseite

**Anzeige einer laufenden Kampagne:**

```
Kampagne: Weihnachten 2025 einfuehrung
Status: AKTIV seit 2025-12-01 09:00

Template: Weihnachtsmotiv 2025 (full_screen_media)
Zielgruppe: Alle (13 Screens)

Gueltig: 2025-12-01 00:00 bis 2025-12-26 23:59
Prioritaet: 1

Betroffene Screens:
┌──────────────────────────────┐
│ info01  online   aktiv       │ [Screenshot]
│ info02  online   aktiv       │ [Screenshot]
│ info03  offline  ausstehend  │
│ info04  online   aktiv       │ [Screenshot]
│ ... (10 weitere) ...         │
└──────────────────────────────┘

Aktionen:
[Deaktivieren]  [Bearbeiten]  [Vorschau aendernx]

Aktivierungsverlauf:
2025-12-01 09:00 — Kampagne gestartet von admin@...
2025-12-01 09:05 — 9 Screens haben gerendert
2025-12-01 10:30 — info03 ging offline, Kampagnen-Inhalt wartet auf Rueckkehr
```

## 3. Verknuepfung zur Prioritaetsregel

Die Regel `campaign > tenant_playlist > fallback` ist:

- **hardcoded** im Player
- **administrierbar** ueber die Kampagnen-Aktivierung
- **vorhersagbar** durch klare Doku

### Abbildung im System

```
Fuer jeden Screen:
  IF Kampagne fuer diesen Screen aktiv UND gueltig_von <= jetzt <= gueltig_bis
    THEN Zeige Kampagnen-Inhalt
  ELSE IF Tenant-Playlist hat gueltige Items
    THEN Zeige Tenant-Playlist
  ELSE
    Zeige Fallback
```

Diese Logik wird:

1. **Serverseitig** berechnet bei jedem Sync-Request (HTTP `/api/v1/screens/{screenSlug}/playlist`)
2. **Spielerseitig** nochmals geprueft beim Rendering (fuer Offline-Robustheit)

### Admin-Sichtbarkeit

Die Admin-UI zeigt auf der Seite "Screens" fuer jeden Monitor:

```
info01
├── Kampagne (AKTIV bis 2025-12-26)
│   └── Weihnachten 2025 einfuehrung
├── Fallback (wird nach Kampagnen-Ablauf gezeigt)
└── Tenant Playlist
    ├── Playlist A (Tenant XYZ)
    │   ├── Bild-1 (gueltig bis 2025-04-01)
    │   ├── Video-2 (laedt...)
    │   └── Webseite-3
    └── Fallback-Verzeichnis
```

Diese View zeigt, was der Screen **aktuell gerade zeigt** und warum.

## 4. Datenmodell

### Tabelle `templates`

```sql
CREATE TABLE templates (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  slug TEXT NOT NULL UNIQUE,
  name TEXT NOT NULL,
  description TEXT,
  template_type TEXT NOT NULL CHECK (template_type IN ('message_wall', 'full_screen_media', 'screen_specific_scene')),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_by_user_id TEXT NOT NULL,

  -- Serializierte Konfiguration (JSON)
  config JSONB NOT NULL DEFAULT '{}'
  -- Beispiele:
  -- {
  --   "target_mode": "all_screens" | "group" | "specific_screens",
  --   "target_group": "wall-all" (wenn target_mode = "group"),
  --   "target_screen_ids": ["..."] (wenn target_mode = "specific_screens"),
  --   "scenes": [
  --     {
  --       "media_type": "image|video|pdf|webpage|html",
  --       "asset_id": "...",
  --       "portrait_asset_id": "..." (optional),
  --       "landscape_asset_id": "..." (optional),
  --       "duration_sec": 10,
  --       "load_timeout_sec": 10,
  --       "valid_from": "2025-03-25T00:00:00Z",
  --       "valid_until": "2025-04-01T23:59:59Z"
  --     }
  --   ]
  -- }
);
```

### Tabelle `campaigns`

```sql
CREATE TABLE campaigns (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL,
  template_id UUID NOT NULL REFERENCES templates(id),
  active BOOLEAN NOT NULL DEFAULT false,
  priority INT NOT NULL DEFAULT 1,
  valid_from TIMESTAMPTZ NOT NULL,
  valid_until TIMESTAMPTZ,
  auto_deactivate BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_by_user_id TEXT NOT NULL,

  -- ueberschreiben/erweitern Template-Zielgruppe (optional)
  target_mode TEXT CHECK (target_mode IN ('template', 'all_screens', 'group', 'specific_screens')),
  target_group TEXT,
  target_screen_ids UUID[] DEFAULT '{}'::uuid[]
);
```

### Tabelle `campaign_screen_assignments` (generiert)

Diese Tabelle wird **serverseitig** generiert/gepflegt, wenn eine Kampagne aktiv wird.

Sie expandiert Gruppen in konkrete Screen-IDs:

```sql
CREATE TABLE campaign_screen_assignments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  campaign_id UUID NOT NULL REFERENCES campaigns(id) ON DELETE CASCADE,
  screen_id UUID NOT NULL REFERENCES screens(id) ON DELETE CASCADE,
  assigned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE(campaign_id, screen_id)
);
```

**Logik:**

```
IF campaign.target_mode = 'template'
  THEN Fuelle campaign_screen_assignments aus template.config.target_screen_ids
ELSE IF campaign.target_mode = 'group'
  THEN Fuelle campaign_screen_assignments aus allen Screens in campaign.target_group
ELSE IF campaign.target_mode = 'specific_screens'
  THEN Fuelle campaign_screen_assignments aus campaign.target_screen_ids
ELSE
  (alle Screens)
```

## 5. Praxis-Beispiele

### Beispiel 1 — Weihnachtsplakatierung (full_screen_media)

**Szenario:**

Admin will ab 01.12.2025 fuer 4 Wochen ein rotes Weihnachtsmotiv auf allen Screens zeigen.

**Schritte:**

1. Admin → Templates → "+ Neues Template"
   - Name: `Weihnachtsmotiv 2025`
   - Typ: `full_screen_media`
   - Zielgruppe: `Alle Screens`

2. Szene hinzufuegen:
   - Bild hochladen (passend fuer Portrait und Landscape)
   - Dauer: 10 Sekunden

3. Speichern → Editor zeigt Draft mit Vorschau

4. Admin → Templates → [Weihnachtsmotiv 2025] → "Aktivieren"
   - Kampagnen-Name: `Weihnachten 2025 globale Dekoration`
   - Gueltig von: 2025-12-01
   - Gueltig bis: 2025-12-26
   - Aktiv ab: sofort

5. Kampagne speichern → Sofort sichtbar auf allen Screens

### Beispiel 2 — Schriftzug ueber die Infowand (message_wall)

**Szenario:**

Admin hat eine neue `message_wall`-Gruppe "wall-all" mit 9 Screens. Er will ein riesiges rotes Schriftzug-Motiv aufteilen und auf allen 9 Screens verteilen.

**Schritte:**

1. Admin → Templates → "+ Neues Template"
   - Name: `Rotes Schriftzug auf Infowand`
   - Typ: `message_wall`
   - Zielgruppe: `Gruppe: wall-all`

2. Layout waehlen: `3x3-Grid` (passt zu 9 Screens)

3. Gesamte Grafik hochladen (oder als Text eingeben)

4. Slot-Zuordnung:
   - System zeigt interaktive 3x3-Vorschau
   - Admin tuen: "Slot 1 → info01", "Slot 2 → info02", ...
   - System generiert automatisch die Crop-Regionen

5. Speichern + Aktivieren
   - Jeder Screen zeigt seinen Ausschnitt

### Beispiel 3 — Deaktivierung und Fallback

**Szenario:**

Kampagne laueft seit 2 Wochen. Admin will sie sofort stoppen, damit Screens auf ihre normalen Playlists zurueckfallen.

**Aktion:**

Admin → Kampagnen → [Kampagne] → "Deaktivieren"

**Folge:**

- Server setzt `campaigns.active = false`
- Bei naechstem Sync ladet jeder Player wieder die Tenant-Playlist
- Fallback-Verzeichnis wird nur noch angezeigt, wenn tenantbezogene Playlist leer ist

## 6. Zusammenfassung

Der Template-Editor:

- **ist zwei-stufig** — Template-Verwaltung + Kampagnen-Aktivierung
- **ist intuitiv** — Multi-Step-Formulare mit Vorschauen
- **unterstützt alle Template-Typen** — full_screen, message_wall, screen_specific
- **haelt die Prioritaetsregel transparent** — Admin sieht, welche Kampagne welche Screens uebersteuert
- **ist zukunftssicher** — Datenmodell skaliert mit neuen Template-Typen
