Immich (photos)
Immich reads library/pictures, makes thumbnails and previews (from HEIC and
raw too), recognises faces and places, and searches by what is in a picture. SoundStorm provisions it
with nobody logging in, gives every member an Immich account that sees only their own folder, and never
lets Immich touch a photo file.
Why Immich
Photos fail the rule for what SoundStorm owns: iPhones save HEIC, which Go's standard library cannot decode, clips need transcoding, and a photo library is a scanning job. Immich was chosen over lighter options such as Photoview (closer to "the folder is the interface") for search by what is in a picture - the feature people compare against Google Photos - at the price of four containers (server, machine learning, Postgres with vector search, Valkey), about 5 GB of images and 6-8 GB of RAM.
Pinned to a major version
Researched, not assumed: Immich 2.0 (October 2025) promised semver, and 3.0 (July 2026) then broke API
endpoints "that affect only third-party tools" - which is what SoundStorm is. So every Immich image is
pinned to its major version, v3, never latest, and moving to v4 is a deliberate
change with an adapter update behind it.
Provisioning
Every step was checked against a live 3.2.2:
/api/auth/admin-sign-upwithsoundstorm@soundstorm.invalid- RFC 2606's never-existing domain. Immich validates the address's shape and sends nothing to it.- Log in, then create an API key with
permissions: ["all"]. The session token expires and the key does not, so the key is kept and the password is not. - Create an external library on
/pictures, mounted read-only. Immich's docs describe creating one only through its admin screens; the endpoint behind them is in the API. - Switch folder watching on by reading
/api/system-config, changinglibrary.watch.enabled, and sending the whole document back - a test holds that this changes nothing else.
pictures/ however it arrived, and Immich can never move, rename or delete one. Its
thumbnails and previews live in a named volume, regenerable from the photos. Its database must be a
named volume too: Immich's Postgres must not sit on a network share or an NTFS drive, and a named volume
lives on Docker's own Linux disk on every host.An account per member
Each member gets an Immich account (/api/admin/users, made the first time they look)
whose one external library reads only pictures/Personal/<name>/. The owner keeps the
administrator's account, whose library is the whole folder. The adapter acts as the person asking
(immich.Config.ActAs): every request carries their own key - never a fallback to the
administrator's. Filtering one shared account was rejected because Immich groups faces across every photo
it can see; separate accounts keep People, Places and search to each person's own photos. Verified first:
overlapping libraries are allowed, and a member asking for another's photo by id gets a 400. Removing a
member deletes their account with force and keeps their folder. See
Photos.
The calls SoundStorm makes
| Call | Used for |
|---|---|
/api/search/metadata | Browsing newest first, filename search, a person's or town's photos, On this day (one search per earlier year) |
/api/search/smart | Search by what is in a picture |
/api/assets/{id}/thumbnail | Thumbnails (WebP) and previews (JPEG, art id <id>@preview) |
/api/assets/{id}/original | The original, as a download |
/api/assets/{id}/video/playback | Clips; honors Range, so seeking works through the proxy |
/api/people, PUT /api/people/{id} | People, faces, naming someone found but unnamed |
/api/search/cities | Places |
POST /api/libraries/{id}/scan | "Look now" - every library, members' included |
Quirks
- Paths are as Immich's container sees them (
/pictures/...), so the adapter trims its media root withsource.RelativeTo, which refuses anything outside it. An asset uploaded to Immich's own storage can therefore never be named for deletion. - Smart search needs models Immich downloads on first use. On a fresh install the first searches timed out while it did, so the adapter falls back to a filename search.
- Order is Immich's, deliberately. Photos are not browsed alphabetically, so each item's
SortKeyis its rank in Immich's newest-first order, behind a~so photos follow titled media in a browse of everything - and merged paging still holds, because the key is the source's order. - Memories are not used. Immich makes them overnight and only for days it picked (empty on a real library), so On this day is SoundStorm's own.
- Dates and places from imports are written as XMP sidecars beside the photo, which Immich reads; checked with a Takeout photo whose sidecar put it in the right city and year.
Uploads appear about four seconds after landing, through folder watching plus SoundStorm's rescan. Immich's Postgres uses a fixed default password reachable only on the compose network; generating one would require telling a fresh install from an existing database, whose password cannot change under it. That is recorded as a decision left open.