# 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) ```bash # Mit Script (empfohlen): ./dev.sh # Oder manuell: docker compose -f docker/dev/docker-compose.yml up -d ``` ### Zugriff - **Frontend**: http://localhost:3000 (Hot Module Reloading aktiv) - **Backend**: http://localhost:5001 (API) - **API Documentation**: http://localhost:5001/api/docs/ (Swagger UI, nur in Development verfügbar) - **Slideshow**: http://localhost:3000/slideshow - **Moderation**: http://localhost:3000/moderation (Login über Admin Session) ### Logs verfolgen ```bash # 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! ```javascript // ✅ 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)**: ```bash # .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: ```bash # 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: ```bash # 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:** ```javascript 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 ```bash # 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 ```bash # 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 ```bash # 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: ```bash # 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:** ```javascript // 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 ### Consent-System testen ```bash # 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 ```bash # 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 ``` ### Telegram-Benachrichtigungen testen **Voraussetzung:** Bot-Setup abgeschlossen (siehe `scripts/README.telegram.md`) ```bash # 1. ENV-Variablen in docker/dev/backend/config/.env konfigurieren: TELEGRAM_ENABLED=true TELEGRAM_BOT_TOKEN= TELEGRAM_CHAT_ID= # 2. Backend neu starten (lädt neue ENV-Variablen): docker compose -f docker/dev/docker-compose.yml restart backend-dev # 3. Test-Nachricht wird automatisch beim Server-Start gesendet docker compose -f docker/dev/docker-compose.yml logs -f backend-dev # 4. Upload-Benachrichtigung testen (Phase 3+): curl -X POST http://localhost:5001/api/upload-batch \ -F "images=@test.jpg" \ -F "year=2024" \ -F "title=Test Upload" \ -F "name=Test User" \ -F 'consents={"workshopConsent":true,"socialMediaConsents":[]}' # → Prüfe Telegram-Gruppe auf Benachrichtigung # 5. Service manuell deaktivieren: TELEGRAM_ENABLED=false ``` ### API-Tests ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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**: ```bash lsof -ti:3000 | xargs kill -9 # Oder Port in docker/dev/docker-compose.yml ändern ``` ### Consent-Filter zeigt nichts **Problem**: `display_in_workshop` fehlt in groupFormatter **Lösung**: Bereits gefixt (Commit f049c47) ## Git Workflow ```bash # 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): ```bash 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:** ```bash 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`: ```bash 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`: ```yaml 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:** ```bash ./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):** ```bash 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:** ```bash 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:** ```bash 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 ```bash 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):** ```yaml 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:** ```bash 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: ```bash git push && git push --tags ``` ### Beispiel-Workflow: ```bash # 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](https://www.conventionalcommits.org/)! ### Manuelle Scripts (falls nötig) ```bash # 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 ```bash # 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 ```