From 936b96a36e28dce8056985358dc85df033537286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 10 Aug 2026 13:08:49 +0000 Subject: [PATCH] app store: uninstall removes containers and never data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is now no uninstall option that deletes data, rather than a careful one that does. A user uninstalling a sidecar is saying "stop running this", which is not the same sentence as "delete my photo library", and for Immich or Jellyfin getting that wrong once is unrecoverable. No confirmation dialog makes it a good default. So: `docker compose down` without `-v`. Containers and networks go; the service directory and everything under it stays exactly as it was. The bind-mount convention already makes this hard to get wrong, which is worth noting because it means the safety is structural rather than a rule someone has to keep following. Data lives on the host inside the service directory, so `-v` — which only removes NAMED volumes — could not delete it even if a future change added the flag back. `mode: 'existing'` has no disposal question at all: we did not create that service, so uninstall removes our sidecar and our rows and touches nothing else. Reclaiming disk becomes its own feature later, with the sizes in front of the user — "Photos is using 340 GB, delete it?" — as a deliberate act rather than a checkbox inside an uninstall flow. Removed two stale `down -v` references that survived the first pass, one in the schema comment and one in the design doc's table. Leftovers like those are how a rule becomes permission again. Co-Authored-By: Claude Opus 5 --- docs/sidecar-app-store.md | 9 ++++----- src/databases/officer_db/src/schema/app-store.ts | 9 ++++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/sidecar-app-store.md b/docs/sidecar-app-store.md index 3a98cdec..bb45a288 100644 --- a/docs/sidecar-app-store.md +++ b/docs/sidecar-app-store.md @@ -142,11 +142,10 @@ Two independent flags, because they answer different questions: That yields the three outcomes asked for: -| Action | Effect | -| ------------------------ | ------------------------------------------------------------------------------------ | -| **Disable** | Stop the sidecar. Container, config, schema and data all stay. Re-enable is instant. | -| **Uninstall, keep data** | Stop, remove the process. Leave container volumes and rows. | -| **Full uninstall** | Also `docker compose down -v` and drop the sidecar's tables. | +| Action | Effect | +| ------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| **Disable** | Stop the sidecar. Container, config, schema and data all stay. Re-enable is instant. | +| **Uninstall** | Stop the sidecar, `docker compose down` — containers and networks removed. **The service directory and everything in it stays.** | The middle one is the in-between; the user chooses disposal at uninstall time rather than us guessing. diff --git a/src/databases/officer_db/src/schema/app-store.ts b/src/databases/officer_db/src/schema/app-store.ts index 7f802909..f00c46cb 100644 --- a/src/databases/officer_db/src/schema/app-store.ts +++ b/src/databases/officer_db/src/schema/app-store.ts @@ -23,8 +23,11 @@ import { pgTable, serial, text, boolean, timestamp, jsonb, uniqueIndex } from 'd // SHOULD BE RUNNING. Disabling is the reversible middle ground the owner asked for — stop the process, // keep the container, the config, the tables and the data, and start again later at no cost. // -// Uninstall then has a disposal choice rather than a fixed meaning: keep the data, drop the container, -// or drop both. None of those are this table's business beyond recording that the row is gone. +// Uninstall stops the sidecar and removes the containers. It does NOT remove data, and there is no +// option that does: the service directory and everything under it survives. A user uninstalling a +// sidecar is saying "stop running this", not "delete my photo library", and the two are unrecoverably +// different for Immich and Jellyfin. Reclaiming disk is a separate, deliberate feature with the sizes +// shown — not a checkbox in an uninstall flow. export const sidecarInstalls = pgTable( 'sidecar_installs', { @@ -67,7 +70,7 @@ export const sidecarInstalls = pgTable( * Absolute path to the rendered compose directory, for `mode: 'provisioned'` only. * * Stored rather than derived because it is the user's directory and he may move it — and because - * uninstall must not guess at a path it is about to run `docker compose down -v` in. + * uninstall must not guess at a path it is about to run `docker compose down` in. */ composeDir: text('compose_dir'), installedAt: timestamp('installed_at', { withTimezone: true }),