Project-Image-Uploader/README.md
matthias.lotz e4ddd229b8 feat: Public/Internal Host Separation
Implemented subdomain-based feature separation for production deployment.

**Backend:**
- New hostGate middleware for host-based API protection
- Public host blocks: /api/admin, /api/groups, /api/slideshow, /api/auth
- Public host allows: /api/upload, /api/manage, /api/social-media/platforms
- Rate limiting: 20 uploads/hour on public host (publicUploadLimiter)
- Audit log enhancement: source_host, source_type tracking
- Database migration 009: Added source tracking columns

**Frontend:**
- Host detection utility (hostDetection.js) with feature flags
- React code splitting with lazy loading for internal features
- Conditional routing: Internal routes only mounted on internal host
- 404 page: Host-specific messaging and navbar
- Clipboard fallback for HTTP environments

**Configuration:**
- Environment variables: PUBLIC_HOST, INTERNAL_HOST, ENABLE_HOST_RESTRICTION
- Docker dev setup: HOST variables, TRUST_PROXY_HOPS configuration
- Frontend .env.development: DANGEROUSLY_DISABLE_HOST_CHECK for Webpack

**Testing:**
- 20/20 hostGate unit tests passing
- Local testing guide in README.dev.md
- /etc/hosts setup for public.test.local, internal.test.local

**Bug Fixes:**
- Fixed clipboard API not available on HTTP
- Fixed missing PUBLIC_HOST in frontend env-config.js
- Fixed wrong navbar on 404 page for public host
- Fixed social media platforms loading in UUID management

**Documentation:**
- CHANGELOG.md: Complete feature documentation
- README.md: Feature overview
- README.dev.md: Host-separation testing guide
- TESTING-HOST-SEPARATION.md: Integration note
2025-11-25 22:02:53 +01:00

637 lines
27 KiB
Markdown
Raw Blame History

# 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)
- **🌐 Public/Internal Host Separation** (Nov 25):
- Subdomain-based feature separation for production deployment
- Public host (`deinprojekt.hobbyhimmel.de`): Upload + UUID Management only
- Internal host (`deinprojekt.lan.hobbyhimmel.de`): Full admin access
- Frontend code splitting with React.lazy() for optimized bundle size
- Backend API protection via hostGate middleware
- Rate limiting: 20 uploads/hour on public host
- Audit log tracking with source host information
- Complete local testing support via /etc/hosts entries
- Zero configuration overhead for single-host deployments
- **🧪 Comprehensive Test Suite** (Nov 16):
- 45 automated tests covering all API endpoints (100% passing)
- Jest + Supertest integration testing framework
- Unit tests for authentication middleware
- API tests for admin, consent, migration, and upload endpoints
- In-memory SQLite database for isolated testing
- Coverage: 26% statements, 15% branches (realistic starting point)
- Test execution time: ~10 seconds for full suite
- CI/CD ready with proper teardown and cleanup
- **🔒 Admin Session Authentication** (Nov 16):
- Server-managed HTTP sessions for all admin/system endpoints
- CSRF protection on every mutating request via `X-CSRF-Token`
- Secure `ADMIN_SESSION_SECRET` configuration keeps cookies tamper-proof
- Protected routes: `/api/admin/*`, `/api/system/migration/migrate`, `/api/system/migration/rollback`
- Session-aware moderation UI with login + first-admin setup wizard
- Complete authentication documentation in `AUTHENTICATION.md`
- **📋 API Route Documentation** (Nov 16):
- Single Source of Truth: `backend/src/routes/routeMappings.js`
- Comprehensive route overview in `backend/src/routes/README.md`
- Critical Express routing order documented (specific before generic)
- Frontend-ready route reference with authentication requirements
- OpenAPI specification auto-generation integrated
- **🔐 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 admin session)
- **Authentication Flow**:
- Built-in login form establishes a server session stored in HttpOnly cookies
- First-time setup wizard creates the initial admin user once `ADMIN_SESSION_SECRET` is configured
- CSRF token must be included (header `X-CSRF-Token`) for any mutating admin API call
- `AUTHENTICATION.md` documents CLI/cURL examples for managing sessions and CSRF tokens
- **Protected Endpoints**: All `/api/admin/*` routes require authentication
- **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:5001` | 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)