diff --git a/docs/FEATURE_PLAN-social-media.md b/docs/FEATURE_PLAN-social-media.md new file mode 100644 index 0000000..931e123 --- /dev/null +++ b/docs/FEATURE_PLAN-social-media.md @@ -0,0 +1,1010 @@ +# Feature Plan: Social Media Consent Management + +## 📋 Übersicht + +**Feature**: Einwilligungsverwaltung für Bildveröffentlichung in Werkstatt und Social Media +**Ziel**: Rechtskonforme Einholung und Verwaltung von Nutzerzustimmungen für die Anzeige von Bildern in der Werkstatt und Veröffentlichung auf Social Media Plattformen +**Priorität**: High (Rechtliche Anforderung) +**Geschätzte Implementierungszeit**: 4-5 Tage +**Branch**: `feature/SocialMedia` + +## 🎯 Funktionale Anforderungen + +### Must-Have (Phase 1) +- [x] **Pflicht-Zustimmung**: Nutzer muss der Anzeige in der Werkstatt zustimmen (ohne Zustimmung kein Upload möglich) +- [x] **Social Media Zustimmung**: Optionale, separate Zustimmungen für verschiedene Social Media Plattformen (Facebook, Instagram, TikTok) +- [x] **Aufklärungstext**: Informativer Text über Prüfung und Freigabe durch Hobbyhimmel +- [x] **Datenbankpersistierung**: Speicherung der Zustimmungen pro Upload-Gruppe mit Zeitstempel +- [x] **Moderation-Filter**: Filter im Moderation Panel nach Consent-Status +- [x] **Visuelle Kennzeichnung**: Icons/Tags für Social Media Freigaben im Moderation Panel +- [x] **Export-Funktion**: Möglichkeit zum Export der Consent-Daten für rechtliche Dokumentation +- [x] **Gruppen-ID Anzeige**: Nach Upload wird Gruppen-ID als Referenz angezeigt +- [x] **Widerrufs-Information**: Hinweis auf Kontaktmöglichkeit für Widerruf der Zustimmung + +### Nice-to-Have (Phase 2) +- [ ] **Verwaltungslink**: Kryptischer UUID-basierter Link für Nutzer zur Selbstverwaltung +- [ ] **Self-Service Portal**: Nutzer kann über Link Beschreibungen ändern, Bilder löschen, Consents widerrufen +- [ ] **E-Mail-Benachrichtigung**: Optional E-Mail mit Verwaltungslink nach Upload +- [ ] **Consent-Historie**: Vollständige Audit-Trail aller Consent-Änderungen + +## 🔒 Rechtliche Überlegungen + +### DSGVO-Konformität +- **Eindeutige Einwilligung**: Jede Zustimmung muss explizit durch Checkbox erfolgen (kein Pre-Check) +- **Informierte Einwilligung**: Klare Beschreibung, wofür die Daten verwendet werden +- **Widerrufbarkeit**: Nutzer muss Zustimmung jederzeit widerrufen können +- **Dokumentation**: Zeitstempel und Umfang der Einwilligung müssen gespeichert werden +- **Zweckbindung**: Separate Zustimmungen für verschiedene Verwendungszwecke (Werkstatt vs. Social Media) + +### Empfohlene Texte + +#### Werkstatt-Anzeige (Pflicht) +``` +Ich willige ein, dass meine hochgeladenen Bilder auf dem Monitor in der offenen +Werkstatt des Hobbyhimmels angezeigt werden dürfen. Die Bilder sind nur lokal +im Hobbyhimmel sichtbar und werden nicht über das Internet zugänglich gemacht. +``` + +#### Social Media Veröffentlichung (Optional) +``` +Ich willige ein, dass meine Bilder und Texte auf folgenden Social Media Plattformen +veröffentlicht werden dürfen: +☐ Facebook +☐ Instagram +☐ TikTok +☐ [Weitere Plattformen...] + +Die Veröffentlichung erfolgt inklusive aller von mir angegebenen Informationen +(Name, Beschreibung, etc.). +``` + +#### Aufklärungshinweis +``` +ℹ️ Wichtiger Hinweis: +Alle hochgeladenen Inhalte werden vom Hobbyhimmel-Team geprüft, bevor sie angezeigt +oder veröffentlicht werden. Wir behalten uns vor, Inhalte nicht zu zeigen oder +rechtswidrige Inhalte zu entfernen. Nach dem Upload erhalten Sie eine Gruppen-ID +als Referenz. + +Widerruf Ihrer Einwilligung: +Sie können Ihre Einwilligung jederzeit widerrufen. Bitte kontaktieren Sie uns hierzu +mit Ihrer Gruppen-ID unter: it@hobbyhimmel.de +``` + +## 🔧 Technische Umsetzung + +### Datenbankschema + +#### Migration 1: Erweitere `groups` Tabelle +**Datei**: `backend/src/database/migrations/005_add_consent_fields.sql` + +```sql +-- Migration 005: Add consent management fields +-- Füge Consent-Felder zur groups-Tabelle hinzu + +ALTER TABLE groups ADD COLUMN display_in_workshop BOOLEAN NOT NULL DEFAULT 0; +ALTER TABLE groups ADD COLUMN consent_timestamp DATETIME; +ALTER TABLE groups ADD COLUMN management_token TEXT UNIQUE; -- Für Phase 2 + +-- Index für schnelle Abfragen +CREATE INDEX IF NOT EXISTS idx_groups_display_consent ON groups(display_in_workshop); +CREATE INDEX IF NOT EXISTS idx_groups_management_token ON groups(management_token); + +-- Update existing groups to default values (approved groups get consent retroactively) +UPDATE groups SET display_in_workshop = 1, consent_timestamp = created_at WHERE id > 0; +``` + +#### Migration 2: Neue `social_media_platforms` Tabelle +**Datei**: `backend/src/database/migrations/006_create_social_media_tables.sql` + +```sql +-- Migration 006: Social Media Platform Configuration und Consents + +-- Tabelle für konfigurierbare Social Media Plattformen +CREATE TABLE IF NOT EXISTS social_media_platforms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + platform_name TEXT UNIQUE NOT NULL, -- z.B. 'facebook', 'instagram', 'tiktok' + display_name TEXT NOT NULL, -- z.B. 'Facebook', 'Instagram', 'TikTok' + icon_name TEXT, -- Optional: Material-UI Icon Name + is_active BOOLEAN DEFAULT 1, -- Plattform aktiv/inaktiv + sort_order INTEGER DEFAULT 0, -- Anzeigereihenfolge + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- Tabelle für Consent pro Gruppe und Plattform +CREATE TABLE IF NOT EXISTS group_social_media_consents ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + group_id TEXT NOT NULL, + platform_id INTEGER NOT NULL, + consented BOOLEAN NOT NULL DEFAULT 0, + consent_timestamp DATETIME NOT NULL, + revoked BOOLEAN DEFAULT 0, -- Für Widerruf (Phase 2) + revoked_timestamp DATETIME, -- Wann widerrufen (Phase 2) + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (group_id) REFERENCES groups(group_id) ON DELETE CASCADE, + FOREIGN KEY (platform_id) REFERENCES social_media_platforms(id) ON DELETE CASCADE, + UNIQUE(group_id, platform_id) -- Jede Plattform nur einmal pro Gruppe +); + +-- Indizes +CREATE INDEX IF NOT EXISTS idx_consents_group_id ON group_social_media_consents(group_id); +CREATE INDEX IF NOT EXISTS idx_consents_platform_id ON group_social_media_consents(platform_id); +CREATE INDEX IF NOT EXISTS idx_consents_consented ON group_social_media_consents(consented); + +-- Trigger für updated_at +CREATE TRIGGER IF NOT EXISTS update_consents_timestamp +AFTER UPDATE ON group_social_media_consents +FOR EACH ROW +BEGIN + UPDATE group_social_media_consents SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id; +END; + +-- Standard-Plattformen einfügen +INSERT INTO social_media_platforms (platform_name, display_name, icon_name, sort_order) VALUES + ('facebook', 'Facebook', 'Facebook', 1), + ('instagram', 'Instagram', 'Instagram', 2), + ('tiktok', 'TikTok', 'MusicNote', 3); +``` + +### Backend-Erweiterungen + +#### 1. Repository-Erweiterungen +**Datei**: `backend/src/repositories/GroupRepository.js` + +**Neue Methoden:** +```javascript +// Consent Management +async createGroupWithConsent(groupData, workshopConsent, socialMediaConsents) +async getGroupWithConsents(groupId) +async updateConsents(groupId, socialMediaConsents) +async getGroupsByConsentStatus(displayInWorkshop, platformName = null) + +// Social Media Platforms +async getActiveSocialMediaPlatforms() +async getSocialMediaConsentsForGroup(groupId) + +// Export +async exportConsentData(filters = {}) + +// Management Token (Phase 2) +async generateManagementToken(groupId) +async getGroupByManagementToken(token) +``` + +#### 2. Neue Repository-Klasse +**Datei**: `backend/src/repositories/SocialMediaRepository.js` + +```javascript +class SocialMediaRepository { + constructor(dbManager) { + this.db = dbManager; + } + + // Platform Management + async getAllPlatforms() + async getActivePlatforms() + async createPlatform(platformData) + async updatePlatform(platformId, platformData) + async togglePlatformStatus(platformId, isActive) + + // Consent Management + async saveConsents(groupId, consentsArray) + async getConsentsForGroup(groupId) + async revokeConsent(groupId, platformId) // Phase 2 + async getConsentHistory(groupId) // Phase 2 +} +``` + +#### 3. API-Routes + +**Datei**: `backend/src/routes/consent.js` (NEU) + +```javascript +// GET /api/social-media/platforms - Liste aller aktiven Plattformen +router.get('/social-media/platforms', async (req, res) => { + // Returns: [{ id, platform_name, display_name, icon_name, sort_order }] +}); + +// POST /api/groups/:groupId/consents - Speichere Consents für Gruppe +router.post('/groups/:groupId/consents', async (req, res) => { + // Body: { workshopConsent: true, socialMediaConsents: [{ platformId: 1, consented: true }] } +}); + +// GET /api/groups/:groupId/consents - Lade Consents für Gruppe +router.get('/groups/:groupId/consents', async (req, res) => { + // Returns: { workshopConsent, socialMediaConsents, consentTimestamp } +}); + +// GET /api/admin/groups/by-consent - Filter Gruppen nach Consent (Admin) +router.get('/admin/groups/by-consent', async (req, res) => { + // Query params: ?workshopConsent=true&platform=facebook +}); + +// GET /api/admin/consents/export - Export Consent-Daten (Admin) +router.get('/admin/consents/export', async (req, res) => { + // Returns CSV or JSON with all consent data +}); +``` + +**Datei**: `backend/src/routes/management.js` (NEU - Phase 2) + +```javascript +// GET /api/manage/:token - Validiere Management-Token und lade Gruppe +router.get('/manage/:token', async (req, res) => {}); + +// PUT /api/manage/:token/consents - Widerrufe/Ändere Consents +router.put('/manage/:token/consents', async (req, res) => {}); + +// DELETE /api/manage/:token/images/:imageId - Lösche Bild +router.delete('/manage/:token/images/:imageId', async (req, res) => {}); +``` + +#### 4. Upload-Route Anpassung +**Datei**: `backend/src/routes/batchUpload.js` + +```javascript +// Erweitere Upload-Logik um Consent-Speicherung +router.post('/upload-batch', upload.array('images', 50), async (req, res) => { + try { + // ... existing upload logic ... + + // Parse consent data + const { workshopConsent, socialMediaConsents } = JSON.parse(req.body.consents || '{}'); + + // Validate workshop consent (required) + if (!workshopConsent) { + return res.status(400).json({ + error: 'Workshop display consent is required' + }); + } + + // Save group with consents + const groupId = await groupRepository.createGroupWithConsent( + groupData, + workshopConsent, + socialMediaConsents + ); + + // Generate management token (Phase 2) + const managementToken = await groupRepository.generateManagementToken(groupId); + + res.json({ + success: true, + groupId, + managementToken, // Phase 2 + message: 'Upload successful' + }); + + } catch (error) { + // Error handling + } +}); +``` + +### Frontend-Komponenten + +#### 1. Neue Komponente: ConsentCheckboxes +**Datei**: `frontend/src/Components/ComponentUtils/MultiUpload/ConsentCheckboxes.js` + +```javascript +import React, { useState, useEffect } from 'react'; +import { + Box, + FormControlLabel, + Checkbox, + Typography, + Paper, + Divider, + Alert +} from '@mui/material'; +import InfoIcon from '@mui/icons-material/Info'; +import FacebookIcon from '@mui/icons-material/Facebook'; +import InstagramIcon from '@mui/icons-material/Instagram'; +import MusicNoteIcon from '@mui/icons-material/MusicNote'; + +const ICON_MAP = { + 'Facebook': FacebookIcon, + 'Instagram': InstagramIcon, + 'MusicNote': MusicNoteIcon, +}; + +function ConsentCheckboxes({ onConsentChange, consents, disabled = false }) { + const [platforms, setPlatforms] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // Lade verfügbare Plattformen vom Backend + fetchPlatforms(); + }, []); + + const fetchPlatforms = async () => { + try { + const response = await fetch('/api/social-media/platforms'); + const data = await response.json(); + setPlatforms(data); + } catch (error) { + console.error('Error loading platforms:', error); + } finally { + setLoading(false); + } + }; + + const handleWorkshopChange = (event) => { + onConsentChange({ + ...consents, + workshopConsent: event.target.checked + }); + }; + + const handleSocialMediaChange = (platformId) => (event) => { + const updatedConsents = { ...consents }; + const platformConsents = updatedConsents.socialMediaConsents || []; + + if (event.target.checked) { + platformConsents.push({ platformId, consented: true }); + } else { + const index = platformConsents.findIndex(c => c.platformId === platformId); + if (index > -1) platformConsents.splice(index, 1); + } + + updatedConsents.socialMediaConsents = platformConsents; + onConsentChange(updatedConsents); + }; + + const isPlatformChecked = (platformId) => { + return consents.socialMediaConsents?.some(c => c.platformId === platformId) || false; + }; + + return ( + + {/* Aufklärungshinweis */} + } sx={{ mb: 3 }}> + + Wichtiger Hinweis + + + Alle hochgeladenen Inhalte werden vom Hobbyhimmel-Team geprüft, bevor sie + angezeigt oder veröffentlicht werden. Wir behalten uns vor, Inhalte nicht + zu zeigen oder rechtswidrige Inhalte zu entfernen. + + + Nach dem Upload erhalten Sie eine Gruppen-ID als Referenz für die Kontaktaufnahme. + + + + {/* Pflicht-Zustimmung: Werkstatt-Anzeige */} + + + Anzeige in der Werkstatt * + + + } + label={ + + Ich willige ein, dass meine hochgeladenen Bilder auf dem Monitor in + der offenen Werkstatt des Hobbyhimmels angezeigt werden dürfen. + Die Bilder sind nur lokal im Hobbyhimmel sichtbar und werden nicht + über das Internet zugänglich gemacht. (Pflichtfeld) + + } + /> + + + + + {/* Optional: Social Media Veröffentlichung */} + + + Social Media Veröffentlichung (optional) + + + Ich willige ein, dass meine Bilder und Texte auf folgenden Social Media + Plattformen veröffentlicht werden dürfen (inklusive aller angegebenen + Informationen wie Name und Beschreibung): + + + {loading ? ( + Lade Plattformen... + ) : ( + + {platforms.map(platform => { + const IconComponent = ICON_MAP[platform.icon_name] || InfoIcon; + return ( + + } + label={ + + + + {platform.display_name} + + + } + /> + ); + })} + + )} + + + {/* Widerrufs-Hinweis */} + + + Widerruf Ihrer Einwilligung: Sie können Ihre Einwilligung + jederzeit widerrufen. Kontaktieren Sie uns hierzu mit Ihrer Gruppen-ID unter: + it@hobbyhimmel.de + + + + ); +} + +export default ConsentCheckboxes; +``` + +#### 2. Neue Komponente: UploadSuccessDialog +**Datei**: `frontend/src/Components/ComponentUtils/MultiUpload/UploadSuccessDialog.js` + +```javascript +import React, { useState } from 'react'; +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Typography, + Box, + IconButton, + Alert, + TextField, + InputAdornment +} from '@mui/material'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import CheckCircleIcon from '@mui/icons-material/CheckCircle'; + +function UploadSuccessDialog({ open, onClose, uploadResult }) { + const [copied, setCopied] = useState(false); + + const handleCopyGroupId = () => { + navigator.clipboard.writeText(uploadResult.groupId); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + const handleCopyManagementLink = () => { + const link = `${window.location.origin}/manage/${uploadResult.managementToken}`; + navigator.clipboard.writeText(link); + }; + + return ( + + + + + Upload erfolgreich! + + + + + + {uploadResult.imageCount} Bild{uploadResult.imageCount !== 1 ? 'er' : ''} wurden erfolgreich hochgeladen. + + + + + Ihre Gruppen-ID (Referenznummer): + + + + + + + ), + }} + sx={{ + '& .MuiOutlinedInput-root': { + fontFamily: 'monospace', + fontSize: '14px' + } + }} + /> + {copied && ( + + ✓ In Zwischenablage kopiert + + )} + + + {/* Phase 2: Management Link */} + {uploadResult.managementToken && ( + + + Verwaltungslink (nur für Sie): + + + Über diesen Link können Sie Ihre Bilder verwalten, Beschreibungen ändern + oder Ihre Einwilligung widerrufen. Speichern Sie diesen Link sicher! + + + + )} + + + + Ihre Bilder werden vom Hobbyhimmel-Team geprüft und dann freigegeben. + Bei Fragen oder zum Widerruf Ihrer Einwilligung kontaktieren Sie uns + bitte mit Ihrer Gruppen-ID unter: it@hobbyhimmel.de + + + + + + + + + ); +} + +export default UploadSuccessDialog; +``` + +#### 3. MultiUploadPage Anpassung +**Datei**: `frontend/src/Components/Pages/MultiUploadPage.js` + +**Änderungen:** +- Import ConsentCheckboxes und UploadSuccessDialog +- State für Consents hinzufügen +- Upload-Button nur aktivieren wenn workshopConsent = true +- Consents beim Upload mit senden +- UploadSuccessDialog nach erfolgreichem Upload anzeigen + +```javascript +// Neuer State +const [consents, setConsents] = useState({ + workshopConsent: false, + socialMediaConsents: [] +}); + +// Upload-Validierung erweitern +const handleUpload = async () => { + // ... existing checks ... + + if (!consents.workshopConsent) { + Swal.fire({ + icon: 'warning', + title: 'Zustimmung erforderlich', + text: 'Bitte stimmen Sie der Anzeige in der Werkstatt zu, um fortfahren zu können.', + confirmButtonColor: '#4CAF50' + }); + return; + } + + // Upload mit Consents + const result = await uploadImageBatch(filesToUpload, metadata, descriptionsArray, consents); +}; + +// Render mit ConsentCheckboxes + +``` + +#### 4. Moderation Panel Erweiterungen +**Datei**: `frontend/src/Components/Pages/ModerationGroupsPage.js` + +**Neue Features:** +- Filter-Dropdown für Consent-Status (Alle / Nur Werkstatt / Facebook / Instagram / TikTok) +- Social Media Icons als Badges bei jeder Gruppe +- Export-Button für Consent-Daten +- Consent-Details in Gruppen-Ansicht + +```javascript +// Neue Komponente: ConsentBadges +function ConsentBadges({ consents }) { + return ( + + {consents.socialMediaConsents?.map(consent => ( + } + label={consent.platformDisplayName} + size="small" + color="primary" + variant="outlined" + /> + ))} + + ); +} +``` + +### Utils-Erweiterung + +#### Upload Utility +**Datei**: `frontend/src/Utils/batchUpload.js` + +```javascript +export const uploadImageBatch = async (files, metadata, descriptions, consents) => { + const formData = new FormData(); + + // ... existing file append logic ... + + // Add consent data + formData.append('consents', JSON.stringify({ + workshopConsent: consents.workshopConsent, + socialMediaConsents: consents.socialMediaConsents + })); + + const response = await fetch('/api/upload-batch', { + method: 'POST', + body: formData + }); + + const result = await response.json(); + return result; +}; +``` + +## 📝 Implementierungs-Aufgaben + +### Phase 1: Core Consent Management (Must-Have) + +#### Backend Tasks + +**Task 1.1: Datenbank-Migrationen** ⏱️ 1-2h +- [ ] Migration 005: `display_in_workshop`, `consent_timestamp`, `management_token` zu `groups` hinzufügen +- [ ] Migration 006: `social_media_platforms` und `group_social_media_consents` Tabellen erstellen +- [ ] Standard-Plattformen (Facebook, Instagram, TikTok) einfügen +- [ ] Migrationen testen (up/down) + +**Task 1.2: Repository-Erweiterungen** ⏱️ 3-4h +- [ ] `GroupRepository`: `createGroupWithConsent()` implementieren +- [ ] `GroupRepository`: `getGroupWithConsents()` implementieren +- [ ] `GroupRepository`: `getGroupsByConsentStatus()` für Moderation-Filter +- [ ] `SocialMediaRepository`: Neue Klasse erstellen +- [ ] `SocialMediaRepository`: Platform-Management-Methoden +- [ ] `SocialMediaRepository`: Consent-Management-Methoden +- [ ] Unit-Tests für neue Repository-Methoden + +**Task 1.3: API-Routes** ⏱️ 3-4h +- [ ] Route `GET /api/social-media/platforms` erstellen +- [ ] Route `POST /api/groups/:groupId/consents` erstellen +- [ ] Route `GET /api/groups/:groupId/consents` erstellen +- [ ] Route `GET /api/admin/groups/by-consent` für Moderation-Filter +- [ ] Route `GET /api/admin/consents/export` für CSV/JSON Export +- [ ] Validierung und Error-Handling +- [ ] Integration-Tests für Routes + +**Task 1.4: Upload-Route Anpassung** ⏱️ 2h +- [ ] `batchUpload.js`: Consent-Parameter entgegennehmen +- [ ] Validierung: `workshopConsent` muss true sein +- [ ] Consent-Daten mit Gruppe speichern +- [ ] Timestamp setzen +- [ ] Response um `groupId` erweitern +- [ ] Error-Handling bei fehlender Zustimmung + +#### Frontend Tasks + +**Task 1.5: ConsentCheckboxes Komponente** ⏱️ 4-5h +- [ ] Komponente erstellen mit Material-UI +- [ ] Aufklärungstext-Alert implementieren +- [ ] Pflicht-Checkbox für Werkstatt-Anzeige +- [ ] Dynamische Plattform-Liste vom Backend laden +- [ ] Social Media Checkboxen generieren +- [ ] Icon-Mapping für Plattformen +- [ ] Widerrufs-Hinweis anzeigen +- [ ] Responsive Design +- [ ] Props für Disabled-State und onChange-Callback + +**Task 1.6: UploadSuccessDialog Komponente** ⏱️ 2-3h +- [ ] Dialog-Komponente mit Material-UI erstellen +- [ ] Gruppen-ID prominent anzeigen +- [ ] Copy-to-Clipboard für Gruppen-ID +- [ ] Aufklärungstext über Prüfung anzeigen +- [ ] Kontakt-Information einbinden +- [ ] Responsive Design +- [ ] Animation für Success-State + +**Task 1.7: MultiUploadPage Integration** ⏱️ 2-3h +- [ ] State für Consents hinzufügen +- [ ] ConsentCheckboxes einbinden (vor Upload-Button) +- [ ] Upload-Button nur aktivieren wenn `workshopConsent = true` +- [ ] Consents-Validation in `handleUpload()` +- [ ] Consents an Backend senden +- [ ] UploadSuccessDialog nach Upload anzeigen +- [ ] Gruppen-ID aus Response verarbeiten +- [ ] Error-Handling für fehlende Zustimmung + +**Task 1.8: Moderation Panel - Consent-Anzeige** ⏱️ 3-4h +- [ ] ConsentBadges Komponente erstellen +- [ ] Social Media Icons/Chips anzeigen +- [ ] Badges in Gruppen-Liste integrieren +- [ ] Consent-Details in Detailansicht +- [ ] Tooltip mit Consent-Timestamp +- [ ] Visuelle Unterscheidung (Werkstatt-only vs. Social Media) + +**Task 1.9: Moderation Panel - Filter & Export** ⏱️ 3-4h +- [ ] Filter-Dropdown für Consent-Status +- [ ] API-Abfrage mit Filter-Parametern +- [ ] Export-Button implementieren +- [ ] CSV/JSON Export-Logik +- [ ] Download-Funktionalität +- [ ] Filter-State in URL (für Bookmarking) + +#### Testing & Documentation + +**Task 1.10: Tests** ⏱️ 3-4h +- [ ] Backend Unit-Tests für Repositories +- [ ] Backend Integration-Tests für API-Routes +- [ ] Frontend Component-Tests für ConsentCheckboxes +- [ ] Frontend Integration-Tests für Upload-Flow +- [ ] E2E-Test: Kompletter Upload mit Consents +- [ ] E2E-Test: Moderation mit Consent-Filter + +**Task 1.11: Dokumentation** ⏱️ 2h +- [ ] README.md aktualisieren (neue Features) +- [ ] API-Dokumentation für neue Endpoints +- [ ] Datenbank-Schema dokumentieren +- [ ] Screenshots für Consent-UI +- [ ] Deployment-Guide für Migrationen + +### Phase 2: Self-Service Management Portal (Nice-to-Have) + +#### Backend Tasks + +**Task 2.1: Management-Token System** ⏱️ 3-4h +- [ ] UUID-Token-Generierung implementieren +- [ ] `management_token` in Gruppe speichern +- [ ] Token-Validierungs-Logik +- [ ] Token-Expiration (optional, z.B. 90 Tage) +- [ ] Security: Rate-Limiting für Token-Zugriffe + +**Task 2.2: Management API-Routes** ⏱️ 4-5h +- [ ] Route `GET /api/manage/:token` - Token validieren und Gruppe laden +- [ ] Route `PUT /api/manage/:token/consents` - Consents widerrufen/ändern +- [ ] Route `PUT /api/manage/:token/metadata` - Titel/Beschreibung ändern +- [ ] Route `DELETE /api/manage/:token/images/:imageId` - Bild löschen +- [ ] Route `DELETE /api/manage/:token` - Gesamte Gruppe löschen +- [ ] Audit-Log für alle Änderungen über Management-Portal + +**Task 2.3: Consent-Widerruf Logik** ⏱️ 2-3h +- [ ] `revoked` und `revoked_timestamp` in DB setzen +- [ ] Consent-Historie für Audit-Trail +- [ ] Benachrichtigung an Admins bei Widerruf +- [ ] Automatische Entfernung von Social Media bei Widerruf + +#### Frontend Tasks + +**Task 2.4: Management Portal Page** ⏱️ 6-8h +- [ ] Neue Route `/manage/:token` erstellen +- [ ] Token-Validierung und Gruppe laden +- [ ] UI für Consent-Management +- [ ] UI für Metadaten-Bearbeitung +- [ ] UI für Bild-Löschung +- [ ] UI für Gruppen-Löschung +- [ ] Sicherheits-Bestätigungen (z.B. für Widerruf) +- [ ] Error-Handling bei ungültigem Token + +**Task 2.5: Management-Link in UploadSuccessDialog** ⏱️ 1h +- [ ] Management-Link anzeigen +- [ ] Copy-to-Clipboard Funktionalität +- [ ] Hinweis zur sicheren Aufbewahrung +- [ ] Link-Vorschau mit Icon + +**Task 2.6: E-Mail-Benachrichtigung (optional)** ⏱️ 4-6h +- [ ] Backend: E-Mail-Service integrieren (z.B. nodemailer) +- [ ] E-Mail-Template für Upload-Bestätigung +- [ ] Management-Link in E-Mail einbetten +- [ ] Optional: E-Mail-Adresse beim Upload abfragen +- [ ] DSGVO-Hinweis für E-Mail-Speicherung + +## 🧪 Test-Szenarien + +### Acceptance Tests - Phase 1 + +1. **Upload mit Pflicht-Zustimmung** + - [ ] Upload ohne Werkstatt-Zustimmung wird blockiert + - [ ] Upload mit Werkstatt-Zustimmung funktioniert + - [ ] Consent-Timestamp wird korrekt gespeichert + +2. **Social Media Consents** + - [ ] Keine Social Media Zustimmung: Upload erfolgreich, nur Werkstatt-Anzeige + - [ ] Eine Plattform: Consent wird korrekt gespeichert + - [ ] Mehrere Plattformen: Alle Consents werden gespeichert + - [ ] Plattform-Liste wird dynamisch geladen + +3. **Upload-Success Dialog** + - [ ] Gruppen-ID wird angezeigt + - [ ] Copy-to-Clipboard funktioniert + - [ ] Informationstexte sind korrekt + +4. **Moderation Panel** + - [ ] Social Media Badges werden angezeigt + - [ ] Filter nach Consent-Status funktioniert + - [ ] Export-Funktion liefert korrekten CSV/JSON + - [ ] Consent-Details sind sichtbar + +### Acceptance Tests - Phase 2 + +5. **Management Portal** + - [ ] Token-Zugriff funktioniert + - [ ] Consent-Widerruf funktioniert + - [ ] Metadaten können geändert werden + - [ ] Bilder können gelöscht werden + - [ ] Ungültiger Token wird abgelehnt + +6. **Sicherheit** + - [ ] Token ist kryptisch und nicht erratbar (UUID v4) + - [ ] Rate-Limiting verhindert Token-Brute-Force + - [ ] Audit-Log für alle Änderungen vorhanden + +## 📊 Datenbank-Beispiele + +### Gruppe mit Consents +```sql +-- groups Tabelle +INSERT INTO groups (group_id, year, title, name, display_in_workshop, consent_timestamp, management_token) +VALUES ('abc123', 2025, 'Mein Projekt', 'Max Mustermann', 1, '2025-11-09 14:30:00', 'a7f3k9m2-d4e8-4b1c-9f7a-3e2d8c1b5a6f'); + +-- group_social_media_consents Tabelle +INSERT INTO group_social_media_consents (group_id, platform_id, consented, consent_timestamp) VALUES + ('abc123', 1, 1, '2025-11-09 14:30:00'), -- Facebook: Ja + ('abc123', 2, 1, '2025-11-09 14:30:00'), -- Instagram: Ja + ('abc123', 3, 0, '2025-11-09 14:30:00'); -- TikTok: Nein +``` + +### Export-Format (CSV) +```csv +group_id,title,name,upload_date,workshop_consent,consent_timestamp,facebook,instagram,tiktok +abc123,Mein Projekt,Max Mustermann,2025-11-09 14:30:00,true,2025-11-09 14:30:00,true,true,false +def456,Anderes Projekt,Anna Schmidt,2025-11-10 10:15:00,true,2025-11-10 10:15:00,false,true,false +``` + +## 🚀 Deployment-Hinweise + +### Datenbank-Migration +```bash +# Backup vor Migration +sqlite3 backend/src/data/db/database.db ".backup backup-pre-consent.db" + +# Migrationen ausführen +node backend/src/database/runMigrations.js + +# Verifizierung +sqlite3 backend/src/data/db/database.db "SELECT * FROM social_media_platforms;" +``` + +### Umgebungsvariablen (Phase 2) +```env +# E-Mail Konfiguration (optional) +SMTP_HOST=smtp.example.com +SMTP_PORT=587 +SMTP_USER=noreply@hobbyhimmel.de +SMTP_PASS=your-password + +# Management Token Expiration (in Tagen) +MANAGEMENT_TOKEN_EXPIRY=90 +``` + +## ✅ Definition of Done + +### Phase 1 +- [ ] Alle Backend-Migrationen erfolgreich durchgeführt +- [ ] Alle Backend-Routes implementiert und getestet +- [ ] Alle Frontend-Komponenten implementiert und integriert +- [ ] Upload funktioniert nur mit Werkstatt-Zustimmung +- [ ] Social Media Consents werden korrekt gespeichert +- [ ] Moderation Panel zeigt Consent-Status an +- [ ] Export-Funktion funktioniert +- [ ] Alle Tests grün +- [ ] Dokumentation aktualisiert +- [ ] Code-Review durchgeführt +- [ ] Deployment auf Staging erfolgreich + +### Phase 2 +- [ ] Management-Token-System implementiert +- [ ] Management-Portal funktionsfähig +- [ ] Consent-Widerruf funktioniert +- [ ] Alle Phase-2-Tests grün +- [ ] Sicherheits-Review durchgeführt +- [ ] Production-Deployment erfolgreich + +## 📅 Zeitplan + +### Phase 1 (Must-Have): 4-5 Arbeitstage +- Tag 1: Backend Migrationen & Repositories (Tasks 1.1, 1.2) +- Tag 2: Backend API-Routes (Tasks 1.3, 1.4) +- Tag 3: Frontend Komponenten (Tasks 1.5, 1.6) +- Tag 4: Frontend Integration (Tasks 1.7, 1.8, 1.9) +- Tag 5: Testing & Dokumentation (Tasks 1.10, 1.11) + +### Phase 2 (Nice-to-Have): 3-4 Arbeitstage +- Tag 6-7: Backend Management-System (Tasks 2.1, 2.2, 2.3) +- Tag 8-9: Frontend Management-Portal (Tasks 2.4, 2.5) +- Tag 10 (optional): E-Mail-Integration (Task 2.6) + +## 🔗 Abhängigkeiten + +### Externe Libraries +- **Keine neuen Dependencies** für Phase 1 (nutzt vorhandene Material-UI) +- **Phase 2**: Optional `nodemailer` für E-Mail-Benachrichtigungen + +### Interne Abhängigkeiten +- Basiert auf bestehendem Upload-Flow +- Nutzt vorhandene Datenbank-Infrastruktur +- Integration in bestehendes Moderation-Panel + +## 📚 Referenzen + +- [DSGVO Art. 7 - Bedingungen für die Einwilligung](https://dsgvo-gesetz.de/art-7-dsgvo/) +- [Material-UI Checkbox Documentation](https://mui.com/material-ui/react-checkbox/) +- [SQLite Foreign Key Support](https://www.sqlite.org/foreignkeys.html) +- [UUID v4 Best Practices](https://www.rfc-editor.org/rfc/rfc4122) + +--- + +**Erstellt am**: 9. November 2025 +**Letzte Aktualisierung**: 9. November 2025 +**Status**: Draft - Wartet auf Review