- Create TelegramNotificationService with all notification methods - Add node-telegram-bot-api dependency - Integrate service into server.js (auto-test on dev startup) - Add ENV variables to docker/dev/backend/config/.env - Create unit tests (10/14 passing - mock issues for 4) - Update README.dev.md with Telegram testing guide Service Features: - sendTestMessage() - Test connection - sendUploadNotification() - Phase 3 ready - sendConsentChangeNotification() - Phase 4 ready - sendGroupDeletedNotification() - Phase 4 ready - sendDeletionWarning() - Phase 5 ready Phase 2 complete: Backend service ready for integration.
21 KiB
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 Frontendbackend/src/routes/README.md- Vollständige API-Route-DokumentationAUTHENTICATION.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
- 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
# 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:
-
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 -
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 weiterhincurl -b cookies.txt -X POST http://localhost:5001/auth/logoutverwenden. - 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/usersan (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-ManagementComponents/ComponentUtils/MultiUpload/ConsentCheckboxes.js- GDPR-konforme Consent-UIComponents/Pages/ModerationGroupsPage.js- Moderation mit Consent-Filternservices/reorderService.js- Drag-and-Drop Logikhooks/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-Konfigurationrepositories/GroupRepository.js- Consent-Management & CRUDrepositories/SocialMediaRepository.js- Plattform- & Consent-Verwaltungroutes/batchUpload.js- Upload mit Consent-Validierungmiddlewares/session.js- Express-Session + SQLite Storemiddlewares/auth.js- Admin Session-Guard & CSRF-Pflichtdatabase/DatabaseManager.js- Automatische Migrationenservices/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-Konfigurationtests/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
Consent-System testen
# 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
Telegram-Benachrichtigungen testen
Voraussetzung: Bot-Setup abgeschlossen (siehe scripts/README.telegram.md)
# 1. ENV-Variablen in docker/dev/backend/config/.env konfigurieren:
TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=<dein-bot-token>
TELEGRAM_CHAT_ID=<deine-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
# 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
Consent-Filter zeigt nichts
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):
- Notepad öffnen (als Administrator)
- Datei öffnen:
C:\Windows\System32\drivers\etc\hosts - 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:
- Browser DevTools → Network → JS Filter
- Öffne
http://public.test.local:3000 - Erwartung: Slideshow/Admin/Groups-Bundles werden nicht geladen
- Navigiere zu
/admin→ Redirect zu 404
Internal Host:
- Öffne
http://internal.test.local:3000 - Navigiere zu
/slideshow - 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=truein.env.development(Frontend)
"Alle Routen geben 403"
- Prüfe
ENABLE_HOST_RESTRICTION=true - Prüfe
PUBLIC_HOST/INTERNAL_HOSTENV-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
- Linux:
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:
- ✅ Version in allen package.json erhöht
- ✅ Footer.js, OpenAPI-Spec, Docker-Images aktualisiert
- ✅ CHANGELOG.md automatisch generiert aus Git-Commits
- ✅ Git Commit erstellt
- ✅ Git Tag erstellt
- ✅ 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:→ ✨ Featuresfix:→ 🐛 Fixesrefactor:→ ♻️ Refactoringchore:→ 🔧 Choresdocs:→ 📚 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