Project-Image-Uploader/README.dev.md
matthias.lotz 40aa546498 chore: Improve release script with tag-based commit detection
- Add helpful warning when no previous tag exists
- Show which tag is being used for commit range
- Provide tip for creating retroactive tags
- Fix typo in git log command (--online -> --oneline)
2025-11-29 16:52:19 +01:00

20 KiB
Raw Blame History

Development Setup

⚠️ Wichtige Hinweise für Frontend-Entwickler

🔴 BREAKING CHANGES - API-Umstrukturierung (November 2025)

Im Rahmen der OpenAPI-Auto-Generation wurden massive Änderungen an der API-Struktur vorgenommen:

  • Authentication: Admin-Endpoints laufen jetzt über serverseitige Sessions + CSRF Tokens
  • Route-Struktur: Einige Pfade haben sich geändert (Single Source of Truth: routeMappings.js)
  • Error Handling: Neue HTTP-Status-Codes (403 für Auth-Fehler)

📖 Siehe:

  • frontend/MIGRATION-GUIDE.md - Detaillierte Migrations-Anleitung für Frontend
  • backend/src/routes/README.md - Vollständige API-Route-Dokumentation
  • AUTHENTICATION.md - Auth-System-Setup und Verwendung

Schnellstart

Starten (Development Environment)

# Mit Script (empfohlen):
./dev.sh

# Oder manuell:
docker compose -f docker/dev/docker-compose.yml up -d

Zugriff

Logs verfolgen

# Alle Services:
docker compose -f docker/dev/docker-compose.yml logs -f

# Nur Frontend:
docker compose -f docker/dev/docker-compose.yml logs -f frontend-dev

# Nur Backend:
docker compose -f docker/dev/docker-compose.yml logs -f backend-dev

API-Entwicklung

⚠️ BREAKING CHANGES - Frontend Migration erforderlich

Massive API-Änderungen im November 2025:

  • Session + CSRF Authentication für alle Admin-Endpoints
  • Route-Pfade umstrukturiert (siehe routeMappings.js)
  • Neue Error-Response-Formate

📖 Frontend Migration Guide: frontend/MIGRATION-GUIDE.md

Route-Struktur

Die API verwendet eine Single Source of Truth für Route-Mappings:

📄 backend/src/routes/routeMappings.js - Zentrale Route-Konfiguration

Siehe auch: backend/src/routes/README.md für vollständige API-Übersicht

Wichtige Route-Gruppen:

  • /api/upload, /api/download - Öffentliche Upload/Download-Endpoints
  • /api/manage/:token - Self-Service Management Portal (UUID-Token)
  • /api/admin/* - Admin-Endpoints (Session + CSRF Authentication)
  • /api/system/migration/* - Datenbank-Migrationen

⚠️ Express Route-Reihenfolge beachten: Router mit spezifischen Routes vor generischen Routes mounten!

// ✅ RICHTIG: Spezifisch vor generisch
{ router: 'consent', prefix: '/api/admin' },  // /groups/by-consent
{ router: 'admin', prefix: '/api/admin' },    // /groups/:groupId

// ❌ FALSCH: Generisch fängt alles ab
{ router: 'admin', prefix: '/api/admin' },    // /groups/:groupId matched auf 'by-consent'!
{ router: 'consent', prefix: '/api/admin' },  // Wird nie erreicht

Authentication

Zwei Auth-Systeme parallel:

  1. Admin API (Session + CSRF):

    # .env konfigurieren:
    ADMIN_SESSION_SECRET=$(openssl rand -hex 32)
    
    # Initialen Admin anlegen (falls benötigt)
    curl -c cookies.txt http://localhost:5001/auth/setup/status
    curl -X POST -H "Content-Type: application/json" \
      -c cookies.txt -b cookies.txt \
      -d '{"username":"admin","password":"SuperSicher123"}' \
      http://localhost:5001/auth/setup/initial-admin
    
    # Login + CSRF Token holen
    curl -X POST -H "Content-Type: application/json" \
      -c cookies.txt -b cookies.txt \
      -d '{"username":"admin","password":"SuperSicher123"}' \
      http://localhost:5001/auth/login
    CSRF=$(curl -sb cookies.txt http://localhost:5001/auth/csrf-token | jq -r '.csrfToken')
    
    # Authentifizierter Admin-Request
    curl -b cookies.txt -H "X-CSRF-Token: $CSRF" \
      http://localhost:5001/api/admin/groups
    
  2. Management Portal (UUID Token): User, die Bilder hochladen, erhalten automatisch einen UUID-Token für das Self-Service Management Portal. Über diesen Token / Link können sie ihre hochgeladenen Gruppen verwalten:

    # Automatisch beim Upload generiert
    GET /api/manage/550e8400-e29b-41d4-a716-446655440000
    

📖 Vollständige Doku: AUTHENTICATION.md

Admin-Hinweise: Logout & neue Nutzer

  • Logout: Der Moderationsbereich enthält jetzt einen Logout-Button (Icon in der Kopfzeile). Klick → POST /auth/logout → Session beendet, Login erscheint erneut. Für Skripte kannst du weiterhin curl -b cookies.txt -X POST http://localhost:5001/auth/logout verwenden.
  • Weiterer Admin: Verwende das neue API-basierte Skript ./scripts/create_admin_user.sh --server http://localhost:5001 --username zweiteradmin --password 'SuperPasswort123!' [--admin-user bestehend --admin-password ... --role ... --require-password-change]. Das Skript erledigt Login, CSRF, Duplikats-Check und legt zusätzliche Admins über /api/admin/users an (Fallback: backend/src/scripts/createAdminUser.js).

OpenAPI-Spezifikation

Die OpenAPI-Spezifikation wird automatisch beim Backend-Start generiert:

# Generiert: backend/docs/openapi.json
# Swagger UI: http://localhost:5001/api/docs/

# Manuelle Generierung:
cd backend
node src/generate-openapi.js

Swagger-Annotationen in Routes:

router.get('/example', async (req, res) => {
    /* 
        #swagger.tags = ['Example']
        #swagger.summary = 'Get example data'
        #swagger.responses[200] = { description: 'Success' }
    */
});

