Project-Image-Uploader/frontend/MIGRATION-GUIDE.md
matthias.lotz 6332b82c6a Feature Request: admin session security
- replace bearer auth with session+CSRF flow and add admin user directory

- update frontend moderation flow, force password change gate, and new CLI

- refresh changelog/docs/feature plan + ensure swagger dev experience
2025-11-23 21:18:42 +01:00

376 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Frontend Migration Guide - API Umstrukturierung
**Datum:** 16. November 2025
**Betrifft:** ALLE API-Aufrufe im Frontend
**Status:** ⚠️ Aktion erforderlich - ALLE Routen prüfen!
---
## <20> BREAKING CHANGE: Konsistente `/api` Prefixes
**ALLE API-Routen haben sich geändert!**
### Vorher (inkonsistent):
```javascript
// Teils mit /api
fetch('/api/upload/batch')
fetch('/api/manage/xyz')
// Teils OHNE /api - FALSCH!
fetch('/groups/123')
fetch('/groups/123/approve')
fetch('/moderation/groups/123')
```
### Jetzt (konsistent):
```javascript
// ALLE Routen mit /api Prefix
fetch('/api/upload/batch')
fetch('/api/manage/xyz')
fetch('/api/groups/123') // Public
fetch('/api/admin/groups/123/approve') // Admin
fetch('/api/admin/groups/123') // Admin
```
---
## 🔒 Admin API Authentication
Alle Admin-Endpoints (`/api/admin/*` und `/api/system/*`) benötigen jetzt **Bearer Token Authentication**.
### Route-Hierarchie
1. **Public API**: `/api/*`
- Öffentlich zugänglich
- `/api/upload`, `/api/groups`, `/api/download`, etc.
2. **Management API**: `/api/manage/*`
- Token-basiert (UUID aus Upload-Response)
- Für Gruppenbesitzer
3. **Admin API**: `/api/admin/*` ⚠️ **BEARER TOKEN ERFORDERLICH**
- Moderation, Logs, Consents
- `/api/admin/groups`, `/api/admin/deletion-log`, etc.
4. **System API**: `/api/system/migration/*` ⚠️ **BEARER TOKEN ERFORDERLICH**
- Wartungsfunktionen
### Betroffene Admin-Endpoints
- `/api/admin/groups` - Gruppen auflisten
- `/api/admin/groups/:id` - Gruppe abrufen
- `/api/admin/groups/:id/approve` - Gruppe genehmigen
- `/api/admin/groups/:id` - Gruppe löschen
- `/api/admin/groups/:id/images/:imageId` - Bild löschen
- `/api/admin/groups/by-consent` - Nach Consent filtern
- `/api/admin/consents/export` - Consent-Export
- `/api/admin/social-media/platforms` - Plattformen auflisten
- `/api/admin/reorder/:groupId/images` - Bilder neu anordnen
- `/api/admin/deletion-log` - Deletion Log
- `/api/admin/cleanup/*` - Cleanup-Funktionen
- `/api/admin/rate-limiter/stats` - Rate-Limiter-Statistiken
- `/api/admin/management-audit` - Audit-Log
**System-Endpoints:**
- `/api/system/migration/migrate` - Migration ausführen
- `/api/system/migration/rollback` - Migration zurückrollen
---
## 📝 Erforderliche Änderungen
### 1. ALLE API-Routen prüfen und `/api` hinzufügen
**Schritt 1**: Finde alle API-Aufrufe im Frontend:
```bash
# Alle fetch/axios Aufrufe finden
grep -r "fetch\(" frontend/src/
grep -r "axios\." frontend/src/
```
**Schritt 2**: Prüfe jede Route und füge `/api` Prefix hinzu (falls fehlend):
```javascript
// ❌ FALSCH (alte Routen)
fetch('/groups/123')
fetch('/groups/123/approve')
fetch('/moderation/groups/123')
// ✅ RICHTIG (neue Routen)
fetch('/api/groups/123') // Public
fetch('/api/admin/groups/123/approve') // Admin (+ Bearer Token!)
fetch('/api/admin/groups/123') // Admin (+ Bearer Token!)
```
### 2. Admin-Session & CSRF einrichten
Die Admin-API verwendet jetzt serverseitige Sessions mit CSRF-Schutz. Statt Tokens in `.env` zu hinterlegen, erfolgt die Authentifizierung über Login-Endpunkte:
1. **Setup-Status abfragen** `GET /auth/setup/status``{ needsSetup, hasSession }`
2. **Ersten Admin anlegen** `POST /auth/setup/initial-admin` (nur einmal nötig)
3. **Login** `POST /auth/login` mit `{ username, password }`
4. **CSRF Token holen** `GET /auth/csrf-token` (liefert `csrfToken` und setzt HttpOnly Session-Cookie)
Alle nachfolgenden Admin-Requests senden automatisch das Session-Cookie (`credentials: 'include'`) und den `X-CSRF-Token` Header.
### 3. API-Aufrufe für Admin-Endpoints anpassen
#### Vorher (ohne Session):
```javascript
const response = await fetch('/api/admin/groups');
```
#### Nachher (mit Session + CSRF):
```javascript
const response = await fetch('/api/admin/groups', {
method: 'GET',
credentials: 'include',
headers: {
'X-CSRF-Token': csrfToken, // nur bei mutierenden Requests zwingend nötig
}
});
```
### 3. Zentrale API-Helper-Funktion erstellen
**Empfohlen**: Nutze `src/services/adminApi.js` als einzige Stelle, die Session- und CSRF-Handling kapselt:
```javascript
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
let csrfToken = null;
const ensureCsrfToken = async () => {
if (!csrfToken) {
const response = await fetch('/auth/csrf-token', { credentials: 'include' });
const data = await response.json();
csrfToken = data.csrfToken;
}
return csrfToken;
};
export const adminFetch = async (url, options = {}) => {
const method = (options.method || 'GET').toUpperCase();
const headers = new Headers(options.headers || {});
if (!SAFE_METHODS.has(method)) {
headers.set('X-CSRF-Token', await ensureCsrfToken());
}
const response = await fetch(url, {
...options,
method,
credentials: 'include',
headers
});
if (!response.ok) {
throw await parseError(response);
}
return response;
};
```
### 4. Error Handling erweitern
```javascript
try {
const response = await adminFetch('/api/admin/groups');
const data = await response.json();
// ...
} catch (error) {
if (error.status === 401) {
// Session abgelaufen
redirectToLogin();
} else if (error.status === 403 && error.reason === 'CSRF_INVALID') {
// CSRF neu anfordern
await adminSession.refreshStatus();
} else if (error.status === 429) {
notifyRateLimit();
} else {
console.error('Admin API error:', error);
}
}
```
---
## 🔍 Betroffene Dateien finden
### Alle API-Calls prüfen (KRITISCH!)
```bash
cd frontend/src
# ALLE API-Calls finden (fetch + axios):
grep -rn "fetch(" --include="*.js" --include="*.jsx"
grep -rn "axios\." --include="*.js" --include="*.jsx"
# Spezifisch nach alten Routen OHNE /api suchen:
grep -rn "fetch('/groups" --include="*.js"
grep -rn "fetch('/moderation" --include="*.js"
# Admin-API-Calls finden:
grep -rn "/api/admin" --include="*.js" --include="*.jsx"
```
**Bekannte betroffene Dateien:**
### Routen ohne `/api` Prefix (MÜSSEN GEFIXT WERDEN):
- `Components/Pages/ModerationGroupsPage.js`
-`/groups/${groupId}/approve` → ✅ `/api/admin/groups/${groupId}/approve`
-`/groups/${groupId}` (DELETE) → ✅ `/api/admin/groups/${groupId}`
-`/api/admin/social-media/platforms` für Moderationsfilter
-`/api/social-media/platforms` für öffentliche Formulare (keine Session nötig)
- `Components/Pages/ModerationGroupImagesPage.js`
-`/moderation/groups/${groupId}` → ✅ `/api/admin/groups/${groupId}`
- `Components/Pages/PublicGroupImagesPage.js`
-`/groups/${groupId}` → ✅ `/api/groups/${groupId}`
### Admin-Endpoints (Session + CSRF erforderlich):
- `Components/Pages/ModerationGroupsPage.js` - Alle Moderations-Calls
- `Components/Pages/ModerationGroupImagesPage.js` - Gruppe laden + Bilder löschen
- `Components/ComponentUtils/DeletionLogSection.js` - Deletion Log
- `Components/ComponentUtils/ConsentManager.js` - Consent-Export (Admin)
- `services/reorderService.js` - Admin-Reorder (falls im Einsatz)
### Public/Management Endpoints (nur Pfad prüfen):
- `Utils/batchUpload.js` - Bereits korrekt (`/api/...`)
- `Components/Pages/ManagementPortalPage.js` - Bereits korrekt (`/api/manage/...`)
- `Utils/sendRequest.js` - Bereits korrekt (axios)
---
## ✅ Checkliste
### Phase 1: Route-Prefixes (ALLE Dateien)
- [ ] Alle `fetch()` und `axios` Calls gefunden (grep)
- [ ] Alle Routen ohne `/api` Prefix identifiziert
- [ ] `/api` Prefix zu Public-Routen hinzugefügt (`/api/groups`, `/api/upload`)
- [ ] Admin-Routen auf `/api/admin/*` geändert
- [ ] Management-Routen auf `/api/manage/*` geprüft (sollten schon korrekt sein)
### Phase 2: Admin Authentication (Session)
- [ ] `AdminSessionProvider` wrappt die App
- [ ] `AdminSessionGate` schützt alle Moderationsseiten
- [ ] `adminApi.js` nutzt `credentials: 'include'` + `X-CSRF-Token`
- [ ] Login- und Initial-Setup-Formulare eingebunden
- [ ] Fehlerbehandlung für `401/403 (SESSION_REQUIRED/CSRF_INVALID)` ergänzt
### Phase 3: Testing & Deployment
- [ ] Frontend lokal getestet (alle Routen)
- [ ] Admin-Funktionen getestet (Approve, Delete, etc.)
- [ ] Public-Routen getestet (Gruppe laden, Upload)
- [ ] Production `.env` aktualisiert
---
## 🧪 Testing
### Lokales Testing
1. Backend starten (`npm run dev`) stellt Session- & Auth-Routen bereit.
2. Frontend starten (`npm start`).
3. `/moderation` öffnen:
- **Falls kein Admin existiert** → Setup-Formular ausfüllen.
- Danach mit frisch erstellten Credentials anmelden.
4. Moderationsfunktionen (Approve/Delete/Reorder/Consent-Export) durchspielen.
### Test-Fälle
- ✅ Moderation funktioniert mit aktiver Session
- ✅ Login/Logout ändert sofort den Zugriff auf Seiten
- ✅ CSRF-geschützte Aktionen schlagen fehl, wenn Token manipuliert wird
- ✅ Consent-Export & Reorder funktionieren weiterhin
- ✅ Öffentliche Routen bleiben ohne Login erreichbar
---
## 📚 Weitere Dokumentation
- **Backend Auth-Doku**: `AUTHENTICATION.md`
- **API Route-Übersicht**: `backend/src/routes/README.md`
- **Route-Konfiguration**: `backend/src/routes/routeMappings.js`
- **OpenAPI Spec**: `backend/docs/openapi.json`
- **Swagger UI**: http://localhost:5001/api/docs/ (dev only)
---
## 🆘 Troubleshooting
### Problem: "Session Required" / 403 Fehler
**Ursachen:**
1. Session abgelaufen (Inaktivität, Browser geschlossen)
2. Cookies blockiert (Third-Party/SameSite Einstellungen)
**Lösung:**
- Seite neu laden → Login-Formular erscheint
- Browser-Einstellungen prüfen: Cookies für Host erlauben
### Problem: "CSRF invalid"
**Ursachen:**
- CSRF-Token nicht gesetzt oder veraltet
**Lösung:**
- `AdminSessionGate` neu laden → holt automatisch neues Token
- Sicherstellen, dass `adminApi` bei mutierenden Calls `X-CSRF-Token` setzt
### Problem: Setup-Formular erscheint nicht
**Ursachen:**
- Bereits ein Admin vorhanden
**Lösung:**
- Bestehende Admin-Credentials verwenden
- Falls vergessen: über Datenbank (Tabelle `admin_users`) neuen Admin eintragen oder Passwort zurücksetzen
### Problem: Login schlägt wiederholt fehl
**Checks:**
1. Backend-Logs prüfen (Rate-Limits? falsches Passwort?)
2. Prüfen, ob `ADMIN_SESSION_SECRET` gesetzt ist (sonst keine stabilen Sessions)
3. Browser-Konsole → Network Request `POST /auth/login` analysieren
---
## 🚀 Deployment
### Production Checklist
- [ ] Sicheres `ADMIN_SESSION_SECRET` (>= 32 random bytes) gesetzt
- [ ] HTTPS aktiviert (Cookies: `Secure`, `SameSite=Strict`)
- [ ] Session-DB Pfad (`ADMIN_SESSION_DIR`/`ADMIN_SESSION_DB`) persistent gemacht
- [ ] Admin-Benutzer erstellt und dokumentiert (kein Secret im Frontend)
- [ ] Monitoring/Alerting für fehlgeschlagene Logins eingerichtet
### Docker Deployment
```yaml
# docker-compose.yml
services:
backend:
environment:
- ADMIN_SESSION_SECRET=${ADMIN_SESSION_SECRET}
- ADMIN_SESSION_DIR=/data/sessions
# optional weitere Backend-ENV Variablen
frontend:
environment:
- PUBLIC_URL=${PUBLIC_URL:-/}
```
```bash
# .env (nicht in Git!)
ADMIN_SESSION_SECRET=$(openssl rand -hex 32)
```
---
**Fragen?** Siehe `AUTHENTICATION.md` für detaillierte Backend-Dokumentation.
**Status der Backend-Changes:** ✅ Vollständig implementiert und getestet (45/45 Tests passing)