Skip to content

Latest commit

 

History

86 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


License: AGPLv3

Immich Lite

A read-only, multi-user photo/video viewer — stripped from Immich v3.0.1

What this is

Immich Lite is a divergent fork of Immich (pinned at v3.0.1) cut down to a single job: point it at photo/video folders that already exist on disk, mounted read-only, and browse them — timeline, albums, favorites, video playback — with multi-user email/password auth. It does not track upstream Immich releases.

There is no upload, no backup, no machine learning, and no sharing. Assets only ever enter the system by scanning external library folders you mount into the container. The app never writes to your photo library; the only volumes it writes to are the Postgres database and a generated-media volume for thumbnails/previews/transcodes.

See docs-lite/spec.md for the full design rationale and docs-lite/plan.md for the task-by-task strip log.

What was removed from upstream Immich

  • Upload/backup ingest — no upload endpoints, mobile app, or mobile sync API. The external-library scanner is the only ingest path.
  • Machine learning — smart search (CLIP), facial recognition/people, duplicate detection, OCR. The immich-machine-learning container is gone entirely.
  • Sharing — public shared links, partner sharing, same-server album collaborators (albumUsers), and activity/comments.
  • Destructive & edit operations — trash/soft-delete, bulk asset delete, the photo editor, OAuth/OIDC login.
  • Non-web platforms — the mobile app, Fastlane, and their CI workflows are deleted from the repo.

Kept: timeline with virtualized scroll, full-screen photo/video viewer (with ffmpeg transcoding), albums, favorites, tags, memories, global map, metadata search, stacks, multi-user admin, API keys, download/export.

Quick start

  1. Copy docker/example.env to docker/.env and set PHOTOS_LOCATION (the host folder holding your existing photos), UPLOAD_LOCATION (where Postgres data and generated thumbnails live — keep this off the removable photo drive), BACKUP_LOCATION (where database dumps go — on the photo SSD but outside PHOTOS_LOCATION; see Backups), and DB_PASSWORD.

  2. Create the sentinel file once, at the root of your photo volume. Note the source line — PHOTOS_LOCATION lives in docker/.env and is not otherwise set in your shell, so without it you would touch /.immich-lite-library:

    set -a; source docker/.env; set +a
    touch "$PHOTOS_LOCATION/.immich-lite-library"

    Its presence is how both the start script and the server prove the volume is actually mounted. Without it, a scan run against an unplugged drive would mark every asset offline. The matching IMMICH_LITE_LIBRARY_SENTINEL variable in docker/.env is the same path as seen from inside the container (/photos/.immich-lite-library). Leave that variable commented out to disable the guard.

  3. Start the stack for the first time:

    docker compose -f docker/docker-compose.lite.yml --project-directory docker up -d --build
  4. Open http://localhost:2283, complete admin sign-up, then:

    • Create an external library under Administration -> Libraries with an import path of /photos (or a subfolder).
    • Create an API key under Account Settings -> API Keys and put it in docker/.env as IMMICH_LITE_API_KEY. The key must belong to an admin user and must grant library.read, library.update and job.create — the endpoints start.sh calls are declared @Authenticated({ permission: Permission.LibraryRead, admin: true }) and @Authenticated({ permission: Permission.LibraryUpdate, admin: true }) in server/src/controllers/library.controller.ts, and @Authenticated({ permission: Permission.JobCreate, admin: true }) in server/src/controllers/job.controller.ts. An under-scoped key gets a 403, which looks like an invalid key but is not. Missing only job.create degrades gracefully: the scan still runs and just the backup trigger fails.
  5. From then on, start the stack with:

    ./scripts/start.sh

    This preflights the photo drive, brings the stack up, waits for the server to be healthy, and queues a library scan — so photos you added since last time get imported. It refuses to start at all if the drive is not mounted. Scanning is an async background job; watch it under Administration -> Jobs.

    Do not rely on the built-in scheduled jobs (nightly scan, 2AM database backup, 3AM integrity checks) to pick up new photos. Cron jobs are registered in-process at server bootstrap, so they only fire while the stack happens to be running at the scheduled time — which, with restart: always in docker-compose.lite.yml, can include a stack Docker brought back up on its own after a daemon restart. Either way it is not a schedule you can count on: scripts/start.sh is what makes newly added photos appear promptly.

  6. bash scripts/smoke.sh runs an end-to-end curl-based check (admin auth, library create + scan, timeline buckets, thumbnail, video asset) against a running stack. bash scripts/test-start-preflight.sh checks the start script's drive guard without starting containers. scripts/seed-test-media.sh generates throwaway test media into PHOTOS_LOCATION if you don't have real media handy yet.