Entwicklung

Frontend-Entwicklung

  • Code in frontend/src/ editieren → Hot Module Reload übernimmt Änderungen
  • Volumes: Source-Code wird live in Container gemountet
  • Container-Namen: image-uploader-frontend-dev

Wichtige Komponenten:

  • Components/Pages/MultiUploadPage.js - Upload-Interface mit Consent-Management
  • Components/ComponentUtils/MultiUpload/ConsentCheckboxes.js - GDPR-konforme Consent-UI
  • Components/Pages/ModerationGroupsPage.js - Moderation mit Consent-Filtern
  • services/reorderService.js - Drag-and-Drop Logik
  • hooks/useImagePreloader.js - Slideshow-Preloading

Backend-Entwicklung

  • Code in backend/src/ editieren → Nodemon übernimmt Änderungen automatisch
  • Container-Namen: image-uploader-backend-dev
  • Environment: NODE_ENV=development

Wichtige Module:

  • routes/routeMappings.js - Single Source of Truth für Route-Konfiguration
  • repositories/GroupRepository.js - Consent-Management & CRUD
  • repositories/SocialMediaRepository.js - Plattform- & Consent-Verwaltung
  • routes/batchUpload.js - Upload mit Consent-Validierung
  • middlewares/session.js - Express-Session + SQLite Store
  • middlewares/auth.js - Admin Session-Guard & CSRF-Pflicht
  • database/DatabaseManager.js - Automatische Migrationen
  • services/GroupCleanupService.js - 7-Tage-Cleanup-Logik

Datenbank-Entwicklung

Migrationen erstellen

# Neue Migration anlegen:
touch backend/src/database/migrations/XXX_description.sql

# Migrationen werden automatisch beim Backend-Start ausgeführt
# Manuell: docker compose -f docker/dev/docker-compose.yml restart backend-dev

Datenbank-Zugriff

# SQLite Shell:
docker compose -f docker/dev/docker-compose.yml exec backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db

# Schnellabfragen:
docker compose -f docker/dev/docker-compose.yml exec backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db "SELECT * FROM groups LIMIT 5;"

# Schema anzeigen:
docker compose -f docker/dev/docker-compose.yml exec backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db ".schema"

Migrationen debuggen

# Migration-Status prüfen:
docker compose -f docker/dev/docker-compose.yml exec backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db "SELECT * FROM schema_migrations;"

# Backend-Logs mit Migration-Output:
docker compose -f docker/dev/docker-compose.yml logs backend-dev | grep -i migration

Konfiguration anpassen

  • Frontend: docker/dev/frontend/config/.env
  • Backend: docker/dev/backend/config/.env
  • Nginx: docker/dev/frontend/nginx.conf

Testing

Automatisierte Tests

Das Backend verfügt über eine umfassende Test-Suite mit 45 Tests:

# Alle Tests ausführen:
cd backend
npm test

