README.md: - Updated Phase 2 completion date: Nov 11-14 → Nov 11-15 - Added new section: Modular UI Architecture (Nov 15) - Listed all reusable components and their modes - Added code reduction metrics (62% reduction, -227 net lines) - Removed outdated 'email link' mention CHANGELOG.md: - Complete rewrite for feature/SocialMedia branch - Added Phase 1: Social Media Consent Management (Nov 9-10) * Backend: Migrations, APIs, validation * Frontend: ConsentCheckboxes, ConsentBadges, filters * Testing results and GDPR compliance - Added Phase 2 Backend: Management Portal (Nov 11) * Management APIs, security features, audit log * Rate limiting and brute-force protection - Added Phase 2 Frontend: Management Portal UI (Nov 13-14) * ManagementPortalPage, component reuse * Upload success integration - Added Phase 2 UI Refactoring (Nov 15) * 4 new modular components (686 lines) * Multi-mode support (upload/edit/moderate) * Code reduction metrics * UI consistency patterns * Bug fixes All documentation now accurately reflects Nov 9-15 work.
595 lines
24 KiB
Markdown
595 lines
24 KiB
Markdown
# Image Uploader with Multi-Upload & Slideshow
|
||
|
||
A self-hosted image uploader with multi-image upload capabilities and automatic slideshow functionality.
|
||
|
||
## Features
|
||
|
||
**Multi-Image Upload**: Upload multiple images at once with batch processing
|
||
**Social Media Consent Management**: 🆕 GDPR-compliant consent system for workshop display and social media publishing
|
||
**Automatic Cleanup**: 🆕 Unapproved groups are automatically deleted after 7 days
|
||
**Deletion Log**: 🆕 Complete audit trail of automatically deleted content
|
||
**Drag-and-Drop Reordering**: 🆕 User during upload and admins can reorder images via intuitive drag-and-drop interface
|
||
**Slideshow Mode**: Automatic fullscreen slideshow with smooth transitions (respects custom ordering)
|
||
**Preview Image Optimization**: Automatic thumbnail generation for faster gallery loading (96-98% size reduction)
|
||
**Touch-Friendly Interface**: 🆕 Mobile-optimized drag handles and responsive design
|
||
**Moderation Panel**: Dedicated moderation interface with consent filtering and export
|
||
**Persistent Storage**: Docker volumes ensure data persistence across restarts
|
||
**Clean UI**: Minimalist design focused on user experience
|
||
**Self-Hosted**: Complete control over your data and infrastructure
|
||
|
||
## What's New
|
||
This project extends the original [Image-Uploader by vallezw](https://github.com/vallezw/Image-Uploader) with enhanced multi-upload and slideshow capabilities.
|
||
|
||
### 🆕 Latest Features (November 2025)
|
||
- **🔐 Social Media Consent Management** (Phase 1 Complete - Nov 9-10):
|
||
- GDPR-compliant consent system for image usage
|
||
- Mandatory workshop display consent (no upload without approval)
|
||
- Optional per-platform consents (Facebook, Instagram, TikTok)
|
||
- Consent badges and filtering in moderation panel
|
||
- CSV/JSON export for legal documentation
|
||
- Group ID tracking for consent withdrawal requests
|
||
- **🔑 Self-Service Management Portal** (Phase 2 Complete - Nov 11-15):
|
||
- Secure UUID-based management tokens for user self-service
|
||
- Frontend portal at `/manage/:token` for consent management
|
||
- Revoke/restore consents for workshop and social media
|
||
- Edit metadata (title, description) after upload
|
||
- Add/delete images after upload (with moderation re-approval)
|
||
- Complete group deletion with audit trail
|
||
- IP-based rate limiting (10 requests/hour)
|
||
- Brute-force protection (20 failed attempts → 24h ban)
|
||
- Management audit log for security tracking
|
||
- **🎨 Modular UI Architecture** (Nov 15):
|
||
- Reusable components: ConsentManager, GroupMetadataEditor, ImageDescriptionManager
|
||
- Multi-mode support: upload/edit/moderate modes for maximum reusability
|
||
- Code reduction: 62% in ModerationGroupImagesPage (281→107 lines)
|
||
- Consistent design: HTML buttons, Paper boxes, Material-UI Alerts
|
||
- Individual save/discard per component section
|
||
- Zero code duplication between pages
|
||
- **<2A> Slideshow Optimization**: Intelligent image preloading eliminates loading delays and duplicate images
|
||
- **📅 Chronological Display**: Slideshows now play in chronological order (year → upload date)
|
||
- **Automatic Cleanup**: Unapproved groups are automatically deleted after 7 days
|
||
- **Deletion Log**: Complete audit trail with statistics (groups, images, storage freed)
|
||
- **Countdown Display**: Visual indicator showing days until automatic deletion
|
||
- **Approval Feedback**: SweetAlert2 notifications for moderation actions
|
||
- **Manual Cleanup Trigger**: Admin API endpoints for testing and manual cleanup
|
||
- **Image Descriptions**: Add optional descriptions to individual images (max 200 characters)
|
||
- **Edit Mode**: Edit descriptions for uploaded images in upload preview and moderation interface
|
||
- **Slideshow Display**: Image descriptions shown as overlays during slideshow presentation
|
||
- **Public Display**: Descriptions visible in public group views and galleries
|
||
|
||
### Previous Features (October 2025)
|
||
- **Drag-and-Drop Image Reordering**: Admins can now reorder images using intuitive drag-and-drop
|
||
- **Touch-Friendly Interface**: Mobile-optimized controls with always-visible drag handles
|
||
- **Slideshow Integration**: Custom image order automatically applies to slideshow mode
|
||
- **Optimistic UI Updates**: Immediate visual feedback with error recovery
|
||
- **Comprehensive Admin Panel**: Dedicated moderation interface for content curation
|
||
|
||
### Core Features
|
||
- Multi-image batch upload with progress tracking
|
||
- Automatic slideshow presentation mode
|
||
- Image grouping with descriptions and metadata
|
||
- Random slideshow rotation with custom ordering support
|
||
- Keyboard navigation support (Slideshow: Space/Arrow keys, Escape to exit)
|
||
- Mobile-responsive design with touch-first interactions
|
||
|
||
## Quick Start
|
||
|
||
### Docker Deployment (Recommended)
|
||
|
||
#### Production Environment
|
||
|
||
```bash
|
||
# Start production environment
|
||
./prod.sh
|
||
|
||
# Or manually:
|
||
docker compose -f docker/prod/docker-compose.yml up -d
|
||
```
|
||
|
||
#### Development Environment
|
||
|
||
```bash
|
||
# Start development environment
|
||
./dev.sh
|
||
|
||
# Or manually:
|
||
docker compose -f docker/dev/docker-compose.yml up -d
|
||
### Access URLs
|
||
|
||
#### Production (Port 80):
|
||
- Upload Interface: `http://localhost`
|
||
- Slideshow Mode: `http://localhost/slideshow`
|
||
- Groups Overview: `http://localhost/groups`
|
||
- Moderation Panel: `http://localhost/moderation` (requires authentication)
|
||
|
||
#### Development (Port 3000):
|
||
- Upload Interface: `http://localhost:3000`
|
||
- Backend API: `http://localhost:5001`
|
||
- Slideshow Mode: `http://localhost:3000/slideshow`
|
||
|
||
### Multi-Image Upload
|
||
|
||
1. Visit `http://localhost`
|
||
2. Drag & drop multiple images or click to select
|
||
3. Add an optional description for your image collection
|
||
4. **Grant Consent** (mandatory):
|
||
- ✅ **Workshop Display**: Required consent to display images on local monitor
|
||
- ☐ **Social Media** (optional): Per-platform consent for Facebook, Instagram, TikTok
|
||
5. Click "Upload Images" to process the batch
|
||
6. Receive your **Group ID** and **Management Link** as reference
|
||
7. Images are grouped and await moderation approval
|
||
|
||
### Self-Service Management Portal
|
||
|
||
After upload, users receive a unique management link (`/manage/:token`) to:
|
||
|
||
- **View Upload**: See all images and metadata
|
||
- **Manage Consents**: Revoke or restore workshop/social media consents
|
||
- **Edit Metadata**: Update title, description, year (triggers re-moderation)
|
||
- **Manage Images**: Add new images or delete existing ones
|
||
- **Delete Group**: Complete removal with double-confirmation
|
||
- **Email Contact**: Request deletion of already published social media posts
|
||
|
||
**Security Features**:
|
||
- No authentication required (token-based access)
|
||
- Rate limiting: 10 requests per hour per IP
|
||
- Brute-force protection: 20 failed attempts → 24h ban
|
||
- Complete audit trail of all management actions
|
||
|
||
### Slideshow Mode
|
||
|
||
- **Automatic Access**: Navigate to `http://localhost/slideshow`
|
||
- **Features**:
|
||
- Fullscreen presentation
|
||
- 4-second display per image
|
||
- Automatic progression through all slideshow collections
|
||
- **🆕 Chronological order**: Groups play from oldest to newest (year → upload date)
|
||
- **🆕 Intelligent preloading**: Next images load in background for seamless transitions
|
||
- **🆕 Zero loading delays**: Pre-cached images for instant display
|
||
- Smooth fade transitions (0.5s)
|
||
|
||
- **Keyboard Controls**:
|
||
- **ESC**: Exit slideshow / Return to upload page
|
||
- **Spacebar / Arrow Right**: Manually advance to next image
|
||
- **Home Button**: Return to main upload interface
|
||
|
||
### Preview Image Optimization
|
||
|
||
The application automatically generates optimized preview thumbnails for all uploaded images to significantly improve gallery loading performance.
|
||
|
||
- **Automatic Generation**:
|
||
- Preview images are created automatically on server startup
|
||
- Existing images without previews are processed on-demand
|
||
- New uploads generate previews immediately during upload
|
||
|
||
- **Technical Specifications**:
|
||
- **Max Width**: 800px (maintains aspect ratio)
|
||
- **Format**: JPEG with 85% quality
|
||
- **Size Reduction**: 96-98% smaller than originals (e.g., 2076KB → 58.5KB)
|
||
- **Performance**: ~30x faster gallery loading times
|
||
|
||
- **Smart Image Loading**:
|
||
- **Galleries & Overview**: Load lightweight preview images (~50-100KB)
|
||
- **Slideshow Mode**: Uses full-resolution originals for best quality
|
||
- **Fallback**: Automatically uses originals if preview generation fails
|
||
|
||
- **Storage**:
|
||
- Originals: `backend/src/data/images/` (~2-4MB per image)
|
||
- Previews: `backend/src/data/previews/` (~50-100KB per image)
|
||
- Database: `preview_path` column stores preview filename
|
||
|
||
### Moderation Interface (Protected)
|
||
|
||
- **Access**: `http://localhost/moderation` (requires authentication)
|
||
- **Authentication**: HTTP Basic Auth (username: hobbyadmin, password: set during setup)
|
||
- **Features**:
|
||
- Review pending image groups before public display
|
||
- Visual countdown showing days until automatic deletion (7 days for unapproved groups)
|
||
- **Consent Management**:
|
||
- Visual consent badges showing social media platforms
|
||
- Filter by consent status (All / Workshop-only / Facebook / Instagram / TikTok)
|
||
- Export consent data as CSV/JSON for legal compliance
|
||
- Consent timestamp tracking
|
||
- Approve or reject submitted collections with instant feedback
|
||
- Delete individual images from approved groups
|
||
- View group details (title, creator, description, image count)
|
||
- **Deletion Log** (bottom of moderation page):
|
||
- Statistics: Total groups/images deleted, storage freed
|
||
- Detailed history table with timestamps and reasons
|
||
- Toggle between last 10 entries and complete history
|
||
- Bulk moderation actions
|
||
|
||
- **Automatic Cleanup**:
|
||
- Unapproved groups are automatically deleted after 7 days
|
||
- Daily cleanup runs at 10:00 AM (Europe/Berlin timezone)
|
||
- Complete removal: Database entries + physical files (originals + previews)
|
||
- Full audit trail logged for compliance
|
||
- **Note**: Approved groups are NEVER automatically deleted
|
||
|
||
- **Security Features**:
|
||
- Password protected access via nginx HTTP Basic Auth
|
||
- Hidden from search engines (`robots.txt` + `noindex` meta tags)
|
||
- No public links or references in main interface
|
||
|
||
### Public Overview of all approved slideshows
|
||
- **Group Management**: Navigate to `http://localhost/groups`
|
||
- Overview of all approved slideshow collections
|
||
- Launch slideshow mode from any group
|
||
- View group statistics and metadata
|
||
|
||
|
||
## Docker Structure
|
||
|
||
The application uses separate Docker configurations for development and production:
|
||
|
||
```
|
||
docker/
|
||
├── .env.backend.example # Backend environment variables documentation
|
||
├── .env.frontend.example # Frontend environment variables documentation
|
||
├── dev/ # Development environment
|
||
│ ├── docker-compose.yml # Development services configuration
|
||
│ ├── backend/
|
||
│ │ ├── config/.env # Development backend configuration
|
||
│ │ └── Dockerfile # Development backend container
|
||
│ └── frontend/
|
||
│ ├── config/.env # Development frontend configuration
|
||
│ ├── config/env.sh # Runtime configuration script
|
||
│ ├── Dockerfile # Development frontend container
|
||
│ ├── nginx.conf # Development nginx configuration
|
||
│ └── start.sh # Development startup script
|
||
└── prod/ # Production environment
|
||
├── docker-compose.yml # Production services configuration
|
||
├── backend/
|
||
│ ├── config/.env # Production backend configuration
|
||
│ └── Dockerfile # Production backend container
|
||
└── frontend/
|
||
├── config/.env # Production frontend configuration
|
||
├── config/env.sh # Runtime configuration script
|
||
├── config/htpasswd # HTTP Basic Auth credentials
|
||
├── Dockerfile # Production frontend container
|
||
└── nginx.conf # Production nginx configuration
|
||
```
|
||
|
||
### Environment Configuration
|
||
|
||
- **Development**: Uses `docker/dev/` configuration with live reloading
|
||
- **Production**: Uses `docker/prod/` configuration with optimized builds
|
||
- **Scripts**: Use `./dev.sh` or `./prod.sh` for easy deployment
|
||
|
||
## Data Structure
|
||
|
||
Data are stored in SQLite database. The structure is as follows:
|
||
|
||
### Core Tables
|
||
|
||
``` sql
|
||
-- Groups table (extended with consent fields)
|
||
CREATE TABLE groups (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
group_id TEXT UNIQUE NOT NULL,
|
||
year INTEGER NOT NULL,
|
||
title TEXT NOT NULL,
|
||
description TEXT,
|
||
name TEXT,
|
||
upload_date DATETIME NOT NULL,
|
||
approved BOOLEAN DEFAULT FALSE,
|
||
display_in_workshop BOOLEAN NOT NULL DEFAULT 0, -- Consent for workshop display
|
||
consent_timestamp DATETIME, -- When consent was granted
|
||
management_token TEXT, -- For Phase 2: Self-service portal
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Images table
|
||
CREATE TABLE images (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
group_id TEXT NOT NULL,
|
||
file_name TEXT NOT NULL,
|
||
original_name TEXT NOT NULL,
|
||
file_path TEXT NOT NULL,
|
||
preview_path TEXT, -- Optimized thumbnail path
|
||
image_description TEXT, -- Individual image description
|
||
upload_order INTEGER NOT NULL,
|
||
file_size INTEGER,
|
||
mime_type TEXT,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (group_id) REFERENCES groups(group_id) ON DELETE CASCADE
|
||
);
|
||
|
||
-- Deletion log for audit trail
|
||
CREATE TABLE deletion_log (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
group_id TEXT NOT NULL,
|
||
title TEXT,
|
||
name TEXT,
|
||
upload_date DATETIME,
|
||
image_count INTEGER,
|
||
total_size INTEGER,
|
||
deletion_reason TEXT,
|
||
deleted_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
### Social Media Consent Tables
|
||
|
||
``` sql
|
||
-- Configurable social media platforms
|
||
CREATE TABLE social_media_platforms (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
platform_name TEXT UNIQUE NOT NULL, -- e.g., 'facebook', 'instagram', 'tiktok'
|
||
display_name TEXT NOT NULL, -- e.g., 'Facebook', 'Instagram', 'TikTok'
|
||
icon_name TEXT, -- Material-UI Icon name
|
||
is_active BOOLEAN DEFAULT 1,
|
||
sort_order INTEGER DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Per-group, per-platform consent tracking
|
||
CREATE TABLE 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, -- For Phase 2: Consent revocation
|
||
revoked_timestamp DATETIME, -- When consent was revoked
|
||
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)
|
||
);
|
||
|
||
-- Management audit log (Phase 2)
|
||
CREATE TABLE management_audit_log (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
group_id TEXT,
|
||
management_token TEXT, -- First 8 characters only (masked)
|
||
action TEXT NOT NULL, -- validate_token, revoke_consent, edit_metadata, add_images, delete_image, delete_group
|
||
success BOOLEAN NOT NULL,
|
||
error_message TEXT,
|
||
ip_address TEXT,
|
||
user_agent TEXT,
|
||
request_data TEXT, -- JSON of request body
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (group_id) REFERENCES groups(group_id) ON DELETE SET NULL
|
||
);
|
||
|
||
-- Indexes for performance
|
||
CREATE INDEX IF NOT EXISTS idx_audit_group_id ON management_audit_log(group_id);
|
||
CREATE INDEX IF NOT EXISTS idx_audit_action ON management_audit_log(action);
|
||
CREATE INDEX IF NOT EXISTS idx_audit_success ON management_audit_log(success);
|
||
CREATE INDEX IF NOT EXISTS idx_audit_created_at ON management_audit_log(created_at);
|
||
CREATE INDEX IF NOT EXISTS idx_audit_ip_address ON management_audit_log(ip_address);
|
||
revoked_timestamp DATETIME,
|
||
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)
|
||
);
|
||
|
||
-- Migration tracking
|
||
CREATE TABLE schema_migrations (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
migration_name TEXT UNIQUE NOT NULL,
|
||
applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
### Indexes
|
||
|
||
``` sql
|
||
-- Groups indexes
|
||
CREATE INDEX idx_groups_group_id ON groups(group_id);
|
||
CREATE INDEX idx_groups_year ON groups(year);
|
||
CREATE INDEX idx_groups_upload_date ON groups(upload_date);
|
||
CREATE INDEX idx_groups_display_consent ON groups(display_in_workshop);
|
||
CREATE UNIQUE INDEX idx_groups_management_token ON groups(management_token) WHERE management_token IS NOT NULL;
|
||
|
||
-- Images indexes
|
||
CREATE INDEX idx_images_group_id ON images(group_id);
|
||
CREATE INDEX idx_images_upload_order ON images(upload_order);
|
||
|
||
-- Consent indexes
|
||
CREATE INDEX idx_consents_group_id ON group_social_media_consents(group_id);
|
||
CREATE INDEX idx_consents_platform_id ON group_social_media_consents(platform_id);
|
||
CREATE INDEX idx_consents_consented ON group_social_media_consents(consented);
|
||
```
|
||
|
||
### Triggers
|
||
|
||
``` sql
|
||
-- Update timestamp on groups modification
|
||
CREATE TRIGGER update_groups_timestamp
|
||
AFTER UPDATE ON groups
|
||
FOR EACH ROW
|
||
BEGIN
|
||
UPDATE groups SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||
END;
|
||
|
||
-- Update timestamp on consent modification
|
||
CREATE TRIGGER 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;
|
||
```
|
||
|
||
## Architecture
|
||
### Backend (Node.js + Express)
|
||
- **Multi-upload API**: `/api/upload/batch` - Handles batch file processing
|
||
- **Groups API**: `/api/groups` - Retrieves slideshow collections
|
||
- **Preview Generation**: Automatic thumbnail creation using Sharp (800px JPEG, 85% quality)
|
||
- **File Storage**: Organized in `/upload` directory (originals) and `/data/previews` (thumbnails)
|
||
- **Database Storage**: sqlite database in `/app/src/data/db/image_uploader.db`
|
||
|
||
### Frontend (React + Material-UI)
|
||
|
||
- **Multi-Upload Interface**: Drag & drop with preview gallery
|
||
- **Progress Tracking**: Real-time upload status
|
||
- **Spacebar / Arrow Right**: Manually advance to next image
|
||
- **Slideshow Engine**: Fullscreen presentation with automatic progression
|
||
- **Responsive Design**: Mobile and desktop optimized
|
||
- **Home Button**: Return to main upload interface
|
||
|
||
|
||
### Storage Architecture
|
||
|
||
```
|
||
Docker Volume (app-data)
|
||
src
|
||
└── app
|
||
├── src
|
||
├── upload (originals, ~2-4MB each)
|
||
│ ├── ZMmHXzHbqw.jpg
|
||
│ ├── tjjnngOmXS.jpg
|
||
│ └── ...
|
||
└── data
|
||
├── previews (thumbnails, ~50-100KB each)
|
||
│ ├── ZMmHXzHbqw.jpg
|
||
│ ├── tjjnngOmXS.jpg
|
||
│ └── ...
|
||
└── db
|
||
└── image_uploader.db
|
||
|
||
```
|
||
|
||
### Hosting it with Docker
|
||
|
||
- **Frontend**: React 17, Material-UI, React Router
|
||
- **Backend**: Node.js, Express, Multer (file handling)
|
||
- **Containerization**: Docker, Docker Compose
|
||
- **Reverse Proxy**: nginx (routing & file serving)[In order to host the project you will need to create a docker-compose file. These files are combining multiple docker images to interact with each other.
|
||
- **File Upload**: Drag & drop with react-dropzone
|
||
- **Notifications**: SweetAlert2
|
||
|
||
## API Endpoints
|
||
### Upload Operations
|
||
|
||
- `POST /api/upload/batch` - Upload multiple images with description and consent data
|
||
- `GET /api/groups` - Retrieve all slideshow groups
|
||
- `GET /api/groups/:id` - Get specific slideshow group
|
||
|
||
### Consent Management
|
||
|
||
- `GET /api/social-media/platforms` - Get list of active social media platforms
|
||
- `POST /api/groups/:groupId/consents` - Save consent data for a group
|
||
- `GET /api/groups/:groupId/consents` - Get consent data for a group
|
||
- `GET /api/admin/groups/by-consent` - Filter groups by consent status (query params: `?workshopConsent=true&platform=facebook`)
|
||
- `GET /api/admin/consents/export` - Export all consent data as CSV/JSON
|
||
|
||
### User Self-Service Management Portal (Phase 2 - Backend Complete)
|
||
|
||
**Management Portal APIs** (Token-based authentication):
|
||
- `GET /api/manage/:token` - Validate management token and retrieve group data
|
||
- `PUT /api/manage/:token/consents` - Revoke or restore consents (workshop & social media)
|
||
- `PUT /api/manage/:token/metadata` - Edit group title and description (resets approval status)
|
||
- `POST /api/manage/:token/images` - Add new images to existing group (max 50 total, resets approval)
|
||
- `DELETE /api/manage/:token/images/:imageId` - Delete individual image (prevents deleting last image)
|
||
- `DELETE /api/manage/:token` - Delete entire group with all images and data
|
||
|
||
**Management Audit Log APIs** (Admin access only):
|
||
- `GET /api/admin/management-audit?limit=N` - Retrieve recent management actions (default: 10)
|
||
- `GET /api/admin/management-audit/stats` - Get statistics (total actions, success rate, unique IPs)
|
||
- `GET /api/admin/management-audit/group/:groupId` - Get audit log for specific group
|
||
|
||
**Security Features**:
|
||
- IP-based rate limiting: 10 requests per hour per IP
|
||
- Brute-force protection: 20 failed token validations → 24-hour IP ban
|
||
- Complete audit trail: All management actions logged with IP, User-Agent, timestamp
|
||
- Token masking: Only first 8 characters stored in audit log for privacy
|
||
- Automatic file cleanup: Physical deletion of images when removed via API
|
||
|
||
### Moderation Operations (Protected)
|
||
|
||
- `GET /moderation/groups` - Get all groups pending moderation (includes consent info)
|
||
- `PATCH /groups/:id/approve` - Approve/unapprove a group for public display
|
||
- `DELETE /groups/:id` - Delete an entire group
|
||
- `DELETE /groups/:id/images/:imageId` - Delete individual image from group
|
||
|
||
### Admin Operations (Protected by /moderation access)
|
||
|
||
- `GET /api/admin/deletion-log?limit=N` - Get recent deletion log entries (default: 10)
|
||
- `GET /api/admin/deletion-log/all` - Get complete deletion history
|
||
- `GET /api/admin/deletion-log/stats` - Get deletion statistics (total groups/images deleted, storage freed)
|
||
- `POST /api/admin/cleanup/trigger` - Manually trigger cleanup (for testing)
|
||
- `GET /api/admin/cleanup/preview` - Preview which groups would be deleted (dry-run)
|
||
|
||
### File Access
|
||
- `GET /api/upload/:filename` - Access uploaded image files (legacy, use `/api/download` instead)
|
||
- `GET /api/download/:filename` - Download original full-resolution images
|
||
- `GET /api/previews/:filename` - Access optimized preview thumbnails (~100KB, 800px width)
|
||
|
||
## Testing
|
||
|
||
### Automatic Cleanup Testing
|
||
|
||
The application includes comprehensive testing tools for the automatic cleanup feature:
|
||
|
||
```bash
|
||
# Run interactive test helper (recommended)
|
||
./tests/test-cleanup.sh
|
||
|
||
# Available test operations:
|
||
# 1. View unapproved groups with age
|
||
# 2. Backdate groups for testing (simulate 7+ day old groups)
|
||
# 3. Preview cleanup (dry-run)
|
||
# 4. Execute cleanup manually
|
||
# 5. View deletion log history
|
||
```
|
||
|
||
**Testing Workflow:**
|
||
1. Upload a test group (don't approve it)
|
||
2. Use test script to backdate it by 8 days
|
||
3. Preview what would be deleted
|
||
4. Execute cleanup and verify deletion log
|
||
|
||
For detailed testing instructions, see: [`tests/TESTING-CLEANUP.md`](tests/TESTING-CLEANUP.md)
|
||
|
||
## Configuration
|
||
### Environment Variables
|
||
|
||
| Variable | Default | Description |
|
||
|----------|---------|-------------|
|
||
| `API_URL` | `http://localhost:5000` | Backend API endpoint |
|
||
| `CLIENT_URL` | `http://localhost` | Frontend application URL |
|
||
|
||
### Volume Configuration
|
||
- **Upload Limits**: 100MB maximum file size for batch uploads
|
||
- **Supported Formats**: JPG, JPEG, PNG, GIF, WebP
|
||
|
||
|
||
### Backup & Restore
|
||
#### Backup slideshow data
|
||
```sh
|
||
docker cp image-uploader-backend:/usr/src/app/src/data/ ./image-uploader-backup-data
|
||
```
|
||
|
||
#### Restore slideshow data
|
||
```sh
|
||
docker cp ./image-uploader-backup-data image-uploader-backend:/usr/src/app/src/data
|
||
```
|
||
|
||
## Contributing
|
||
Contributions are welcome!
|
||
This project extends the original work by [vallezw](https://github.com/vallezw/Image-Uploader).
|
||
|
||
### Development Setup
|
||
1. Fork the repository
|
||
2. Create feature branch: `git checkout -b feature/amazing-feature`
|
||
3. Commit changes: `git commit -m 'Add amazing feature'`
|
||
4. Push to branch: `git push origin feature/amazing-feature`| Field | Type | Description |#### Changing the URL
|
||
5. Open a Pull Request
|
||
|
||
## License
|
||
This project is distributed under the MIT License. See `LICENSE` for more information.
|
||
|
||
## Acknowledgments
|
||
- Original project: [Image-Uploader by vallezw](https://github.com/vallezw/Image-Uploader)
|
||
|
||
|
||
|
||
|