Files
mule-image/README.md
dtoro 9729391dcc chore(docker): mount ~/Pictures read-write so file ops work; document
The first phase-11 file op (inline rename) returns EROFS today
because docker-compose mounts ~/Pictures read-only by default.
Lightroom-style file operations (rename, move, discard-pile empty)
all need to mutate the filesystem, so the right default is :rw.

Flips both the backend and worker mounts to :rw with an inline
comment explaining the trade-off, and adds a "Photo directory
mounts and permissions" section to the README that:
- States the default is now :rw
- Explains exactly which endpoints fail under :ro (rename, empty
  discard pile, future move/copy)
- Notes the implication: Mulita has full write access to whatever
  host directory ends up at /host/Pictures, same trust model as
  Lightroom's catalog folder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:56:27 +02:00

4.1 KiB

Mulita - Self-Hosted Photo Management Application

A self-hosted, Docker-deployed photo management application inspired by Lightroom's workflow. Mulita provides a fast, keyboard-driven interface to browse, organize, tag, and manage your photo library.

Features

  • Photo Organization: Browse photos in a timeline view with virtual scrolling for performance
  • Thumbnail Generation: Automatic thumbnail generation for all photo formats including RAW
  • Metadata Extraction: Full EXIF/XMP metadata extraction and search
  • Keyboard Shortcuts: Lightroom-style keyboard navigation and actions
  • File Support: JPEG, PNG, RAW formats (CR2, CR3, NEF, ARW, etc.), HEIC/HEIF, and videos
  • Heaps: Temporary collections for organizing photos
  • Tags & Ratings: Organize with tags, star ratings, and color labels
  • Dark Mode: Photography-optimized dark interface

Tech Stack

Backend

  • Python 3.12 with FastAPI
  • SQLite with SQLAlchemy (async)
  • Celery + Redis for background tasks
  • pyvips for fast thumbnail generation
  • ExifTool for metadata extraction

Frontend

  • React 18 with TypeScript
  • Vite for fast development
  • TanStack Query for data fetching
  • TanStack Virtual for virtualized scrolling
  • Tailwind CSS for styling
  • Zustand for state management

Quick Start

Prerequisites

  • Docker and Docker Compose
  • Photo directories to mount

Setup

  1. Clone the repository:
git clone <repository-url>
cd muleimage
  1. Configure your photo directories in .env:
# Edit .env file
PHOTO_DIRS=/path/to/your/photos
  1. Start the application:
docker-compose up -d
  1. Access the application at http://localhost:3000

Photo directory mounts and permissions

Mulita is a Lightroom-style manager — file operations (rename, move, discard, empty discard pile) need to mutate the filesystem under your photo mounts. The default docker-compose.yml mounts:

  • ${PHOTO_DIRS}/photos (read-write)
  • ~/Pictures/host/Pictures (read-write by default so file operations work on your system Pictures folder out of the box)

If you want a strict read-only library — for example pointing at a network share or your authoritative archive — change :rw to :ro on the mount in docker-compose.yml. Mulita will keep working for browsing, rating, color labels, picks, heaps, and the discard flag, but the following endpoints will return an error from the OS (EROFS / Read-only file system):

  • PATCH /photos/{id} with a new filename (rename)
  • DELETE /discard/empty (file unlinks)
  • Future move / copy endpoints

Heads up: with :rw, Mulita has full write access to whatever host directory you mount under ~/Pictures. Treat the same way you would Lightroom's catalog folder.

Architecture

The application consists of 5 Docker services:

  • frontend: React SPA served by Nginx
  • backend: FastAPI REST API
  • worker: Celery workers for background tasks
  • redis: Message broker for Celery
  • db: SQLite database (file-based)

Keyboard Shortcuts

Key Action
Navigate photos
Space Quick preview
Enter Open loupe view
P Pick photo
X Reject photo
1-5 Set star rating
Tab Toggle left sidebar
I Toggle metadata panel
G Grid view
E Loupe view
Delete Move to trash

Development

Backend Development

cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload

Frontend Development

cd frontend
npm install
npm run dev

Configuration

Edit mulita.yml to configure:

  • Source photo directories
  • Thumbnail sizes and quality
  • Scanner settings
  • Performance tuning

Performance

  • Handles 100,000+ photos efficiently
  • Virtual scrolling for smooth timeline navigation
  • Thumbnail generation at 10+ photos/second
  • SQLite FTS5 for fast full-text search

Future Features (Phase 2)

  • AI-powered scene classification
  • Face detection and clustering
  • Smart albums
  • Duplicate detection
  • Export presets
  • Multi-user support

License

MIT