# Feature Plan: Slideshow Optimierung - Preload & Sortierung

**Status**: ✅ Abgeschlossen  
**Branch**: `feature/PreloadImage`  
**Erstellt**: 09. November 2025  
**Abgeschlossen**: 09. November 2025

## Problem-Analyse

### 1. Doppelte Bild-Anzeige (Haupt-Problem)
**Symptome**:
- Slideshow zeigt häufig mehrfach das gleiche Bild in einer Gruppe
- Springt manchmal nur kurz auf das eigentliche nächste Bild
- Tritt bei allen Gruppen mit mehr als einem Bild auf (typisch 3-11 Bilder)
- Problem ist konsistent reproduzierbar

**Root Cause**:
Die aktuelle Implementierung lädt Bilder on-demand ohne Preloading. Beim automatischen Wechsel wird:
1. `setFadeOut(true)` gesetzt → Bild wird ausgeblendet
2. Nach 500ms wird `currentImageIndex` aktualisiert
3. Das neue Bild wird erst JETZT vom Browser angefordert
4. Während des Ladens bleibt das alte Bild sichtbar oder es gibt Flackern
5. Browser zeigt gecachte/teilweise geladene Versionen mehrfach an

**Code-Stelle**: `SlideshowPage.js`, Zeilen 68-82 (`nextImage` Funktion)

### 2. Zufällige Gruppen-Reihenfolge
**Aktuelles Verhalten**:
- Gruppen werden bei jedem Load zufällig gemischt (`sort(() => Math.random() - 0.5)`)
- Keine chronologische oder logische Reihenfolge

**Gewünschtes Verhalten**:
- Sortierung nach `year` (primär, aufsteigend)
- Bei gleichem Jahr: nach `upload_date` (sekundär, aufsteigend)
- Bilder innerhalb der Gruppe: nach `upload_order` (wie bisher)

## Lösungsansatz

### A. Image Preloading (Priorität: HOCH)

#### Strategie
Implementiere intelligentes Preloading für die nächsten 2-3 Bilder:
- **Aktuelles Bild**: Angezeigt
- **Nächstes Bild**: Vollständig vorgeladen (höchste Priorität)
- **Übernächstes Bild**: Im Hintergrund laden (niedrige Priorität)

#### Technische Umsetzung

1. **Preload-Manager-Hook erstellen** (`useImagePreloader.js`)
   ```javascript
   - Verwaltet einen Preload-Queue
   - Nutzt Image() Objekte zum Vorladen
   - Cached erfolgreich geladene Bilder
   - Behandelt Fehler gracefully
   ```

2. **Predictive Loading**
   ```javascript
   - Berechne nächste 2-3 Bilder in der Sequenz
   - Berücksichtige Gruppenübergänge
   - Lade Bilder asynchron im Hintergrund
   ```

3. **State Management**
   ```javascript
   - Neuer State: preloadedImages (Set oder Map)
   - Prüfe vor Fade-Out, ob nächstes Bild geladen ist
   - Verzögere Wechsel falls nötig (max. 1s Fallback)
   ```

#### Vorteile
- ✅ Eliminiert Lade-Latenz
- ✅ Nahtlose Übergänge garantiert
- ✅ Verbesserte User Experience
- ✅ Kein Browser-Flackern mehr

### B. Chronologische Sortierung (Priorität: MITTEL)

#### Backend-Änderungen
**Datei**: `backend/src/routes/groups.js` (oder entsprechender Endpoint)

**Aktuelle Abfrage**:
```sql
SELECT * FROM groups WHERE ... ORDER BY created_at DESC
```

**Neue Abfrage**:
```sql
SELECT * FROM groups 
WHERE approved = 1
ORDER BY year ASC, upload_date ASC
```

#### Frontend-Änderungen
**Datei**: `frontend/src/Components/Pages/SlideshowPage.js`

**Aktueller Code (Zeile 43-44)**:
```javascript
// Mische die Gruppen zufällig
const shuffledGroups = [...groupsData.groups].sort(() => Math.random() - 0.5);
```

**Neuer Code**:
```javascript
// Sortiere chronologisch: Jahr (aufsteigend) → Upload-Datum (aufsteigend)
const sortedGroups = [...groupsData.groups].sort((a, b) => {
  if (a.year !== b.year) {
    return a.year - b.year; // Ältere Jahre zuerst
  }
  // Bei gleichem Jahr: nach Upload-Datum
  return new Date(a.uploadDate) - new Date(b.uploadDate);
});
```

