docs: close the environment contract and de-ambiguate volume derivation (#26)

Review findings on the previous commit:

- README's config table listed 8 of the backend's 25 environment variables,
  omitting the whole DISCORD_* set that the backend refuses to start without.
  The canonical reference cannot be missing the vars that gate startup.
- `docker volume ls --filter name=` is a substring match. Both runbooks used
  it to find a volume they then mount read-only or delete; a second matching
  volume makes the mount fail obscurely and the delete take both. Derive the
  name exactly from the compose project instead.
- CUTOVER §6 removes the retired volume 'once the Postgres data has been
  trusted for a while', in a shell where §1's $VOL no longer exists.
- REDEPLOY and DEPLOY still pointed at /opt/bookmarkmanager, so CUTOVER §6's
  handoff to REDEPLOY §1 sent the operator to a path that does not exist.
This commit is contained in:
2026-08-08 15:50:59 +07:00
parent 01de8903b4
commit 77965c3d76
4 changed files with 53 additions and 25 deletions
+14 -9
View File
@@ -32,10 +32,10 @@ is dropped) — writing it from the spec below costs less than maintaining it
would.
Beyond `DEPLOY.md`'s prerequisites (Docker and Compose), this runbook needs
`python3` — its stdlib `sqlite3` module is the whole SQLite dependency, and it
stands in for `jq` in §5, which is not installed on the server. It does not have
to run on the server: §3 only reads the snapshot copy, so it can run on a laptop
and the resulting `import.sql` be copied over.
`python3`: its stdlib `sqlite3` module is the whole SQLite dependency, and §5's
read-path check uses it in place of `jq`, which the server does not have. It
does not have to run on the server — §3 only reads the snapshot copy, so it can
run on a laptop and the resulting `import.sql` be copied over.
---
@@ -51,9 +51,12 @@ BACKUP_DIR="$(cd .. && pwd)/$(basename "$PWD")-backups"; mkdir -p "$BACKUP_DIR"
STAMP=$(date -u +%Y%m%d-%H%M%S)
# The volume is <compose project>_bookmarks-data, and the project name defaults
# to the lowercased *directory* name, not the repo name — here that makes it
# mangabookmark_bookmarks-data. Ask Docker instead of typing it out.
VOL=$(docker volume ls -q --filter name=_bookmarks-data); echo "$VOL"
# to the lowercased *directory* name, not the repo name — on this host the
# checkout is ~/mangaBookmark, so the volume is mangabookmark_bookmarks-data.
# Derive it exactly rather than with a `--filter name=` substring match, which
# would return every volume whose name merely contains the string.
VOL="$(basename "$PWD" | tr '[:upper:]' '[:lower:]')_bookmarks-data"
docker volume inspect "$VOL" >/dev/null && echo "$VOL"
$COMPOSE stop bookmark-api
@@ -279,8 +282,10 @@ curl -s -H "Authorization: Bearer $TOKEN" $API/bookmarks |
- **Keep the old SQLite volume for a month.** It is already undeclared in
compose, so `docker compose down -v` cannot take it. Remove it by hand once
the Postgres data has been trusted for a while:
`docker volume rm "$VOL"` (see `REDEPLOY.md` §1).
the Postgres data has been trusted for a while. That happens in a shell where
`$VOL` from §1 is long gone, so re-derive it:
`docker volume rm "$(basename ~/mangaBookmark | tr '[:upper:]' '[:lower:]')_bookmarks-data"`
(see `REDEPLOY.md` §1).
- **Delete the generator and the working copies:** `rm -rf /tmp/cutover`. The
timestamped export in `$BACKUP_DIR` is the copy that is kept.
- **Take the first Postgres dump immediately** — `REDEPLOY.md` §1. Until that