Issue 6: ModerationGroupsPage - Filter "Alle Gruppen" not working
- Problem: Backend filtered groups with display_in_workshop=1 even when no filter selected
- Solution: Removed filter condition in else block - now shows ALL groups when filter='all'
- File: backend/src/routes/groups.js
- Test: GET /moderation/groups now returns 73 groups (all groups)
Issue 7: Export button "Consent-Daten exportieren" not working
- Problem: Routes had wrong path prefix (/admin/* instead of /api/admin/*)
- Solution: Added /api prefix to consent admin routes for consistency
- Files: backend/src/routes/consent.js
* GET /api/admin/groups/by-consent (was /admin/groups/by-consent)
* GET /api/admin/consents/export (was /admin/consents/export)
- Test: curl http://localhost:5001/api/admin/consents/export?format=csv works
- Export now includes dynamic Social Media platform columns (facebook, instagram, tiktok)
Test Results:
✅ Filter "Alle Gruppen": 73 groups
✅ Filter "Nur Werkstatt": 1 group
✅ Filter "Facebook": 0 groups
✅ Export CSV with platform columns: facebook,instagram,tiktok
✅ Test upload with Social Media consents saved correctly
✅ Export shows consented platforms per group
Files Changed:
- backend/src/routes/groups.js (filter logic fixed)
- backend/src/routes/consent.js (API paths corrected)
Audit-Logging System:
- Migration 007: management_audit_log table with indexes
- Tracks all management portal actions
- IP address, user-agent, request data logging
- Token masking (only first 8 chars stored)
- Success/failure tracking with error messages
ManagementAuditLogRepository:
- logAction() - Log management actions
- getRecentLogs() - Get last N logs
- getLogsByGroupId() - Get logs for specific group
- getFailedActionsByIP() - Security monitoring
- getStatistics() - Overview statistics
- cleanupOldLogs() - Maintenance (90 days retention)
Audit-Log Middleware:
- Adds res.auditLog() helper function
- Auto-captures IP, User-Agent
- Integrated into all management routes
- Non-blocking (errors don't fail main operation)
Admin API Endpoints:
- GET /api/admin/management-audit?limit=N
- GET /api/admin/management-audit/stats
- GET /api/admin/management-audit/group/:groupId
Tested:
✅ Migration executed successfully
✅ Audit logs written on token validation
✅ Admin API returns logs with stats
✅ Token masking working
✅ Statistics accurate
Rate-Limiting:
- IP-based: 10 requests per hour per IP
- Applies to all /api/manage/* routes
- Returns 429 Too Many Requests when limit exceeded
- Automatic cleanup of expired records (>1h old)
Brute-Force Protection:
- Tracks failed token validation attempts
- After 20 failed attempts: IP banned for 24 hours
- Returns 403 Forbidden for banned IPs
- Integrated into GET /api/manage/:token route
Technical Implementation:
- Created backend/src/middlewares/rateLimiter.js
- In-memory storage with Map() for rate limit tracking
- Separate Map() for brute-force detection
- Middleware applied to all management routes
- Token validation failures increment brute-force counter
Tested:
✅ Rate limit blocks after 10 requests
✅ 429 status code returned correctly
✅ Middleware integration working
✅ IP-based tracking functional
Fixed Task 8 (Delete Group API):
- Changed deletionLogRepository.logDeletion() to createDeletionEntry()
- Use correct parameters matching DeletionLogRepository schema
- Deletion now works: group, images, files, consents all removed
- deletion_log entry created with proper data
Tested:
✅ Group deletion with valid token
✅ 404 for invalid/missing tokens
✅ Files deleted (original + preview)
✅ DB records deleted via CASCADE
✅ Deletion log entry created
All 8 Backend Management API tasks complete!
Backend Management API implementation for self-service user portal:
✅ Task 2: Token Generation (already implemented in Phase 1)
- UUID v4 generated at upload
- Stored in groups.management_token
- Returned in upload response
✅ Task 3: Token Validation API
- GET /api/manage/:token
- Validates token and loads complete group data
- Returns group with images, consents, metadata
- 404 for invalid/missing tokens
✅ Task 4: Consent Revocation API
- PUT /api/manage/:token/consents
- Revoke/restore workshop consent
- Revoke/restore social media platform consents
- Sets revoked=1, revoked_timestamp
- Full error handling and validation
✅ Task 5: Metadata Edit API
- PUT /api/manage/:token/metadata
- Update title, description, name
- Supports partial updates
- Automatically sets approved=0 (returns to moderation)
✅ Task 6: Add Images API
- POST /api/manage/:token/images
- Upload new images to existing group
- Calculates correct upload_order
- Sets approved=0 on changes
- Max 50 images per group validation
- Preview generation support
✅ Task 7: Delete Image API
- DELETE /api/manage/:token/images/:imageId
- Deletes original and preview files
- Removes DB entry
- Sets approved=0 if group was approved
- Prevents deletion of last image
⏳ Task 8: Delete Group API (in progress)
- DELETE /api/manage/:token route created
- Integration with existing GroupRepository.deleteGroup
- Needs testing
Technical Changes:
- Created backend/src/routes/management.js
- Added getGroupByManagementToken() to GroupRepository
- Registered /api/manage routes in index.js
- Installed uuid package for token generation
- All routes use token validation helper
- Docker-only development workflow
Tested Features:
- Token validation with real uploads
- Workshop consent revoke/restore
- Social media consent management
- Metadata updates (full and partial)
- Image upload with multipart/form-data
- Image deletion with file cleanup
- Error handling and edge cases
✅ Phase 1 Complete (Nov 9-10, 2025):
- GDPR-compliant consent management fully implemented
- Mandatory workshop display consent + optional social media consents
- Consent badges, filtering, and CSV/JSON export in moderation panel
- Automatic migration system fixed (inline comments handling)
- GDPR compliance validated: 72 production groups with display_in_workshop = 0
- All features tested and production-ready
Documentation Updates:
- FEATURE_PLAN-social-media.md: All Phase 1 tasks marked complete
- README.md: Added consent system to features, updated database schema, new API endpoints
- README.dev.md: Complete developer guide with debugging, testing, and troubleshooting
Technical Achievements:
- 12 commits over 2 days (faster than 4-5 day estimate)
- Zero GDPR violations (retroactive consent fix validated)
- Zero breaking changes to existing functionality
Ready for Code Review and Production Deployment
- Fixed SQL statement parsing to remove both line and inline comments
- Prevents incomplete SQL statements from inline comments
- Migration 005 and 006 now apply correctly via automatic migration system
- Tested with production data: All 72 groups have display_in_workshop = 0 (GDPR compliant)
Problem: Moderation filter returned 0 groups because:
1. groupFormatter.formatGroupDetail() didn't include display_in_workshop field
2. Platform filters incorrectly required workshop consent
Solution:
- Add display_in_workshop and consent_timestamp to formatGroupDetail()
- Remove workshop requirement from platform filters
- Add default filter to show only groups with workshop consent
- Fix workshop-only filter to check for consented social media
Filter logic:
- 'Alle Gruppen': Only groups WITH workshop consent
- 'Nur Werkstatt': Groups with workshop BUT WITHOUT social media
- Platform filters: Groups with that platform consent (independent of workshop)
Problem: Filtered groups were missing preview images because
getGroupsByConsentStatus() only returned group metadata without images.
Solution: Load all groups with getAllGroupsWithModerationInfo() first
(includes images), add consent data, then filter in-memory based on
query parameters. This ensures preview images are always included.
- Reduce success block complexity to match original styling level
- Keep same information (group ID, next steps, GDPR contact)
- Maintain consistent Material-UI sx usage with rest of app
- Move ConsentCheckboxes below DescriptionInput for better flow
- Replace success dialog with inline success display
- Add copy-to-clipboard button for group ID
- Show detailed next steps and GDPR contact info inline
- Update consent.js routes to use /api prefix
- Add /api/social-media location to dev/prod nginx configs
- Fix route registration for proper API access
- Add ConsentCheckboxes component with workshop and social media consents
- Add UploadSuccessDialog with group ID display and copy functionality
- Integrate consent validation into MultiUploadPage
- Extend batchUpload utility to send consent data
- Add GDPR compliance notices and contact information
- Block uploads without required workshop consent
- Parse consent data from request body (workshopConsent, socialMediaConsents)
- Validate workshop consent is required (400 error if missing)
- Use createGroupWithConsent() instead of createGroup()
- Pass consent data to repository for database storage
- Maintains backward compatibility with existing upload flow
- GDPR-compliant: no upload without explicit workshop consent
- Create consent.js with comprehensive API endpoints:
- GET /api/social-media/platforms - list active platforms
- POST /api/groups/:groupId/consents - save/update group consents
- GET /api/groups/:groupId/consents - retrieve group consent data
- GET /api/admin/groups/by-consent - filter groups by consent status
- GET /api/admin/consents/export - export consent data (JSON/CSV formats)
- Register consent router in routes/index.js
- Full validation and error handling
- CSV export with dynamic platform columns
- Ready for frontend integration
- Create new SocialMediaRepository for platform and consent management
- getAllPlatforms(), getActivePlatforms()
- createPlatform(), updatePlatform(), togglePlatformStatus()
- saveConsents(), getConsentsForGroup(), getGroupIdsByConsentStatus()
- revokeConsent(), restoreConsent(), hasActiveConsent()
- Extend GroupRepository with consent management methods
- createGroupWithConsent() - create group with workshop & social media consents
- getGroupWithConsents() - retrieve group with all consent data
- updateConsents() - update consent preferences
- getGroupsByConsentStatus() - filter groups by consent status
- exportConsentData() - export for legal documentation
- generateManagementToken(), getGroupByManagementToken() (Phase 2)
- Both repositories work together seamlessly via transactions
- Add comprehensive feature plan for consent management system
- Phase 1: Workshop display and social media consents (4-5 days)
- Phase 2: Self-service management portal (3-4 days)
- GDPR-compliant consent handling with timestamps
- Extensible social media platform configuration
- Export functionality for legal documentation
- Contact email: it@hobbyhimmel.de
Plan for implementing automatic EXIF data extraction from uploaded images:
- Extract capture date, camera model, and GPS coordinates
- Use earliest capture date for chronological group sorting
- Add new database fields: capture_date, exif_date_taken, exif_camera_model
- Implement ExifService with exifr library
- Create migration script for existing images
- Update slideshow sorting logic with EXIF-based chronology
- Fallback to year/upload date when EXIF unavailable
Estimated effort: 5-7 hours (3 phases)
Dependencies: exifr npm package
- Lottie-react Bibliothek durch native CSS 3D Transforms ersetzt
- Hobbyhimmel Logo (Hammer & Wolke) als animiertes Loading-Icon
- Wolke rotiert um Y-Achse (4s)
- Hammer rotiert um Y-Achse UND eigene Diagonalachse (3s)
- 15° X-Neigung für dynamischeren 3D-Effekt
- Nested Transform-Hierarchie mit transform-box: fill-box
- Upload-Erfolgsmeldung als grünes Banner unter Animation
- Nutzer muss Upload-Bestätigung mit Button bestätigen
- Loading-Animation bleibt während Erfolgsmeldung sichtbar
- Display app version dynamically from window._env_.APP_VERSION
- Credit original author (vallezw) with link to original repo
- Credit extended version (lotzm) with link to Gitea repo
- Update package.json version to 1.1.0
Footer styling:
- Position fixed at bottom-right corner of viewport
- Unobtrusive design with small font size (11px)
- Semi-transparent background with subtle shadow
- Stays visible while scrolling
- Hover effect on links for better UX
Changes:
- frontend/package.json: version 0.1.0 → 1.1.0
- Footer.js: Dynamic version display, attribution links
- Footer.css: Fixed positioning, responsive styling
- Install sqlite3 in prod Dockerfile using apk (Alpine package manager)
- Required for test-cleanup-prod.sh script to function
- Matches dev environment which already had sqlite3 installed
Changes:
- docker/prod/backend/Dockerfile: Add 'apk add --no-cache sqlite'
- tests/test-cleanup.sh -> split into test-cleanup-dev.sh and test-cleanup-prod.sh
- Separate scripts for dev/prod with correct docker-compose paths
Testing:
- sqlite3 now available at /usr/bin/sqlite3 in prod container
- test-cleanup-prod.sh can now execute database queries
Complete implementation of automatic cleanup for unapproved groups:
- Automatic deletion after 7 days for unapproved groups
- Daily cron job at 10:00 AM (Europe/Berlin)
- Complete deletion log with statistics
- Countdown display in moderation interface
- SweetAlert2 approval feedback
- Comprehensive testing tools
Backend:
- GroupCleanupService with singleton pattern
- DeletionLogRepository for audit trail
- SchedulerService for cron jobs
- Extended GroupRepository with cleanup methods
- Admin API endpoints for deletion log
Frontend:
- DeletionLogSection component with statistics
- Countdown widget in ImageGalleryCard
- SweetAlert2 integration for approval feedback
- Toggle between last 10 and all deletion entries
Infrastructure:
- node-cron v3.0.3 dependency
- nginx configuration updates (dev + prod)
- Database schema with deletion_log table
Testing:
- Interactive bash test script (tests/test-cleanup.sh)
- Node.js test alternative
- Comprehensive testing guide (tests/TESTING-CLEANUP.md)
Bug fixes:
- Singleton import in admin routes
- nginx Basic Auth configuration for /api/admin
Documentation:
- README.md updated with feature description
- CHANGELOG.md with complete overview
- TODO.md marking feature complete
- FEATURE_PLAN finalized with all tasks completed
11 tasks completed, ~21 hours development time
Ready for production deployment
- Update README.md with comprehensive feature description
- Add automatic cleanup and deletion log to features list
- Document countdown display and 7-day retention policy
- Add Testing section with test-cleanup.sh instructions
- Update API endpoints with new admin routes
- Update CHANGELOG.md with complete feature overview
- Backend: Services, Repositories, Scheduler, API endpoints
- Frontend: DeletionLogSection, countdown, SweetAlert2 feedback
- Infrastructure: nginx config updates
- Testing: Comprehensive test tools and documentation
- Update TODO.md marking feature as completed
- Update FEATURE_PLAN with final status
- All 11 tasks completed (100%)
- Bug fixes documented
- Deployment checklist updated
- Final timeline and statistics
- Organize test files into tests/ directory
- Move TESTING-CLEANUP.md to tests/
- Move test-cleanup.sh to tests/
Feature is now complete and ready for merge.
The /moderation page is already password-protected, so API routes
called from that page don't need additional authentication.
This fixes 'Unexpected token <' error in deletion log display.
- Add POST /api/admin/cleanup/trigger for manual cleanup
- Add GET /api/admin/cleanup/preview for dry-run testing
- Create test-cleanup.sh (bash) for easy testing
- Create test-cleanup.js (node) as alternative test tool
- Enable backdating groups for testing purposes
- Create DeletionLogSection component
- Integrate deletion log at bottom of moderation page
- Remove standalone DeletionLogPage and route
- Remove admin nav link (log now in moderation)
- Keep /api/admin routes for backend API access
- Update nginx configs (remove /admin frontend route)
- Create DeletionLogPage with statistics cards and deletion history table
- Add admin navigation link to Navbar
- Configure nginx for /admin and /api/admin routes (dev+prod)
- Add password protection for admin routes
- Support toggle between last 10 and all deletions
- Removed unnecessary migration for approved column (already in DatabaseManager.js)
- Marked existing API endpoint PATCH /groups/:groupId/approve as reusable
- Marked existing repository methods (updateGroupApproval, deleteImage) as reusable
- Updated Phase 1 Task 1 to reflect current state
- Only need to add performance indexes for cleanup queries
Features:
- Add image description field (max 200 chars) for individual images
- Replace 'Sort' button with 'Edit' button in image gallery cards
- Enable edit mode with text fields for each image in moderation
- Display descriptions in slideshow and public views
- Integrate description saving with main save button
Frontend changes:
- ImageGalleryCard: Add edit mode UI with textarea and character counter
- ModerationGroupImagesPage: Integrate description editing into main save flow
- Fix keyboard event propagation in textarea (spacebar issue)
- Remove separate 'Save Descriptions' button
- Add ESLint fixes for useCallback dependencies
Backend changes:
- Fix route order: batch-description route must come before :imageId route
- Ensure batch description update API works correctly
Build optimizations:
- Add .dockerignore to exclude development data (182MB reduction)
- Fix Dockerfile: Remove non-existent frontend/conf directory
- Reduce backend image size from 437MB to 247MB
Fixes:
- Fix route matching issue with batch-description endpoint
- Prevent keyboard events from triggering drag-and-drop
- Clean up unused functions and ESLint warnings