app store: check the host before writing anything

An install that discovers a missing dependency halfway through has already made a directory, possibly
started a container and written a row, and then has to unwind — leaving the user with something that
neither works nor uninstalls. A 30ms check first is worth most of that.

Verified while writing this: nothing in scripts/ installs Docker, and nothing checks for it.
setup-dockers.sh invokes `docker compose` with no preflight, so a fresh host without Docker fails
partway through setup with a bare "command not found". Recorded in the design doc rather than fixed
here — the intended fix is a setup.sh per sidecar, which is also what a sidecar needs once it ships from
its own repository.

`docker compose version` is the probe, not `docker --version`: the latter passes with a dead daemon,
which is the failure people actually hit. "Not installed" and "daemon unreachable" are reported
separately because the remedies differ.

Checked per MODE, not per entry. A host without Docker can still install Photos by pointing at an Immich
somewhere else; refusing the whole entry is the over-strict check that makes people work around the
installer instead of using it.

Dropped `requires: 'docker'` from the catalogue type. Needing Docker is exactly "this entry can
provision", which `modes` already says, so declaring it twice invites the two to disagree. Derived by
needsDocker instead, and a test asserts the derivation matches every entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 13:44:30 +00:00
co-authored by Claude Opus 5
parent 654cb10711
commit 7359867f7f
4 changed files with 161 additions and 9 deletions
+26
View File
@@ -105,6 +105,32 @@ consequences, both wanted:
`[open]` Podman, for anyone wanting genuinely rootless.
### Docker is assumed, and nothing guarantees it
Verified: **nothing in `scripts/` installs Docker, and nothing checks for it.** `setup.sh` calls
`setup-dockers.sh`, which invokes `docker compose` with no preflight, so a fresh host without Docker
fails partway through setup with a bare "command not found".
That is the seam where this project's origin shows — it began as one person's own machine, provisioned
by his own scripts, where Docker was simply always there.
The intended fix is **a `setup.sh` per sidecar**, ensuring its own dependencies before its compose file
is used. That is also the shape a sidecar needs once it lives in its own repository, so a sidecar package
becomes:
```
metadata (catalogue entry) · compose template · setup.sh · schema
```
Until that exists, the app store **detects and reports** rather than guessing or half-installing:
`preflight.ts` checks `docker compose version` — which exercises the binary, the daemon connection and
the plugin in one call, unlike `docker --version`, which passes with a dead daemon — and distinguishes
"not installed" from "daemon unreachable", because the remedies differ.
The check is **per mode, not per entry**: a host without Docker can still install Photos by pointing at
an Immich elsewhere. Refusing the whole entry would be the over-strict check that makes people work
around the installer instead of using it.
---
## Install state