8.4 KiB
Feature: Preview-Bilder für Galerie
Branch: feature/preview-images
Datum: 29. Oktober 2025
🎯 Ziel
Generierung und Verwendung von optimierten Preview-Bildern (Thumbnails) für Galerie-Ansichten, um:
- Ladezeiten drastisch zu reduzieren
- Bandbreite zu sparen
- User Experience zu verbessern
- Mobile Performance zu optimieren
📐 Architektur-Überblick
Aktuelle Situation
- Bilder werden in voller Auflösung in Galerien geladen
- Path:
backend/src/data/images/(Original-Bilder) - Keine Thumbnails oder Preview-Varianten
Ziel-Architektur
backend/src/data/
├── images/ # Original-Bilder (unverändert)
│ └── X_JeZj0TsQ.JPG
└── previews/ # NEU: Preview-Bilder (optimiert)
└── X_JeZj0TsQ.JPG (oder .webp)
Thumbnail-Spezifikationen
- Größe: Max. 800px Breite (beibehält Aspect Ratio)
- Format: JPEG (85% Qualität) oder WebP (falls unterstützt)
- Verwendung: Galerie-Views (GroupsOverviewPage, ModerationGroupsPage)
- Original: Slideshow-View und Download behalten Original-Bilder
🔧 Technische Implementierung
Backend: Sharp Library
Warum Sharp?
- Schnell (nutzt libvips)
- Unterstützt JPEG, PNG, WebP
- Läuft in Node.js ohne externe Binaries
- Unterstützt Resize, Optimize, Format-Konvertierung
Installation:
npm install sharp --save
Datenbankschema-Erweiterung
-- Erweitere images Tabelle um preview_path
ALTER TABLE images ADD COLUMN preview_path TEXT;
-- Index für schnelle Abfragen
CREATE INDEX IF NOT EXISTS idx_images_preview_path ON images(preview_path);
📋 Implementierungs-Phasen
Phase 1: Backend - Preview-Generierung (6-10h)
1.1 Service-Layer erstellen
Datei: backend/src/services/ImagePreviewService.js
Funktionen:
generatePreview(originalPath, outputPath, options)- Generiert einzelnes PreviewgeneratePreviewsForGroup(groupId)- Batch-Generierung für Upload-GruppecleanupOrphanedPreviews()- Entfernt nicht mehr verwendete PreviewsgetPreviewPath(originalFileName)- Gibt Preview-Pfad zurück
Optionen:
{
width: 800, // Max-Breite in px
quality: 85, // JPEG-Qualität
format: 'jpeg', // 'jpeg' oder 'webp'
withoutEnlargement: true // Keine Vergrößerung kleiner Bilder
}
1.2 Upload-Route erweitern
Datei: backend/src/routes/upload.js & backend/src/routes/batchUpload.js
- Nach erfolgreichem Upload: Preview-Generierung triggern
- Preview-Pfad in DB speichern
- Fehlerbehandlung: Bei Preview-Fehler Upload trotzdem erfolgreich
1.3 DB-Schema Migration
Datei: backend/src/database/migrations/003_add_preview_path.sql (NEU)
-- Migration 003: Add preview_path column
ALTER TABLE images ADD COLUMN preview_path TEXT;
CREATE INDEX IF NOT EXISTS idx_images_preview_path ON images(preview_path);
Datei: backend/src/database/DatabaseManager.js
- Erweitere
initDatabase()um Migration-Support - Auto-run Migrations beim Start
1.4 API-Endpunkte erweitern
Bestehende Endpoints anpassen:
GET /groups- Rückgabe mitpreviewPathfür jedes BildGET /groups/:groupId- Rückgabe mitpreviewPathGET /moderation/groups- Rückgabe mitpreviewPath
Neue Endpoints (optional):
POST /groups/:groupId/regenerate-previews- Regeneriert Previews für GruppeGET /previews/:fileName- Serve Preview-Bilder (analog zu/upload/:fileName)
1.5 Constants & Config
Datei: backend/src/constants.js
const PREVIEW_FS_DIR = 'data/previews';
const PREVIEW_CONFIG = {
width: 800,
quality: 85,
format: 'jpeg'
};
Phase 2: Backend - Batch-Migration bestehender Bilder (2-4h)
2.1 Migration-Script
Datei: backend/src/scripts/generatePreviewsForExisting.js
- Liest alle Bilder aus DB ohne
preview_path - Generiert Previews für alle bestehenden Bilder
- Aktualisiert DB mit Preview-Pfaden
- Progress-Logging
Ausführung:
node backend/src/scripts/generatePreviewsForExisting.js
Oder als Express-Endpoint für Admin:
POST /admin/migrate-previews(mit Basic Auth)
Phase 3: Frontend - Preview-Nutzung (3-6h)
3.1 API-Response erweitern
Typ-Definitionen (optional):
interface Image {
id: number;
fileName: string;
originalName: string;
filePath: string; // Original-Bild
previewPath?: string; // NEU: Preview-Bild
uploadOrder: number;
fileSize: number;
mimeType: string;
}
3.2 Component Updates
Dateien zu ändern:
frontend/src/Components/ComponentUtils/GroupCard.jsfrontend/src/Components/Pages/GroupsOverviewPage.jsfrontend/src/Components/Pages/ModerationGroupsPage.js
Logik:
const imageSrc = image.previewPath || image.filePath;
// Fallback auf Original, falls Preview fehlt
3.3 Slideshow beibehält Original
Datei: frontend/src/Components/Pages/SlideshowPage.js
- Keine Änderung - Slideshow nutzt weiterhin
filePath(Original)
Phase 4: Testing & Optimierung (2-4h)
4.1 Unit Tests
ImagePreviewService.test.js- Service-Logik- Test mit verschiedenen Bildformaten (JPEG, PNG)
- Error-Handling Tests
4.2 Integration Tests
- Upload → Preview-Generierung → DB-Update
- API-Response enthält
previewPath - Frontend lädt Preview-Bilder
4.3 Performance-Messung
- Vergleich Ladezeiten: Original vs. Preview
- Bundle-Size (Sharp Library Impact)
- Memory-Usage bei Batch-Generierung
4.4 Cleanup & Docs
README.mdUpdate mit Preview-FeatureCHANGELOG.mdEintrag- Code-Kommentare & JSDoc
⏱️ Zeitschätzung
| Phase | Aufgabe | Geschätzt |
|---|---|---|
| 1.1 | ImagePreviewService | 2-3h |
| 1.2 | Upload-Route erweitern | 1-2h |
| 1.3 | DB-Migration | 1h |
| 1.4 | API-Endpoints | 1-2h |
| 1.5 | Config/Constants | 0.5h |
| 2.1 | Batch-Migration Script | 2-4h |
| 3.1-3.3 | Frontend Updates | 3-6h |
| 4.1-4.4 | Testing & Docs | 2-4h |
| Gesamt | 12-22h |
Realistische Schätzung: 2-3 Arbeitstage
🚀 Deployment-Strategie
Schritt 1: Backend-Deploy mit Preview-Generierung
- Deploy neuer Backend-Code
- DB-Migration läuft automatisch beim Start
- Neue Uploads erhalten automatisch Previews
Schritt 2: Batch-Migration (einmalig)
docker exec image-uploader-backend node src/scripts/generatePreviewsForExisting.js
oder via Admin-Endpoint
Schritt 3: Frontend-Deploy
- Deploy Frontend mit Preview-Support
- Fallback auf Original-Bilder bleibt aktiv
Rollback-Plan
- Preview-Feature ist opt-in (Fallback auf
filePath) - Bei Problemen: Frontend-Rollback ohne Backend-Änderung nötig
📊 Erwartete Verbesserungen
Dateigrößen (Beispiel)
- Original JPEG (3000x2000px): ~2-3 MB
- Preview JPEG (800x533px, 85%): ~80-150 KB
- Einsparung: ~95%
Ladezeiten (Galerie mit 20 Bildern)
- Vorher: 20 × 2.5 MB = 50 MB
- Nachher: 20 × 100 KB = 2 MB
- Verbesserung: ~96% schneller
⚠️ Risiken & Mitigation
Risiko 1: Sharp Build-Fehler in Docker
Mitigation:
- Alpine-kompatible Sharp-Version testen
- Falls nötig:
python3,make,g++in Dockerfile hinzufügen
Risiko 2: Disk-Space Verdopplung
Mitigation:
- Previews sind ~5% der Original-Größe
- Cleanup-Script für verwaiste Previews
- Optional: alte Previews nach X Tagen löschen
Risiko 3: CPU-Last bei Batch-Migration
Mitigation:
- Batch-Processing mit Chunk-Size (z.B. 10 Bilder parallel)
- Progress-Logging
- Optional: Background-Job Queue (Bull, Agenda)
🔄 Zukünftige Erweiterungen
- WebP-Support: Kleinere Dateien, bessere Compression
- Responsive Previews: Mehrere Größen (400px, 800px, 1200px)
- Lazy-Loading: Intersection Observer für On-Demand-Loading
- CDN-Integration: Previews auf S3/CloudFront auslagern
- Image-Optimization: Auto-Rotation (EXIF), Strip Metadata
📝 Acceptance Criteria
- Neue Uploads generieren automatisch Previews
- Bestehende Bilder haben Previews nach Migration
- Galerie-Views laden Preview-Bilder (keine Originals)
- Slideshow lädt weiterhin Original-Bilder
- API liefert sowohl
filePathals auchpreviewPath - Fallback auf Original funktioniert, wenn Preview fehlt
- Ladezeit-Verbesserung messbar (>80%)
- Tests bestehen (Unit + Integration)
- Dokumentation aktualisiert
Erstellt am: 29. Oktober 2025
Zuletzt aktualisiert: 29. Oktober 2025