Backups

The database is the only irreplaceable state here. Photos can be rescanned from disk, but albums, favorites, tags, memories and stacks exist nowhere else.

BACKUP_LOCATION (in docker/.env) puts database dumps on the photo SSD, so they do not share a disk with the Postgres data directory they protect. ./scripts/start.sh checks them on every startup and queues a fresh dump when the newest is older than BACKUP_MAX_AGE_HOURS.

  • bash scripts/verify-backups.sh — integrity and freshness check
  • bash scripts/test-restore.sh — restore the newest dump into a throwaway container and confirm it loads. Run it at least once; an unrestored backup is a file, not a backup.
  • bash scripts/backup-to.sh /Volumes/YourBackupDrive — copy originals and dumps to a second drive. Never deletes at the destination.

Setting this up on an existing install needs a specific migration, because moving the mount without moving its .immich marker stops the server booting. See docs-lite/backup-runbook.md.

Verification story

This fork does not run Immich's original e2e/ suite in full: most of those specs seed their test fixtures by uploading assets over HTTP, and the upload endpoint no longer exists here (ingestion is library-scan only). Specs that depended on that upload seeding path were removed rather than reworked (see the Task 12 report for the exact file list).

What's actually retained and passing:

  • Vitest API/CLI/maintenance specs (e2e/src/specs/server/**) — auth, sessions, API keys, external-library scanning/offline-handling, system config/metadata, user admin, database backups. 166/176 tests pass against a real running server (the other 9 are CLI specs that fail in sandboxes where plain pnpm isn't on PATH, not a suite defect).
  • Playwright ui project (e2e/src/ui/specs) — timeline, asset viewer, and memory-viewer specs that mock the API in-browser rather than depending on real uploaded fixtures. This is real, rendered-browser coverage of exactly the flows that Task 11 could only verify at the API level: 50/67 tests pass (login/timeline render, deep-linking, scrubber scrolling, keyboard navigation in most cases, favorite toggle, album add, archive/unarchive/favorite-an-archived-photo). The remaining 13 are either resource-contention flakiness under parallel workers (asset prev/next-button navigation intermittently times out, passes when re-run serially) or reproducible failures in still-kept features — keyboard month/year/"go to time" navigation, day-range selection, and 5 of 10 "deep link to random asset" iterations consistently fail against the current stripped web build. These weren't previously verified in a real browser and are a genuine, concrete follow-up (not something this task's scope covers fixing). (Note: the dedicated /archive page was intentionally removed along with trash/delete, per docs-lite/spec.md — the archive/unarchive action itself is still live and is what these specs exercise directly on a thumbnail, not the removed page.) A follow-up investigation tried to determine whether these 13 are a real strip regression or an artifact of this project's mocked-network ui Playwright specs, by looking for equivalent coverage in the real-backend web Playwright project — none exists (a pre-existing gap in upstream Immich's own e2e suite, not something the strip introduced). Resolving this conclusively requires a manual click-through against the running stack at http://localhost:2283, which no automated tool in this project's toolchain can currently perform.

scripts/smoke.sh plus manual/API verification against the running stack remains the project's primary day-to-day verification story, alongside whichever e2e subset stays green above.

Attribution

Immich Lite is a fork of immich-app/immich, licensed AGPL-3.0. All credit for the original design, the timeline/scan/thumbnail pipeline, and the vast majority of the code goes to the upstream Immich project and its contributors. This fork keeps the upstream LICENSE (AGPL-3.0) and is not affiliated with or endorsed by the Immich project.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages