Project-Image-Uploader/README.md
matthias.lotz a0d74f795a feat: Complete frontend refactoring and development environment setup
Major Frontend Refactoring:
- Replace ImagePreviewGallery with unified ImageGallery/ImageGalleryCard components
  - Support 4 display modes: group, moderation, preview, single-image
  - Add hidePreview prop to conditionally hide group preview images
  - Unified grid layout with responsive 3/2/1 column design

- Remove 15+ legacy files and components
  - Delete UploadedImagePage, SocialMedia components, old upload components
  - Remove unused CSS files (GroupCard.css, Image.css/scss)
  - Clean up /upload/:image_url route from App.js

- Fix image preview functionality in MultiUploadPage
  - Convert File objects to blob URLs with URL.createObjectURL()
  - Add proper memory cleanup with URL.revokeObjectURL()

- Improve page navigation and layout
  - Fix GroupsOverviewPage to route to /groups/:groupId detail page
  - Adjust PublicGroupImagesPage spacing and layout
  - Fix ModerationGroupsPage duplicate stats section

CSS Refactoring:
- Rename GroupCard.css → ImageGallery.css with updated class names
- Maintain backward compatibility with legacy class names
- Fix grid stretching with fixed 3-column layout

Development Environment:
- Add docker-compose.override.yml for local development
- Create Dockerfile.dev with hot-reload support
- Add start-dev.sh and nginx.dev.conf
- Update README.dev.md with development setup instructions

Production Build:
- Fix frontend/Dockerfile multi-stage build (as → AS)
- Update prod.sh to explicitly use docker-compose.yml (ignore override)
- Resolve node:18-alpine image corruption issue
- Backend Dockerfile improvements for Node 14 compatibility

Documentation:
- Update TODO.md marking completed frontend tasks
- Clean up docs/images directory
- Update README.md with current project status

All changes tested and verified in both development and production environments.
2025-10-27 22:22:52 +01:00

9.0 KiB

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
Slideshow Mode: Automatic fullscreen slideshow with smooth transitions
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
Lightweight: Built with modern web technologies for optimal performance

What's New

This project extends the original Image-Uploader by vallezw with enhanced multi-upload and slideshow capabilities.

  • Multi-image batch upload with progress tracking
  • Automatic slideshow presentation mode
  • Image grouping with descriptions
  • Random slideshow rotation
  • Keyboard navigation support
  • Mobile-responsive design

Quick Start

  1. Create docker-compose.yml:
services:
    image-uploader-frontend:
        image: gitea.lan.hobbyhimmel.de/hobbyhimmel/image-uploader-frontend:latest
        ports:
            - "80:80"
        build: 
            context: ./frontend
            dockerfile: ./Dockerfile
        depends_on:
            - "image-uploader-backend"
        environment:
            - "API_URL=http://image-uploader-backend:5000"
            - "CLIENT_URL=http://localhost"
        container_name: "image-uploader-frontend"
        networks:
            - npm-nw
            - image-uploader-internal
        
    image-uploader-backend:
        image: gitea.lan.hobbyhimmel.de/hobbyhimmel/image-uploader-backend:latest
        ports:
            - "5000:5000"
        build:
            context: ./backend
            dockerfile: ./Dockerfile
        container_name: "image-uploader-backend"
        networks:
            - image-uploader-internal
        volumes:
            - app-data:/usr/src/app/src/data

volumes:
    app-data:
        driver: local

networks:
    npm-nw:
        external: true
    image-uploader-internal:
        driver: bridge
  1. Start the application:
docker compose up -d 
  1. Access the application:
  • Upload Interface: http://localhost
  • Backend: http://localhost:5000
  • Slideshow Mode: http://localhost/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. Click "Upload Images" to process the batch
  5. Images are automatically grouped for slideshow viewing

Slideshow Mode

  • Automatic Access: Navigate to http://localhost/slideshow

  • Features:

    • Fullscreen presentation
    • 4-second display per image
    • Automatic progression through all slideshow collections
    • Random selection of next slideshow after completing current one
    • 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

Moderation Interface (Protected)

  • Access: http://localhost/moderation (requires authentication)

  • Authentication: HTTP Basic Auth (username: admin, password: set during setup)

  • Features:

    • Review pending image groups before public display
    • Approve or reject submitted collections
    • Delete individual images from approved groups
    • View group details (title, creator, description, image count)
    • Bulk moderation actions
  • 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

Data Structure

Data are stored in sqlite database. The structure is as follows:

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,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
                );
CREATE TABLE sqlite_sequence(name,seq);
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,
                    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
                );
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_images_group_id ON images(group_id);
CREATE INDEX idx_images_upload_order ON images(upload_order);
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;

Architecture

Backend (Node.js + Express)

  • Multi-upload API: /api/upload/batch - Handles batch file processing
  • Groups API: /api/groups - Retrieves slideshow collections
  • File Storage: Organized in /upload directory
  • 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
        │   ├── ZMmHXzHbqw.jpg
        │   ├── tjjnngOmXS.jpg
        │   └── ...
        └── data
           └── 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
  • GET /api/groups - Retrieve all slideshow groups
  • GET /api/groups/:id - Get specific slideshow group

Moderation Operations (Protected)

  • GET /moderation/groups - Get all groups pending moderation
  • POST /groups/:id/approve - Approve a group for public display
  • DELETE /groups/:id - Delete an entire group
  • DELETE /groups/:id/images/:imageId - Delete individual image from group

File Access

  • GET /api/upload/:filename - Access uploaded image files

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

docker cp backend:/usr/src/app/src/data/ ./backup-data

Restore slideshow data

docker cp ./backup-data backend:/usr/src/app/src/data

Contributing

Contributions are welcome!
This project extends the original work by vallezw.

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