# Einzelne Test-Suite:
npm test -- tests/api/admin.test.js

# Mit Coverage-Report:
npm test -- --coverage

# Watch-Mode (während Entwicklung):
npm test -- --watch

Test-Struktur:

  • tests/unit/ - Unit-Tests (z.B. Auth-Middleware)
  • tests/api/ - Integration-Tests (API-Endpoints)
  • tests/setup.js - Globale Test-Konfiguration
  • tests/testServer.js - Test-Server-Helper

Test-Features:

  • Jest + Supertest Framework
  • In-Memory SQLite Database (isoliert)
  • Singleton Server Pattern (schnell)
  • 100% Test-Success-Rate (45/45 passing)
  • ~10 Sekunden Ausführungszeit
  • Coverage: 26% Statements, 15% Branches

Test-Umgebung:

  • Verwendet /tmp/test-image-uploader/ für Upload-Tests
  • Eigene Datenbank :memory: (kein Konflikt mit Dev-DB)
  • Environment: NODE_ENV=test
  • Automatisches Cleanup nach Test-Run

Neue Tests hinzufügen:

// tests/api/example.test.js
const { getRequest } = require('../testServer');

describe('Example API', () => {
  it('should return 200', async () => {
    const response = await getRequest()
      .get('/api/example')
      .expect(200);
    
    expect(response.body).toHaveProperty('data');
  });
});

Manuelles Testing

# 1. Upload mit und ohne Workshop-Consent
# 2. Social Media Checkboxen testen (Facebook, Instagram, TikTok)
# 3. Moderation-Filter prüfen:
#    - Alle Gruppen
#    - Nur Werkstatt
#    - Facebook / Instagram / TikTok
# 4. Export-Funktion (CSV/JSON) testen

Cleanup-System testen

# Test-Script verwenden:
./tests/test-cleanup.sh

# Oder manuell:
# 1. Upload ohne Approval
# 2. Gruppe zurückdatieren (Script verwendet)
# 3. Preview: GET http://localhost:5001/api/admin/cleanup/preview
# 4. Trigger: POST http://localhost:5001/api/admin/cleanup/trigger
# 5. Log prüfen: GET http://localhost:5001/api/admin/deletion-log

API-Tests

# Consent-Endpoints:
curl http://localhost:5001/api/social-media/platforms
curl http://localhost:5001/api/groups/by-consent?workshopConsent=true
curl http://localhost:5001/api/admin/consents/export

# Upload testen (mit Consents):
curl -X POST http://localhost:5001/api/upload-batch \
  -F "images=@test.jpg" \
  -F "year=2025" \
  -F "title=Test" \
  -F "name=Developer" \
  -F 'consents={"workshopConsent":true,"socialMediaConsents":[{"platformId":1,"consented":true}]}'

Container-Management

# Status anzeigen:
docker compose -f docker/dev/docker-compose.yml ps

# Container neustarten:
docker compose -f docker/dev/docker-compose.yml restart

# Container neu bauen (nach Package-Updates):
docker compose -f docker/dev/docker-compose.yml build --no-cache

# Stoppen:
docker compose -f docker/dev/docker-compose.yml down

# Mit Volumes löschen (ACHTUNG: Löscht Datenbank!):
docker compose -f docker/dev/docker-compose.yml down -v

Shell-Zugriff

# Frontend Container:
docker compose -f docker/dev/docker-compose.yml exec frontend-dev bash

# Backend Container:
docker compose -f docker/dev/docker-compose.yml exec backend-dev bash

# Datenbank-Shell:
docker compose -f docker/dev/docker-compose.yml exec backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db

Debugging

Backend Debugging

# Live-Logs:
docker compose -f docker/dev/docker-compose.yml logs -f backend-dev

# Nodemon Restart:
# → Änderungen in backend/src/** werden automatisch erkannt

# Fehlerhafte Migration fixen:
# 1. Migration-Eintrag löschen:
docker compose -f docker/dev/docker-compose.yml exec backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db "DELETE FROM schema_migrations WHERE migration_name='XXX.sql';"
# 2. Backend neustarten:
docker compose -f docker/dev/docker-compose.yml restart backend-dev

Frontend Debugging

# React DevTools im Browser verwenden
# Network Tab für API-Calls prüfen
# Console für Fehler checken

# Nginx-Reload (bei Konfig-Änderungen):
docker compose -f docker/dev/docker-compose.yml exec frontend-dev nginx -s reload

Datenbank-Backup & Restore