#### Vorteile
- ✅ Chronologische Story-Erzählung
- ✅ Nutzt bestehende Datenbank-Felder (kein Schema-Change nötig)
- ✅ Einfache Implementierung
- ✅ Konsistente Reihenfolge über alle Sessions

## Implementierungs-Plan

### Phase 1: Image Preloading (Hauptfokus)
**Geschätzte Dauer**: 3-4 Stunden

1. **Custom Hook erstellen** (60 min)
   - [ ] `frontend/src/hooks/useImagePreloader.js` erstellen
   - [ ] Preload-Logik implementieren
   - [ ] Error Handling einbauen

2. **SlideshowPage Integration** (90 min)
   - [ ] Hook in SlideshowPage importieren
   - [ ] Preload-Queue vor jedem Wechsel aktualisieren
   - [ ] State-Management für geladene Bilder
   - [ ] Fallback für langsame Verbindungen

3. **Testing** (60 min)
   - [ ] Manuelle Tests mit verschiedenen Gruppen-Größen
   - [ ] Netzwerk-Throttling Tests (Chrome DevTools)
   - [ ] Fehlerfall-Tests (404, CORS-Fehler)

### Phase 2: Chronologische Sortierung (30 min)
**Geschätzte Dauer**: 30 Minuten

1. **Frontend-Sortierung** (15 min)
   - [ ] Shuffle-Code durch Sort-Logik ersetzen
   - [ ] Testing mit verschiedenen Jahren

2. **Backend-Optimierung** (15 min, Optional)
   - [ ] SQL-Query für sortierte Rückgabe anpassen
   - [ ] Index auf `(year, upload_date)` prüfen

### Phase 3: Testing & Dokumentation (30 min)
**Geschätzte Dauer**: 30 Minuten

1. **Integrationstests**
   - [ ] End-to-End Slideshow-Durchlauf
   - [ ] Performance-Metriken sammeln
   - [ ] Browser-Kompatibilität (Chrome, Firefox, Safari)

2. **Dokumentation**
   - [ ] README.md aktualisieren (Preload-Feature erwähnen)
   - [ ] Code-Kommentare für komplexe Preload-Logik
   - [ ] CHANGELOG.md Entry erstellen

## Technische Details

### Preload-Algorithmus (Pseudo-Code)
```javascript
function calculateNextImages(currentGroupIndex, currentImageIndex, allGroups, count = 2) {
  const result = [];
  let groupIdx = currentGroupIndex;
  let imgIdx = currentImageIndex + 1;
  
  while (result.length < count) {
    const group = allGroups[groupIdx];
    
    if (imgIdx < group.images.length) {
      // Nächstes Bild in aktueller Gruppe
      result.push({ group: groupIdx, image: imgIdx, src: getImageSrc(group.images[imgIdx]) });
      imgIdx++;
    } else {
      // Nächste Gruppe (sortiert, nicht zufällig)
      groupIdx = (groupIdx + 1) % allGroups.length;
      imgIdx = 0;
      
      if (groupIdx === currentGroupIndex && imgIdx === currentImageIndex) {
        break; // Alle Bilder durchlaufen
      }
    }
  }
  
  return result;
}
```

### Datenstruktur (Preload-State)
```javascript
{
  preloadedImages: Map<string, HTMLImageElement>, // URL → Image Object
  preloadQueue: Array<{groupIdx, imageIdx, src}>,
  isPreloading: boolean
}
```

## Erwartete Verbesserungen

### Performance
- **Vor der Änderung**: 
  - Lade-Zeit pro Bild: 200-1500ms (je nach Größe)
  - Sichtbare Verzögerung bei jedem Wechsel
  - Flackern/Doppelte Anzeige

- **Nach der Änderung**:
  - Lade-Zeit: 0ms (bereits geladen)
  - Nahtlose Übergänge
  - Keine Doppel-Anzeige mehr

### User Experience
- ✅ Keine sichtbaren Ladezeiten
- ✅ Flüssige Transitions
- ✅ Chronologische Story (älteste → neueste Bilder)
- ✅ Professionelles Look & Feel

## Risiken & Mitigationen

### Risiko 1: Memory-Usage
**Problem**: Viele vorgeladene Bilder belegen RAM  
**Mitigation**: 
- Nur 2-3 Bilder gleichzeitig laden
- Alte Bilder aus Cache entfernen (LRU-Strategy)
- Max. 20MB Preload-Limit