# Backup:
docker cp image-uploader-backend-dev:/usr/src/app/src/data/db/image_uploader.db ./backup.db

# Restore:
docker cp ./backup.db image-uploader-backend-dev:/usr/src/app/src/data/db/image_uploader.db
docker compose -f docker/dev/docker-compose.yml restart backend-dev

Häufige Probleme

"Migration failed" Fehler

Problem: Inline-Kommentare in SQL-Statements
Lösung: DatabaseManager entfernt diese automatisch (seit Commit 8e62475)

"No such column: display_in_workshop"

Problem: Migration 005 nicht ausgeführt
Lösung: Backend neu starten oder manuell Migration ausführen

Port 3000 bereits belegt

Problem: Anderer Prozess nutzt Port 3000
Lösung:

lsof -ti:3000 | xargs kill -9
# Oder Port in docker/dev/docker-compose.yml ändern

Problem: display_in_workshop fehlt in groupFormatter
Lösung: Bereits gefixt (Commit f049c47)

Git Workflow

# Feature Branch erstellen:
git checkout -b feature/my-feature

# Änderungen committen:
git add .
git commit -m "feat: Add new feature"

# Vor Merge: Code testen!
# - Upload-Flow mit Consents
# - Moderation mit Filtern
# - Slideshow-Funktionalität
# - Cleanup-System

# Push:
git push origin feature/my-feature

Git Hook (optional Absicherung)

Standard-Deployments sollten ADMIN_SESSION_COOKIE_SECURE=true behalten, damit das Session-Cookie nur über HTTPS übertragen wird. Das bereitgestellte Pre-Commit-Hook stellt sicher, dass der Wert in docker/prod/docker-compose.yml automatisch auf true zurückgesetzt wird, falls er versehentlich verändert wurde (z.B. nach einem Test auf HTTP-only Hardware):

ln -s ../../scripts/git-hooks/pre-commit .git/hooks/pre-commit

Nach der Installation aktualisiert der Hook die Datei bei Bedarf und staged sie direkt. Für lokale HTTP-Lab-Deployments nutze eine separate (gitignorierte) docker-compose.override.yml, um ADMIN_SESSION_COOKIE_SECURE=false nur zur Laufzeit zu setzen. Entfernen kannst du den Hook jederzeit über rm .git/hooks/pre-commit.

Host-Separation Testing (Public/Internal Hosts)

Die Applikation unterstützt eine Public/Internal Host-Separation für die Produktion. Lokal kann dies mit /etc/hosts-Einträgen getestet werden.

Schnellstart: Lokales Testing mit /etc/hosts

1. Hosts-Datei bearbeiten:

Linux / Mac:

sudo nano /etc/hosts

Windows (als Administrator):

  1. Notepad öffnen (als Administrator)
  2. Datei öffnen: C:\Windows\System32\drivers\etc\hosts
  3. Dateifilter auf "Alle Dateien" ändern

Füge hinzu:

127.0.0.1   public.test.local
127.0.0.1   internal.test.local

2. Docker .env anpassen:

Bearbeite docker/dev/frontend/config/.env:

API_URL=http://localhost:5001
CLIENT_URL=http://localhost:3000
APP_VERSION=1.1.0
PUBLIC_HOST=public.test.local
INTERNAL_HOST=internal.test.local

Bearbeite docker/dev/docker-compose.yml:

backend-dev:
  environment:
    - PUBLIC_HOST=public.test.local
    - INTERNAL_HOST=internal.test.local
    - ENABLE_HOST_RESTRICTION=true
    - TRUST_PROXY_HOPS=0

frontend-dev:
  environment:
    - HOST=0.0.0.0
    - DANGEROUSLY_DISABLE_HOST_CHECK=true

3. Container starten:

./dev.sh

4. Im Browser testen:

Public Host (http://public.test.local:3000):

  • Upload-Seite funktioniert
  • UUID Management funktioniert (/manage/:token)
  • Social Media Badges angezeigt
  • Kein Admin/Groups/Slideshow-Menü
  • /moderation → 404

Internal Host (http://internal.test.local:3000):

  • Alle Features verfügbar
  • Admin-Bereich, Groups, Slideshow erreichbar
  • Vollständiger API-Zugriff

API-Tests mit curl

Public Host - Blockierte Routen (403):

curl -H "Host: public.test.local" http://localhost:5001/api/admin/deletion-log
curl -H "Host: public.test.local" http://localhost:5001/api/groups
curl -H "Host: public.test.local" http://localhost:5001/api/auth/login

Public Host - Erlaubte Routen:

curl -H "Host: public.test.local" http://localhost:5001/api/upload
curl -H "Host: public.test.local" http://localhost:5001/api/manage/YOUR-UUID
curl -H "Host: public.test.local" http://localhost:5001/api/social-media/platforms

Internal Host - Alle Routen:

curl -H "Host: internal.test.local" http://localhost:5001/api/groups
curl -H "Host: internal.test.local" http://localhost:5001/api/admin/deletion-log

Frontend Code-Splitting testen

Public Host:

  1. Browser DevTools → Network → JS Filter
  2. Öffne http://public.test.local:3000
  3. Erwartung: Slideshow/Admin/Groups-Bundles werden nicht geladen
  4. Navigiere zu /admin → Redirect zu 404

Internal Host:

  1. Öffne http://internal.test.local:3000
  2. Navigiere zu /slideshow
  3. Erwartung: Lazy-Bundle wird erst jetzt geladen (Code Splitting)

Rate Limiting testen

Public Host: 20 Uploads/Stunde

for i in {1..25}; do
  echo "Upload $i"
  curl -X POST -H "Host: public.test.local" \
    http://localhost:5001/api/upload \
    -F "file=@test.jpg" -F "group=Test"
done
# Ab Upload 21: HTTP 429 (Too Many Requests)

Troubleshooting

"Invalid Host header"

  • Lösung: DANGEROUSLY_DISABLE_HOST_CHECK=true in .env.development (Frontend)

"Alle Routen geben 403"

  • Prüfe ENABLE_HOST_RESTRICTION=true
  • Prüfe PUBLIC_HOST / INTERNAL_HOST ENV-Variablen
  • Container neu starten

"public.test.local nicht erreichbar"

  • Prüfe /etc/hosts: cat /etc/hosts | grep test.local
  • DNS-Cache leeren:
    • Linux: sudo systemd-resolve --flush-caches
    • Mac: sudo dscacheutil -flushcache
    • Windows: ipconfig /flushdns

Feature deaktivieren (Standard Dev):

backend-dev:
  environment:
    - ENABLE_HOST_RESTRICTION=false

Production Setup

Für Production mit echten Subdomains siehe:

  • FeatureRequests/FEATURE_PLAN-FrontendPublic.md (Sektion 12: Testing Strategy)
  • nginx-proxy-manager Konfiguration erforderlich
  • Hosts: deinprojekt.hobbyhimmel.de (public), deinprojekt.lan.hobbyhimmel.de (internal)

🚀 Release Management

Automated Release (EMPFOHLEN)

Ein Befehl macht alles:

npm run release        # Patch: 1.2.0 → 1.2.1
npm run release:minor  # Minor: 1.2.0 → 1.3.0  
npm run release:major  # Major: 1.2.0 → 2.0.0

Was passiert automatisch:

  1. Version in allen package.json erhöht
  2. Footer.js, OpenAPI-Spec, Docker-Images aktualisiert
  3. CHANGELOG.md automatisch generiert aus Git-Commits
  4. Git Commit erstellt
  5. Git Tag erstellt
  6. Preview anzeigen + Bestätigung

Dann nur noch:

git push && git push --tags

Beispiel-Workflow:

# Features entwickeln mit Conventional Commits:
git commit -m "feat: Add user login"
git commit -m "fix: Fix button alignment"
git commit -m "refactor: Extract ConsentFilter component"

# Release erstellen:
npm run release:minor

# Preview wird angezeigt, dann [Y] drücken
# Push:
git push && git push --tags

CHANGELOG wird automatisch generiert!

Das Release-Script (scripts/release.sh) gruppiert deine Commits nach Typ:

  • feat: Features
  • fix:🐛 Fixes
  • refactor:♻️ Refactoring
  • chore:🔧 Chores
  • docs:📚 Documentation

Wichtig: Verwende Conventional Commits!

Manuelle Scripts (falls nötig)

# Version nur synchronisieren (ohne Bump):
./scripts/sync-version.sh

# Version manuell bumpen:
./scripts/bump-version.sh patch  # oder minor/major

Version-Synchronisation:

  • Single Source of Truth: frontend/package.json
  • Wird synchronisiert zu: backend/package.json, Footer.js, generate-openapi.js, Docker Images

Nützliche Befehle

# Alle Container-IDs:
docker ps -a

# Speicherplatz prüfen:
docker system df

# Ungenutztes aufräumen:
docker system prune -a

# Logs durchsuchen:
docker compose -f docker/dev/docker-compose.yml logs | grep ERROR

# Performance-Monitoring:
docker stats