### Risiko 2: Langsame Verbindungen
**Problem**: Preload dauert länger als Display-Zeit  
**Mitigation**:
- 1s Timeout pro Preload
- Fallback auf altes Verhalten (ohne Preload)
- User-Feedback (kleiner Ladeindikator)

### Risiko 3: Browser-Kompatibilität
**Problem**: Image Preloading unterschiedlich unterstützt  
**Mitigation**:
- Standard HTML5 Image() API (universell unterstützt)
- Feature-Detection einbauen
- Graceful Degradation

## Testing-Checkliste

- [ ] Slideshow mit 3-Bild-Gruppe (typischer Use-Case)
- [ ] Slideshow mit 11-Bild-Gruppe (Worst-Case)
- [ ] Slideshow mit nur 1 Gruppe (Edge-Case)
- [ ] Gruppenübergang (letzte Bild → erste Bild nächste Gruppe)
- [ ] Chronologische Sortierung (mehrere Jahre)
- [ ] Slow-3G Network Throttling
- [ ] Keyboard-Navigation (Space, Arrow Keys)
- [ ] Browser-DevTools: Keine Fehler in Console
- [ ] Memory-Leak Test (10+ Minuten Slideshow)

## Alternativen (Verworfen)

### Alternative 1: Link-Prefetch
```html
<link rel="prefetch" href="/image.jpg">
```
**Nachteil**: Keine JavaScript-Kontrolle über Lade-Status

### Alternative 2: Service Worker Caching
**Nachteil**: Zu komplex für aktuelles Requirement, Overhead zu groß

### Alternative 3: CSS background-image mit Preload
**Nachteil**: Weniger Kontrolle, keine Image-Events

## Erfolgs-Kriterien

✅ **Must-Have**:
1. Kein doppeltes Bild-Anzeigen mehr
2. Nahtlose Übergänge zwischen Bildern
3. Chronologische Gruppen-Sortierung

✅ **Nice-to-Have**:
1. < 50ms Wechselzeit zwischen Bildern
2. < 10MB zusätzlicher Memory-Footprint
3. Browser-Console bleibt fehlerfrei

## Rollout-Plan

1. **Development** (feature/PreloadImage Branch)
   - Implementierung & Testing
   - Code Review

2. **Staging/Testing**
   - Deployment auf Dev-Environment
   - Manuelle QA-Tests
   - Performance-Messungen

3. **Production**
   - Merge zu `main`
   - Deployment via Docker Compose
   - Monitoring für 24h

## Offene Fragen

- [ ] Soll ein User-Präferenz für Sortierung (chronologisch vs. zufällig) später hinzugefügt werden?
- [ ] Soll Preload-Count (2-3 Bilder) konfigurierbar sein?
- [ ] Soll ein Debug-Modus für Preload-Status eingebaut werden?

---

## ✅ Implementierungs-Ergebnis

### Erfolgreich Implementiert
- ✅ Custom Hook `useImagePreloader.js` mit intelligenter Preload-Logik
- ✅ Integration in `SlideshowPage.js`
- ✅ Chronologische Sortierung (Jahr → Upload-Datum)
- ✅ Sequenzieller Gruppenwechsel (kein Zufall mehr)
- ✅ Cache-Management (max 10 Bilder, LRU-Strategy)
- ✅ Timeout-Handling (3s für langsame Verbindungen)
- ✅ Debug-Logging im Development-Mode

### Testing-Ergebnisse
- ✅ Keine doppelten Bilder mehr
- ✅ Keine sichtbaren Ladezeiten
- ✅ Nahtlose Übergänge zwischen Bildern
- ✅ Funktioniert bei langsamen Verbindungen (Production-Server getestet)
- ✅ Chronologische Reihenfolge funktioniert korrekt

### Performance-Verbesserung
- **Vor der Änderung**: 200-1500ms Ladezeit, Flackern, Doppelte Anzeige
- **Nach der Änderung**: 0ms Ladezeit, keine Verzögerungen, professionelle Übergänge

### Dateien Geändert
1. `/frontend/src/hooks/useImagePreloader.js` (NEU)
2. `/frontend/src/Components/Pages/SlideshowPage.js` (MODIFIZIERT)
3. `/README.md` (AKTUALISIERT)
4. `/CHANGELOG.md` (AKTUALISIERT)
5. `/docs/FEATURE_PLAN-preload-image.md` (AKTUALISIERT)

---

**Erstellt von**: GitHub Copilot  
**Review durch**: @lotzm  
**Status**: Feature erfolgreich implementiert und getestet ✅
