`) sets
+ it from the deploy field, and the walk holds the value it generated. The bench runs no `after_install`, so
+ when the generated password does not log in, the fixture runs THE SAME command the product runs — the
+ app's own CLI inside its own container — and says so.
+
+ READBACK: the app's OPDS feed (HTTP Basic, the route e-readers use): the search must list the title, and the
+ book's own download must be the uploaded book (the marker read out of the EPUB the app serves). Negative
+ controls on every call: a wrong password must answer 401, and a title that cannot exist must not be found."""
+ sub = "books"
+
+ @staticmethod
+ def _epub(marker):
+ import io, zipfile
+ buf = io.BytesIO()
+ z = zipfile.ZipFile(buf, "w")
+ z.writestr(zipfile.ZipInfo("mimetype"), "application/epub+zip")
+ z.writestr("META-INF/container.xml",
+ ''
+ ''
+ '')
+ z.writestr("OEBPS/content.opf",
+ '{marker}'
+ 'Drill Authoren'
+ f'urn:uuid:{marker}'
+ ' '
+ ' '
+ '')
+ z.writestr("OEBPS/toc.ncx",
+ ''
+ f'{marker}'
+ 'One'
+ '')
+ z.writestr("OEBPS/c1.xhtml",
+ ''
+ f'{marker}{marker}-body the household keeps this.
')
+ z.close()
+ return buf.getvalue()
+
+ @staticmethod
+ def _name(w): # SWEEP COPY 2026-10-24: after_install renames `admin` to the generated ADMIN_USER (decision 45)
+ g = w.GENERATED.setdefault("calibre-web", {})
+ if not g.get("ADMIN_USER"):
+ # the BOX generates it (an optional secret): read it the way the household does — the app page's
+ # reveal button, POST /stacks/calibre-web/auto-field/reveal (R-254). Never printed.
+ import json as _json
+ sess = open(f"{w.SC}/sess{os.getpid()}.txt").read().strip()
+ csrf = open(f"{w.SC}/csrf{os.getpid()}.txt").read().strip()
+ r = w.sh(["curl", "-sk", "-H", w.HOSTHDR, "-H", f"Cookie: {sess}", "-H", f"X-CSRF-Token: {csrf}",
+ "--data-urlencode", "env_var=ADMIN_USER", "--data-urlencode", f"_csrf={csrf}",
+ f"{w.BASE}/stacks/calibre-web/auto-field/reveal"])
+ try:
+ d = _json.loads(r.stdout or "{}")
+ g["ADMIN_USER"] = (d.get("data") or d).get("value") or ""
+ except Exception:
+ g["ADMIN_USER"] = ""
+ return g.get("ADMIN_USER") or "admin"
+
+ def _opds(self, w, sub, pw, path):
+ return w.app_curl(sub, path, "-u", f"{self._name(w)}:{pw}")
+
+ def seed(self, w, sub, say):
+ import os, tempfile
+ if not w.wait_app(sub, "/login", want=("200",), tries=72):
+ return None
+ pw = (w.GENERATED.get("calibre-web") or {}).get("ADMIN_PASSWORD") or ""
+ rc, code, _ = self._opds(w, sub, pw, "/opds")
+ if code != "200":
+ say(f" calibre-web: the generated admin password does not log in (opds http={code}) — running the "
+ "template's own after_install command (the app's CLI, as the product does after an install)")
+ import shlex # as the template's after_install: `user: abc` (docker exec -u keeps the image's PATH; `su` does not)
+ out = w.guest("docker exec -u abc calibre-web python3 /app/calibre-web-automated/cps.py -p /config/app.db -s "
+ + shlex.quote(f"{self._name(w)}:{pw}") + " 2>&1")
+ say(f" calibre-web: after_install :: {' '.join(out.split())[-80:]}")
+ rc, code, _ = self._opds(w, sub, pw, "/opds")
+ if code != "200":
+ self.tried = f"admin login after after_install -> {code}"
+ return None
+ jar = tempfile.mktemp(prefix="cw-jar-")
+ try:
+ rc, code, page = w.app_curl(sub, "/login", "-c", jar, "-b", jar)
+ m = re.search(r'name="csrf_token" value="([^"]+)"', page or "")
+ if not m:
+ self.tried = f"GET /login -> {code}, no csrf_token"
+ return None
+ rc, code, _ = w.app_curl(sub, "/login", "-c", jar, "-b", jar, "--data-urlencode", f"csrf_token={m.group(1)}",
+ "--data-urlencode", f"username={self._name(w)}", "--data-urlencode", f"password={pw}",
+ "--data-urlencode", "remember_me=on", method="POST")
+ rc, code, home = w.app_curl(sub, "/", "-c", jar, "-b", jar)
+ m = re.search(r'name="csrf_token" value="([^"]+)"', home or "")
+ has_form = 'action="/upload"' in (home or "")
+ if code != "200" or not has_form or not m:
+ self.tried = f"login -> home {code}, upload form present={has_form}"
+ say(f" calibre-web: {self.tried}")
+ return None
+ marker = "upg" + secrets.token_hex(6)
+ book = tempfile.mktemp(prefix="cw-", suffix=".epub")
+ open(book, "wb").write(self._epub(marker))
+ rc, code, out = w.app_curl(sub, "/upload", "-c", jar, "-b", jar, "-H", f"X-CSRFToken: {m.group(1)}",
+ "-F", f"csrf_token={m.group(1)}",
+ "-F", f"btn-upload=@{book};type=application/epub+zip", method="POST")
+ os.unlink(book)
+ say(f" calibre-web: POST /upload http={code} {out[:80]}")
+ if code != "200":
+ self.tried = f"POST /upload -> {code} {out[:120]}"
+ return None
+ finally:
+ if os.path.exists(jar):
+ os.unlink(jar)
+ t = {"pw": pw, "marker": marker}
+ for _ in range(24): # the upload is a task; the library entry follows within seconds
+ rc, code, feed = self._opds(w, sub, pw, f"/opds/search/{marker}")
+ if marker in (feed or ""):
+ say(f" calibre-web: seeded book {marker} is in the library")
+ return t
+ time.sleep(5)
+ self.tried = "uploaded, but the book never appeared in the OPDS search"
+ return None
+
+ def verify(self, w, sub, t, say):
+ import io, os, tempfile, zipfile
+ if not w.wait_app(sub, "/login", want=("200",), tries=72):
+ say(" calibre-web: the app never served /login")
+ return False
+ rc, code, _ = self._opds(w, sub, "wrong-" + secrets.token_hex(6), "/opds")
+ if code != "401":
+ say(f" calibre-web: READBACK UNUSABLE — a wrong password answered {code}")
+ return False
+ ghost = "upg" + secrets.token_hex(6)
+ rc, code, feed = self._opds(w, sub, t["pw"], f"/opds/search/{ghost}")
+ if code != "200" or "" in (feed or ""):
+ say(f" calibre-web: READBACK UNUSABLE — a title that cannot exist: http={code}, entries={(feed or '').count('')}")
+ return False
+ feed = ""
+ for _ in range(12):
+ rc, code, feed = self._opds(w, sub, t["pw"], f"/opds/search/{t['marker']}")
+ if code == "200" and f"{t['marker']}" in (feed or ""):
+ break
+ time.sleep(5)
+ listed = f"{t['marker']}" in (feed or "")
+ m = re.search(r'href="(/opds/download/\d+/epub/?)"', feed or "")
+ served = False
+ if listed and m:
+ f = tempfile.mktemp(prefix="cw-dl-")
+ rc, code, _ = w.app_curl(sub, m.group(1), "-u", f"admin:{t['pw']}", "-o", f)
+ try:
+ z = zipfile.ZipFile(io.BytesIO(open(f, "rb").read()))
+ served = any(f"{t['marker']}-body" in z.read(n).decode("utf-8", "replace") for n in z.namelist())
+ except Exception as e:
+ say(f" calibre-web: the download is not a readable EPUB (http={code}): {e}")
+ finally:
+ if os.path.exists(f):
+ os.unlink(f)
+ say(f" calibre-web: readback — listed={listed} download_link={bool(m)} book_content_served={served}")
+ return listed and served
+
+
+# =============================================================================================
+class Wger:
+ """wger (2026-09-30, R-462). THE FRONT DOOR is the web login form (`/en/user/login`, Django CSRF), then the
+ app's own REST API with that session: `POST /api/v2/weightentry/` (a weight on a date — household data in its
+ SQLite), read back with `GET /api/v2/weightentry/?weight=`. Measured on the bench 2026-09-30 (2.6).
+ NOT the app-API login (`/allauth/app/v1/auth/login`): it answers 500 on a CORRECT password on this template
+ (no JWT_PRIVATE_KEY — filed, R-737). THE ADMIN PASSWORD: as calibre-web — the box's `after_install` sets it;
+ the bench runs the template's own command (password as the last argument) when the generated one does not
+ log in. Negative controls on every readback: no session answers 403, a weight never entered counts 0."""
+ sub = "fitness"
+ SET_PW = ("import os, sys; sys.path.insert(0, '/home/wger/src'); os.chdir('/home/wger/src'); "
+ "os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.main'); import django; django.setup(); "
+ "from django.contrib.auth.models import User; u = User.objects.get(username='admin'); "
+ "u.set_password(sys.argv[1]); u.save(); print('FELHOM_AFTER_INSTALL_OK')")
+
+ @staticmethod
+ def _host(w, sub):
+ return w.host(sub) if hasattr(w, "host") else f"{sub}.{w.DOMAIN}"
+
+ def _login(self, w, sub, pw, jar):
+ o = f"https://{self._host(w, sub)}"
+ hdr = ["-H", f"Origin: {o}", "-H", f"Referer: {o}/en/user/login", "-c", jar, "-b", jar]
+ rc, code, page = w.app_curl(sub, "/en/user/login", *hdr)
+ m = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', page or "")
+ if not m:
+ return None, f"GET /en/user/login -> {code}, no csrf"
+ rc, code, _ = w.app_curl(sub, "/en/user/login", *hdr, "--data-urlencode", f"csrfmiddlewaretoken={m.group(1)}",
+ "--data-urlencode", "login=admin", "--data-urlencode", f"password={pw}", method="POST")
+ jt = open(jar).read() if os.path.exists(jar) else ""
+ if code != "302" or "sessionid" not in jt:
+ return None, f"POST /en/user/login -> {code}"
+ csrf = re.search(r"csrftoken\s+(\S+)", jt)
+ return hdr + ["-H", f"X-CSRFToken: {csrf.group(1) if csrf else ''}"], "ok"
+
+ def seed(self, w, sub, say):
+ import shlex, tempfile
+ if not w.wait_app(sub, "/en/user/login", want=("200",), tries=72):
+ return None
+ pw = (w.GENERATED.get("wger") or {}).get("ADMIN_PASSWORD") or ""
+ jar = tempfile.mktemp(prefix="wger-jar-")
+ try:
+ hdr, why = self._login(w, sub, pw, jar)
+ if hdr is None:
+ say(f" wger: the generated admin password does not log in ({why}) — running the template's own "
+ "after_install command (the app's CLI, as the product does after an install)")
+ out = w.guest("docker exec wger python3 -c " + shlex.quote(self.SET_PW) + " " + shlex.quote(pw) + " 2>&1")
+ say(f" wger: after_install :: {' '.join(out.split())[-60:]}")
+ hdr, why = self._login(w, sub, pw, jar)
+ if hdr is None:
+ self.tried = f"web login after after_install: {why}"
+ return None
+ weight = "%d.%02d" % (60 + secrets.randbelow(60), secrets.randbelow(100))
+ rc, code, out = w.app_curl(sub, "/api/v2/weightentry/", *hdr, "-H", "Content-Type: application/json",
+ data=json.dumps({"date": "2026-09-30T10:00:00Z", "weight": weight}), method="POST")
+ say(f" wger: POST /api/v2/weightentry/ http={code}")
+ if code != "201":
+ self.tried = f"POST /api/v2/weightentry/ -> {code} {out[:120]}"
+ return None
+ return {"pw": pw, "weight": weight}
+ finally:
+ if os.path.exists(jar):
+ os.unlink(jar)
+
+ def verify(self, w, sub, t, say):
+ import tempfile
+ if not w.wait_app(sub, "/en/user/login", want=("200",), tries=72):
+ say(" wger: the app never served /en/user/login")
+ return False
+ rc, code, _ = w.app_curl(sub, f"/api/v2/weightentry/?weight={t['weight']}")
+ if code not in ("401", "403"):
+ say(f" wger: READBACK UNUSABLE — no session answered {code}")
+ return False
+ jar = tempfile.mktemp(prefix="wger-jar-")
+ try:
+ hdr, why = self._login(w, sub, t["pw"], jar)
+ if hdr is None:
+ say(f" wger: login failed: {why}")
+ return False
+ rc, code, out = w.app_curl(sub, "/api/v2/weightentry/?weight=199.99", *hdr)
+ if code != "200" or '"count":0' not in (out or "").replace(" ", ""):
+ say(f" wger: READBACK UNUSABLE — a weight never entered: http={code} {out[:80]}")
+ return False
+ rc, code, out = w.app_curl(sub, f"/api/v2/weightentry/?weight={t['weight']}", *hdr)
+ ok = code == "200" and f'"weight":"{t["weight"]}"' in (out or "").replace(" ", "")
+ say(f" wger: readback of the seeded weight entry http={code} found={ok}")
+ return ok
+ finally:
+ if os.path.exists(jar):
+ os.unlink(jar)
+
+
+# =============================================================================================
+class Crafty:
+ """Crafty Controller 4 (2026-09-30, R-462). Its own REST API v2, behind its own HTTPS port (the template tells
+ traefik `scheme=https`; the bench adapter reads that label): `POST /api/v2/auth/login` as `admin` with the
+ deploy's CRAFTY_PASSWORD (the compose entrypoint writes it into default.json), then `POST /api/v2/roles` — a
+ role is a record in crafty's own database, created the way its panel creates one — read back with
+ `GET /api/v2/roles`. Measured on the bench 2026-09-30 (4.10.7): the POST needs `mfa_required` (500 without).
+ Negative control on every readback: a wrong token must answer 401/403."""
+ sub = "minecraft"
+
+ def _token(self, w, sub, pw):
+ rc, code, out = w.app_curl(sub, "/api/v2/auth/login", "-H", "Content-Type: application/json",
+ data=json.dumps({"username": "admin", "password": pw}), method="POST")
+ try:
+ return json.loads(out)["data"]["token"], code
+ except Exception:
+ return None, f"{code} {(out or '')[:120]}"
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/", want=("200", "302"), tries=90):
+ return None
+ pw = (w.GENERATED.get("crafty-controller") or {}).get("CRAFTY_PASSWORD") or ""
+ tok, why = None, None
+ for _ in range(12): # crafty answers `/` before its API accepts the seeded admin
+ tok, why = self._token(w, sub, pw)
+ if tok:
+ break
+ time.sleep(5)
+ if not tok:
+ self.tried = f"POST /api/v2/auth/login -> {why}"
+ return None
+ role = "upg" + secrets.token_hex(5)
+ rc, code, out = w.app_curl(sub, "/api/v2/roles", "-H", f"Authorization: Bearer {tok}",
+ "-H", "Content-Type: application/json",
+ data=json.dumps({"name": role, "servers": [], "mfa_required": False}), method="POST")
+ say(f" crafty: POST /api/v2/roles http={code} {out[:60]}")
+ if code != "200" or '"ok"' not in (out or ""):
+ self.tried = f"POST /api/v2/roles -> {code} {out[:120]}"
+ return None
+ return {"pw": pw, "role": role}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/", want=("200", "302"), tries=90):
+ say(" crafty: the app never answered /")
+ return False
+ tok = None
+ for _ in range(12):
+ tok, why = self._token(w, sub, t["pw"])
+ if tok:
+ break
+ time.sleep(5)
+ if not tok:
+ say(f" crafty: login failed: {why}")
+ return False
+ rc, code, _ = w.app_curl(sub, "/api/v2/roles", "-H", f"Authorization: Bearer x{tok}")
+ if code not in ("401", "403"):
+ say(f" crafty: READBACK UNUSABLE — a wrong token answered {code}")
+ return False
+ rc, code, out = w.app_curl(sub, "/api/v2/roles", "-H", f"Authorization: Bearer {tok}")
+ names = [r.get("role_name") for r in (json.loads(out).get("data") or [])] if code == "200" else []
+ ok = t["role"] in names
+ say(f" crafty: readback of the seeded role http={code} found={ok} (roles listed: {len(names)})")
+ return ok
+
+
+# =============================================================================================
+class UptimeKuma:
+ """Uptime Kuma 2 (2026-09-30, R-462). Its web page talks to the server over socket.io, and its first-run setup,
+ login and every edit exist ONLY there — so the fixture speaks socket.io's plain HTTP long-polling transport
+ (Engine.IO v4: `GET/POST /socket.io/?EIO=4&transport=polling`) through the app's own front door, exactly the
+ messages the page sends: `setup` (the first admin), `login`, `addStatusPage` (a status page is a record in its
+ own SQLite). READBACK through its public REST route `GET /api/status-page/` (the page households share),
+ which must carry the seeded title; negative control: a slug never made must not answer 200 with a title."""
+ sub = "status"
+ RS = "\x1e"
+
+ class _IO:
+ def __init__(self, w, sub):
+ self.w, self.sub, self.sid, self.buf, self.ack = w, sub, None, [], 0
+
+ def _get(self):
+ rc, code, out = self.w.app_curl(self.sub, f"/socket.io/?EIO=4&transport=polling&sid={self.sid}", timeout=30)
+ if code != "200":
+ raise RuntimeError(f"poll http={code} {out[:80]}")
+ for p in (out or "").split(UptimeKuma.RS):
+ if p == "2": # ping → pong
+ self._post("3")
+ elif p:
+ self.buf.append(p)
+
+ def _post(self, body):
+ rc, code, out = self.w.app_curl(self.sub, f"/socket.io/?EIO=4&transport=polling&sid={self.sid}",
+ "-H", "Content-Type: text/plain;charset=UTF-8", data=body, method="POST")
+ if code != "200":
+ raise RuntimeError(f"post http={code} {out[:80]}")
+
+ def open(self):
+ rc, code, out = self.w.app_curl(self.sub, "/socket.io/?EIO=4&transport=polling")
+ m = re.search(r'"sid":"([^"]+)"', out or "")
+ if code != "200" or not m:
+ raise RuntimeError(f"handshake http={code} {out[:80]}")
+ self.sid = m.group(1)
+ self._post("40")
+ for _ in range(10):
+ self._get()
+ if any(p.startswith("40") for p in self.buf):
+ return self
+ raise RuntimeError("no socket.io connect")
+
+ def call(self, event, *args):
+ n = self.ack
+ self.ack += 1
+ self._post(f"42{n}" + json.dumps([event, *args]))
+ for _ in range(30):
+ for p in list(self.buf):
+ if p.startswith(f"43{n}["):
+ self.buf.remove(p)
+ return json.loads(p[len(f"43{n}"):])[0]
+ self._get()
+ raise RuntimeError(f"no answer to {event}")
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/", want=("200", "302"), tries=90):
+ return None
+ user, pw = "drill" + secrets.token_hex(3), "Drill-" + secrets.token_hex(10) + "A1"
+ try:
+ io = self._IO(w, sub).open()
+ r = io.call("setup", user, pw)
+ say(f" uptime-kuma: setup ok={r.get('ok')} {str(r.get('msg'))[:60]}")
+ if not r.get("ok"):
+ self.tried = f"socket.io setup -> {r}"
+ return None
+ io = self._IO(w, sub).open()
+ r = io.call("login", {"username": user, "password": pw, "token": ""})
+ if not r.get("ok"):
+ self.tried = f"socket.io login -> {str(r)[:120]}"
+ return None
+ title, slug = "Drill " + secrets.token_hex(4), "upg" + secrets.token_hex(4)
+ r = io.call("addStatusPage", title, slug)
+ say(f" uptime-kuma: addStatusPage ok={r.get('ok')} {str(r.get('msg'))[:60]}")
+ if not r.get("ok"):
+ self.tried = f"socket.io addStatusPage -> {str(r)[:120]}"
+ return None
+ except Exception as e:
+ self.tried = f"socket.io: {e}"
+ say(f" uptime-kuma: {self.tried}")
+ return None
+ return {"user": user, "pw": pw, "title": title, "slug": slug}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/", want=("200", "302"), tries=90):
+ say(" uptime-kuma: the app never answered /")
+ return False
+ rc, code, out = w.app_curl(sub, f"/api/status-page/upgnever{secrets.token_hex(4)}")
+ if code == "200" and '"title"' in (out or ""):
+ say(f" uptime-kuma: READBACK UNUSABLE — a slug never made answered {code} with a title")
+ return False
+ found = False
+ for _ in range(12):
+ rc, code, out = w.app_curl(sub, f"/api/status-page/{t['slug']}")
+ try:
+ found = code == "200" and json.loads(out)["config"]["title"] == t["title"]
+ except Exception:
+ found = False
+ if found:
+ break
+ time.sleep(5)
+ say(f" uptime-kuma: readback of the seeded status page http={code} found={found}")
+ return found
+
+
+# =============================================================================================
+class Radicale:
+ """Radicale (2026-10-01, new app through NEW-APP-CHECKLIST.md). THE FRONT DOOR is CalDAV itself, the route every
+ phone and desktop calendar uses: HTTP basic auth with the box's generated login (`RADICALE_USER`, default
+ "csalad"; `RADICALE_PASSWORD`). Seed: MKCALENDAR a calendar, PUT one event (a unique UID and SUMMARY); read back
+ with GET. Negative controls on every readback: no credentials 401, a wrong password 401, an event never created
+ 404 — so a read that says "found" cannot be an open door or a catch-all."""
+ sub = "calendar"
+
+ @staticmethod
+ def _creds(w):
+ g = w.GENERATED.get("radicale") or {}
+ return g.get("RADICALE_USER") or "csalad", g.get("RADICALE_PASSWORD") or ""
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/.web/", want=("200",), tries=60):
+ self.tried = "/.web/ never answered 200"
+ return None
+ user, pw = self._creds(w)
+ cal = "felhom-" + secrets.token_hex(4)
+ uid = "ev-" + secrets.token_hex(6) + "@felhom"
+ summary = "Felhom teszt " + secrets.token_hex(3)
+ rc, code, _ = w.app_curl(sub, f"/{user}/{cal}/", "-u", f"{user}:{pw}", method="MKCALENDAR")
+ say(f" radicale: MKCALENDAR /{user}/{cal}/ http={code}")
+ if code != "201":
+ self.tried = f"MKCALENDAR -> {code}"
+ return None
+ ics = ("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//felhom//fixture//EN\r\nBEGIN:VEVENT\r\n"
+ f"UID:{uid}\r\nDTSTAMP:20261001T100000Z\r\nDTSTART:20261002T100000Z\r\nSUMMARY:{summary}\r\n"
+ "END:VEVENT\r\nEND:VCALENDAR\r\n")
+ rc, code, _ = w.app_curl(sub, f"/{user}/{cal}/{uid}.ics", "-u", f"{user}:{pw}", "-H", "Content-Type: text/calendar",
+ data=ics, method="PUT")
+ say(f" radicale: PUT event http={code}")
+ if code != "201":
+ self.tried = f"PUT event -> {code}"
+ return None
+ return {"user": user, "pw": pw, "cal": cal, "uid": uid, "summary": summary}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/.web/", want=("200",), tries=60):
+ say(" radicale: /.web/ never answered")
+ return False
+ path = f"/{t['user']}/{t['cal']}/{t['uid']}.ics"
+ rc, c_none, _ = w.app_curl(sub, path)
+ rc, c_wrong, _ = w.app_curl(sub, path, "-u", f"{t['user']}:{t['pw']}x")
+ rc, c_absent, _ = w.app_curl(sub, f"/{t['user']}/{t['cal']}/never-{secrets.token_hex(3)}.ics", "-u", f"{t['user']}:{t['pw']}")
+ if c_none != "401" or c_wrong != "401" or c_absent != "404":
+ say(f" radicale: READBACK UNUSABLE — no auth {c_none}, wrong password {c_wrong}, absent event {c_absent}")
+ return False
+ rc, code, out = w.app_curl(sub, path, "-u", f"{t['user']}:{t['pw']}")
+ ok = code == "200" and f"SUMMARY:{t['summary']}" in (out or "")
+ say(f" radicale: readback http={code} found={ok} (controls: no auth {c_none}, wrong {c_wrong}, absent {c_absent})")
+ return ok
+
+
+# =============================================================================================
+class Karakeep:
+ """Karakeep (2026-10-01, new app through NEW-APP-CHECKLIST.md). THE FRONT DOOR is the app's own: the first account
+ is made by its sign-up call (tRPC `users.create` — the first account becomes the admin; through the setup gate on the
+ box, as the household), then the route its phone app uses to sign in — `apiKeys.exchange` (email + password -> an API
+ key) — and the REST API: `POST /api/v1/bookmarks` (a text bookmark with a unique title), read back with
+ `GET /api/v1/bookmarks/`. Negative controls on every readback: no key 401, a wrong key 401, an id never made 404.
+ A text bookmark, not a URL: the crawler's success depends on the internet, the read-back must not."""
+ sub = "bookmarks"
+
+ @staticmethod
+ def _trpc(w, sub, proc, payload):
+ rc, code, out = w.app_curl(sub, f"/api/trpc/{proc}?batch=1", "-H", "Content-Type: application/json",
+ data=json.dumps({"0": {"json": payload}}), method="POST")
+ try:
+ return code, json.loads(out)[0]
+ except Exception:
+ return code, {"_raw": (out or "")[:200]}
+
+ def _key(self, w, sub, t):
+ code, r = self._trpc(w, sub, "apiKeys.exchange", {"keyName": "felhom-" + secrets.token_hex(3),
+ "email": t["email"], "password": t["pw"]})
+ return ((r.get("result") or {}).get("data") or {}).get("json", {}).get("key") if code == "200" else None
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/api/health", want=("200",), tries=72):
+ self.tried = "/api/health never answered 200"
+ return None
+ email = "admin-" + secrets.token_hex(3) + "@felhom.invalid"
+ pw = "Kk-" + secrets.token_hex(10)
+ code, r = self._trpc(w, sub, "users.create", {"name": "Felhom", "email": email, "password": pw, "confirmPassword": pw})
+ role = ((r.get("result") or {}).get("data") or {}).get("json", {}).get("role")
+ say(f" karakeep: users.create (the first account) http={code} role={role}")
+ if code != "200":
+ self.tried = f"users.create -> {code} {str(r)[:120]}"
+ return None
+ t = {"email": email, "pw": pw}
+ key = self._key(w, sub, t)
+ if not key:
+ self.tried = "apiKeys.exchange gave no key"
+ return None
+ title = "felhom-seed-" + secrets.token_hex(4)
+ rc, code, out = w.app_curl(sub, "/api/v1/bookmarks", "-H", f"Authorization: Bearer {key}", "-H", "Content-Type: application/json",
+ data=json.dumps({"type": "text", "text": "Felhom teszt jegyzet " + title, "title": title}), method="POST")
+ say(f" karakeep: POST /api/v1/bookmarks http={code}")
+ try:
+ bid = json.loads(out)["id"]
+ except Exception:
+ self.tried = f"POST bookmark -> {code} {(out or '')[:120]}"
+ return None
+ t.update({"id": bid, "title": title, "role": role})
+ return t
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/api/health", want=("200",), tries=72):
+ say(" karakeep: /api/health never answered")
+ return False
+ key = self._key(w, sub, t)
+ if not key:
+ say(" karakeep: the household's email + password no longer give a key")
+ return False
+ rc, c_none, _ = w.app_curl(sub, f"/api/v1/bookmarks/{t['id']}")
+ rc, c_wrong, _ = w.app_curl(sub, f"/api/v1/bookmarks/{t['id']}", "-H", "Authorization: Bearer ak1_felhom_wrong")
+ rc, c_absent, _ = w.app_curl(sub, "/api/v1/bookmarks/never" + secrets.token_hex(4), "-H", f"Authorization: Bearer {key}")
+ if c_none != "401" or c_wrong != "401" or c_absent != "404":
+ say(f" karakeep: READBACK UNUSABLE — no key {c_none}, wrong key {c_wrong}, absent id {c_absent}")
+ return False
+ rc, code, out = w.app_curl(sub, f"/api/v1/bookmarks/{t['id']}", "-H", f"Authorization: Bearer {key}")
+ ok = code == "200" and t["title"] in (out or "")
+ say(f" karakeep: readback http={code} found={ok} (controls: no key {c_none}, wrong {c_wrong}, absent {c_absent})")
+ return ok
+
+
+# =============================================================================================
+class Dawarich:
+ """Dawarich (2026-10-01, new app through NEW-APP-CHECKLIST.md). THE FRONT DOOR is the route the phone apps use:
+ `POST /api/v1/overland/batches?api_key=` (Overland's GeoJSON — one point with a unique place and time), read back
+ with `GET /api/v1/points?api_key=…&start_at=…&end_at=…`. The API key is the account's own (the household copies it
+ from its settings page); the fixture reads it with the app's own CLI (`bin/rails runner` in the app's container —
+ R-156's allowed route, nothing planted). Negative controls on every readback: no key 401, a wrong key 401, a range
+ with nothing in it answers []."""
+ sub = "timeline"
+
+ @staticmethod
+ def _key(w):
+ out = w.guest("docker exec dawarich bin/rails runner 'puts User.order(:id).first.api_key' 2>/dev/null | tail -1")
+ k = (out or "").strip()
+ return k if re.fullmatch(r"[A-Za-z0-9_-]{20,}", k) else None
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/api/v1/health", want=("200",), tries=90):
+ self.tried = "/api/v1/health never answered 200"
+ return None
+ key = self._key(w)
+ if not key:
+ self.tried = "no API key from the app's own CLI"
+ return None
+ lat = round(47.40 + secrets.randbelow(2000) / 10000.0, 4)
+ lon = round(19.00 + secrets.randbelow(2000) / 10000.0, 4)
+ ts = "2026-09-%02dT%02d:%02d:00Z" % (1 + secrets.randbelow(28), secrets.randbelow(24), secrets.randbelow(60))
+ body = {"locations": [{"type": "Feature", "geometry": {"type": "Point", "coordinates": [lon, lat]},
+ "properties": {"timestamp": ts, "altitude": 110, "speed": 0, "horizontal_accuracy": 5,
+ "device_id": "felhom-fixture"}}]}
+ rc, code, out = w.app_curl(sub, f"/api/v1/overland/batches?api_key={key}", "-H", "Content-Type: application/json",
+ data=json.dumps(body), method="POST")
+ say(f" dawarich: POST /api/v1/overland/batches http={code} ({lat},{lon} at {ts})")
+ if code not in ("200", "201"):
+ self.tried = f"overland batch -> {code} {(out or '')[:120]}"
+ return None
+ return {"lat": lat, "lon": lon, "ts": ts}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/api/v1/health", want=("200",), tries=90):
+ say(" dawarich: /api/v1/health never answered")
+ return False
+ key = self._key(w)
+ day = t["ts"][:10]
+ rng = f"start_at={day}T00:00:00Z&end_at={day}T23:59:59Z"
+ rc, c_none, _ = w.app_curl(sub, f"/api/v1/points?{rng}")
+ rc, c_wrong, _ = w.app_curl(sub, f"/api/v1/points?api_key=felhom-wrong-key&{rng}")
+ rc, c_empty, o_empty = w.app_curl(sub, f"/api/v1/points?api_key={key}&start_at=2001-01-01T00:00:00Z&end_at=2001-01-02T00:00:00Z")
+ if c_none != "401" or c_wrong != "401" or (o_empty or "").strip() != "[]":
+ say(f" dawarich: READBACK UNUSABLE — no key {c_none}, wrong key {c_wrong}, empty range {(o_empty or '')[:40]!r}")
+ return False
+ found = False
+ for _ in range(12): # the batch is stored by a background job
+ rc, code, out = w.app_curl(sub, f"/api/v1/points?api_key={key}&{rng}")
+ # the point's fields are read as text: the unique coordinates must both appear in the answer
+ found = code == "200" and str(t["lat"]) in (out or "") and str(t["lon"]) in (out or "")
+ if found:
+ break
+ time.sleep(5)
+ say(f" dawarich: readback http={code} found={found} (controls: no key {c_none}, wrong {c_wrong}, empty range [])")
+ return found
+
+
+
+# =============================================================================================
+class Grocy:
+ """Grocy (2026-10-10, new app through NEW-APP-CHECKLIST.md). THE FRONT DOOR is the household's own
+ browser session plus grocy's REST API, which the same session authenticates — measured on the bench
+ 2026-10-10 (4.7.1): `GET /api/system/info` answers 200 with the login cookie and **401 without it**, so
+ the API is not a second, open door.
+
+ Sign-in is `POST /login` with `username=admin` and `password_base64=` — grocy's
+ form base64-encodes the password client-side, and the server reads that field name (its login page's own
+ input is `password_base64`). The password is the one the box generated and `after_install` installed.
+
+ Seed, all through grocy's own routes: read a location and a quantity unit (a fresh install has one of
+ each), `POST /api/objects/products` with a marker name, then `POST /api/stock/products//add` — the
+ stock route, so the seed exercises what grocy is actually for, not just one table.
+
+ Readback asks the APP for the stock, not the file: `GET /api/stock/products/` must return the marker
+ name AND `stock_amount` 5.
+
+ THE FIXTURE PROVES ITSELF ON EVERY VERIFY: a call with no cookie must be 401, a product id that cannot
+ exist must be 404, and a session minted from a WRONG password must be 401. If any control misreads, the
+ readback is declared unusable rather than passed — a readback that has broken into always saying "found"
+ would otherwise pass every edge.
+ """
+ sub = "kamra"
+
+ # THE TWO VENUES DIFFER HERE, and saying so is the honest part. On the BOX the controller runs
+ # `after_install`, so the generated password is the live one. On the BENCH there is no controller and
+ # `after_install` never runs (check-volume-persistence.build_env generates the value, nothing applies
+ # it), so grocy still carries its image default. The fixture tries the generated password FIRST and
+ # falls back to the documented default, and records which one answered — a silent fallback would hide
+ # a box-side after_install that had stopped working.
+ DEFAULT_PW = "admin"
+
+ def _login_pw(self, w, sub, say):
+ g = w.GENERATED.get("grocy") or {}
+ for pw, src in ((g.get("ADMIN_PASSWORD") or "", "the box's generated password"),
+ (self.DEFAULT_PW, "grocy's image default (no after_install on the bench)")):
+ if not pw:
+ continue
+ if self._session(w, sub, pw):
+ say(" grocy: signed in with %s" % src)
+ return pw, src
+ return "", "neither the generated password nor the image default signed in"
+
+ def _session(self, w, sub, pw):
+ """Grocy's own login route; returns the Cookie header value, or ''.
+
+ BOTH field names are sent on purpose, and that was measured, not guessed: grocy 4.7 renamed the
+ form field to `password_base64` (LoginController base64-decodes it into `password` and unsets it),
+ while 4.6 — the FROM side of the first ladder step — reads a plain `password` and ignores the new
+ name. Sending both signs in on 4.6.0 AND on 4.7.1 (measured 2026-10-10 on the bench, Set-Cookie
+ on both), so one fixture spans the edge. The two releases even name the cookie differently
+ (`grocy_session` vs `grocy_session_access_token`), which is why the cookie is read by pattern.
+ """
+ body = ("username=admin&password=" + (pw or "")
+ + "&password_base64=" + base64.b64encode((pw or "").encode()).decode())
+ rc, code, out = w.app_curl(sub, "/login", "-D", "-", "-o", "/dev/null",
+ "-H", "Content-Type: application/x-www-form-urlencoded",
+ data=body, method="POST")
+ return _set_cookies(out) if rc == 0 else ""
+
+ @staticmethod
+ def _first_id(out):
+ m = re.search(r'"id":\s*"?(\d+)"?', out or "")
+ return m.group(1) if m else None
+
+ def seed(self, w, sub, say):
+ # GET / is what runs grocy's migrations (measured on 4.6.0: /login answered 200 with a
+ # ZERO-BYTE database, / created the schema and the admin row), so the wait dials / first.
+ if not w.wait_app(sub, "/", want=("200", "302"), tries=72):
+ self.tried = "/ never answered"
+ return None
+ w.app_curl(sub, "/stockoverview")
+ pw, src = self._login_pw(w, sub, say)
+ if not pw:
+ self.tried = src
+ say(" grocy: " + src)
+ return None
+ ck = self._session(w, sub, pw)
+ if not ck:
+ self.tried = "POST /login gave no session cookie"
+ say(" grocy: login gave no session cookie")
+ return None
+ rc, code, out = w.app_curl(sub, "/api/objects/locations", "-H", "Cookie: " + ck)
+ loc = self._first_id(out)
+ rc, code, out = w.app_curl(sub, "/api/objects/quantity_units", "-H", "Cookie: " + ck)
+ qu = self._first_id(out)
+ if not loc or not qu:
+ self.tried = "no location (%s) or quantity unit (%s) to hang a product on" % (loc, qu)
+ say(" grocy: " + self.tried)
+ return None
+ mark = "felhom-upg-" + secrets.token_hex(4)
+ body = json.dumps({"name": mark, "location_id": int(loc), "qu_id_purchase": int(qu),
+ "qu_id_stock": int(qu), "min_stock_amount": 2})
+ rc, code, out = w.app_curl(sub, "/api/objects/products", "-H", "Cookie: " + ck,
+ "-H", "Content-Type: application/json", data=body, method="POST")
+ say(" grocy: POST /api/objects/products http=%s :: %s" % (code, (out or "")[:120]))
+ if code != "200":
+ self.tried = "POST /api/objects/products -> %s" % code
+ return None
+ m = re.search(r'"created_object_id":\s*"?(\d+)"?', out or "")
+ if not m:
+ self.tried = "the product POST answered 200 with no created_object_id"
+ return None
+ pid = m.group(1)
+ rc, code, out = w.app_curl(sub, "/api/stock/products/%s/add" % pid, "-H", "Cookie: " + ck,
+ "-H", "Content-Type: application/json",
+ data=json.dumps({"amount": 5, "transaction_type": "purchase"}), method="POST")
+ say(" grocy: POST /api/stock/products/%s/add http=%s" % (pid, code))
+ if code != "200":
+ self.tried = "stock add -> %s" % code
+ return None
+ return {"pw": pw, "pw_src": src, "pid": pid, "mark": mark, "amount": 5}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/login", want=("200",), tries=72):
+ say(" grocy: /login never answered")
+ return False
+ path = "/api/stock/products/%s" % t["pid"]
+ rc, c_none, _ = w.app_curl(sub, path)
+ bad = self._session(w, sub, t["pw"] + "x")
+ rc, c_wrong, _ = w.app_curl(sub, path, *(["-H", "Cookie: " + bad] if bad else []))
+ ck = self._session(w, sub, t["pw"])
+ if not ck:
+ say(" grocy: the household's own password no longer signs in after the step")
+ return False
+ rc, c_absent, _ = w.app_curl(sub, "/api/objects/products/999999", "-H", "Cookie: " + ck)
+ if c_none != "401" or c_wrong != "401" or c_absent != "404":
+ say(" grocy: READBACK UNUSABLE - no cookie %s, wrong password %s, absent id %s"
+ % (c_none, c_wrong, c_absent))
+ return False
+ rc, code, out = w.app_curl(sub, path, "-H", "Cookie: " + ck)
+ found = False
+ if code == "200":
+ try:
+ d = json.loads(out or "{}")
+ found = (str(d.get("stock_amount")) in (str(t["amount"]), "%s.0" % t["amount"])
+ and (d.get("product") or {}).get("name") == t["mark"])
+ except ValueError:
+ found = False
+ say(" grocy: readback http=%s found=%s (controls: no cookie %s, wrong %s, absent %s)"
+ % (code, found, c_none, c_wrong, c_absent))
+ return found
+
+
+# =============================================================================================
+class LubeLogger:
+ """LubeLogger (2026-10-10, new app through NEW-APP-CHECKLIST.md). THE FRONT DOOR is the app's own login
+ form plus its REST API, both of which exist only because our template turns authentication ON: the image
+ ships `EnableAuth: false`, and with that an anonymous stranger is handed the `IsRootUser` role (measured
+ on the bench 2026-10-10: a stranger created a vehicle through `POST /Vehicle/SaveVehicle`). The container
+ entrypoint exports `EnableAuth=true` plus the SHA-256 of the generated name and password, so BOTH VENUES
+ behave the same here — unlike grocy, nothing depends on `after_install`.
+
+ Seed, through the app's own routes: sign in at `POST /Login/Login`, create a vehicle with a marker plate
+ at `POST /Vehicle/SaveVehicle`, then add a service record with a marker description at
+ `POST /api/vehicle/servicerecords/add` — so the seed covers the vehicle table AND a child record.
+
+ Readback asks the APP: `GET /api/vehicles` must still carry the plate, and
+ `GET /api/vehicle/servicerecords?vehicleId=` must still carry the description and the cost.
+
+ THE FIXTURE PROVES ITSELF ON EVERY VERIFY: no cookie must be 401, a session minted from a WRONG password
+ must be 401, and a vehicleId that cannot exist must answer an EMPTY list (measured: 200 `[]`). If any
+ control misreads, the readback is unusable rather than passed.
+ """
+ sub = "garazs"
+
+ @staticmethod
+ def _creds(w):
+ g = w.GENERATED.get("lubelogger") or {}
+ return g.get("ROOT_USER") or "csalad", g.get("ROOT_PASSWORD") or ""
+
+ def _session(self, w, sub, user, pw):
+ rc, code, out = w.app_curl(sub, "/Login/Login", "-D", "-", "-o", "/dev/null",
+ "-H", "Content-Type: application/x-www-form-urlencoded",
+ data="UserName=%s&Password=%s" % (user, pw), method="POST")
+ return _set_cookies(out) if rc == 0 else ""
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/Login/Index", want=("200",), tries=72):
+ self.tried = "/Login/Index never answered 200"
+ return None
+ user, pw = self._creds(w)
+ if not pw:
+ self.tried = "no generated ROOT_PASSWORD for lubelogger in this run"
+ return None
+ ck = self._session(w, sub, user, pw)
+ if not ck:
+ self.tried = "POST /Login/Login gave no session cookie"
+ say(" lubelogger: login gave no session cookie")
+ return None
+ plate = "FEL-" + secrets.token_hex(3).upper()
+ desc = "Felhom teszt szerviz " + secrets.token_hex(3)
+ rc, code, out = w.app_curl(sub, "/Vehicle/SaveVehicle", "-H", "Cookie: " + ck,
+ "-H", "Content-Type: application/x-www-form-urlencoded",
+ data=("Year=2019&Make=Skoda&Model=Octavia&LicensePlate=%s"
+ "&IsElectric=false&IsDiesel=true&UseHours=false" % plate),
+ method="POST")
+ say(" lubelogger: POST /Vehicle/SaveVehicle http=%s :: %s" % (code, (out or "")[:100]))
+ if code != "200" or '"success":true' not in (out or ""):
+ self.tried = "SaveVehicle -> %s %s" % (code, (out or "")[:120])
+ return None
+ rc, code, out = w.app_curl(sub, "/api/vehicles", "-H", "Cookie: " + ck)
+ vid = None
+ try:
+ for v in json.loads(out or "[]"):
+ if str(v.get("licensePlate")) == plate:
+ vid = str(v.get("id"))
+ except ValueError:
+ pass
+ if not vid:
+ self.tried = "the new vehicle did not come back from /api/vehicles"
+ say(" lubelogger: " + self.tried)
+ return None
+ rc, code, out = w.app_curl(sub, "/api/vehicle/servicerecords/add", "-H", "Cookie: " + ck,
+ "-H", "Content-Type: application/x-www-form-urlencoded",
+ data=("vehicleId=%s&date=2026-10-01&odometer=123456&description=%s"
+ "&cost=19900¬es=felhom-fixture"
+ % (vid, desc.replace(" ", "+"))), method="POST")
+ say(" lubelogger: POST servicerecords/add http=%s :: %s" % (code, (out or "")[:110]))
+ if code != "200" or '"success":true' not in (out or ""):
+ self.tried = "servicerecords/add -> %s" % code
+ return None
+ return {"user": user, "pw": pw, "plate": plate, "vid": vid, "desc": desc, "cost": "19900"}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/Login/Index", want=("200",), tries=72):
+ say(" lubelogger: /Login/Index never answered")
+ return False
+ rc, c_none, _ = w.app_curl(sub, "/api/vehicles")
+ bad = self._session(w, sub, t["user"], t["pw"] + "x")
+ rc, c_wrong, _ = w.app_curl(sub, "/api/vehicles", *(["-H", "Cookie: " + bad] if bad else []))
+ ck = self._session(w, sub, t["user"], t["pw"])
+ if not ck:
+ say(" lubelogger: the household's own password no longer signs in after the step")
+ return False
+ rc, c_absent, absent_body = w.app_curl(sub, "/api/vehicle/servicerecords?vehicleId=999999",
+ "-H", "Cookie: " + ck)
+ empty = c_absent == "200" and (absent_body or "").strip() in ("[]", "[ ]")
+ if c_none != "401" or c_wrong != "401" or not empty:
+ say(" lubelogger: READBACK UNUSABLE - no cookie %s, wrong password %s, absent vehicle %s %s"
+ % (c_none, c_wrong, c_absent, (absent_body or "")[:40]))
+ return False
+ rc, code, out = w.app_curl(sub, "/api/vehicles", "-H", "Cookie: " + ck)
+ plate_ok = code == "200" and ('"%s"' % t["plate"]) in (out or "")
+ rc, code2, out2 = w.app_curl(sub, "/api/vehicle/servicerecords?vehicleId=%s" % t["vid"],
+ "-H", "Cookie: " + ck)
+ rec_ok = code2 == "200" and t["desc"] in (out2 or "") and t["cost"] in (out2 or "")
+ say(" lubelogger: readback vehicle=%s (http=%s) service record=%s (http=%s) "
+ "(controls: no cookie %s, wrong %s, absent list empty)"
+ % (plate_ok, code, rec_ok, code2, c_none, c_wrong))
+ return bool(plate_ok and rec_ok)
+
+# =============================================================================================
+class Grimmory:
+ """Grimmory (2026-10-01, new app through NEW-APP-CHECKLIST.md). THE FRONT DOOR is the app's own API, the one its web
+ client calls: the first admin by `POST /api/v1/setup` (through the setup gate on the box, as the household), sign in
+ with `POST /api/v1/auth/login` (a bearer token), a library on `/books`, and a real EPUB (built here, with a unique
+ title) uploaded with `POST /api/v1/files/upload` — the app writes it into the household's book folder. Read back:
+ `GET /api/v1/books` lists the title. Negative controls on every readback: no token 401, a wrong password 401, and a
+ second `POST /api/v1/setup` refused (403) — the readback is not an open door."""
+ sub = "library"
+
+ @staticmethod
+ def _epub(title):
+ import io as _io, zipfile
+ b = _io.BytesIO()
+ z = zipfile.ZipFile(b, "w")
+ z.writestr(zipfile.ZipInfo("mimetype"), "application/epub+zip")
+ z.writestr("META-INF/container.xml", '')
+ z.writestr("OEBPS/content.opf", f'{title}Felhom{title}hu ')
+ z.writestr("OEBPS/c1.xhtml", 'cSzia!
')
+ z.close()
+ return b.getvalue()
+
+ def _token(self, w, sub, user, pw):
+ rc, code, out = w.app_curl(sub, "/api/v1/auth/login", "-H", "Content-Type: application/json",
+ data=json.dumps({"username": user, "password": pw}), method="POST")
+ try:
+ return code, json.loads(out).get("accessToken")
+ except Exception:
+ return code, None
+
+ def seed(self, w, sub, say):
+ import tempfile
+ if not w.wait_app(sub, "/api/v1/healthcheck", want=("200",), tries=90):
+ self.tried = "/api/v1/healthcheck never answered 200"
+ return None
+ user, pw = "admin", "Gm-" + secrets.token_hex(10)
+ rc, code, out = w.app_curl(sub, "/api/v1/setup", "-H", "Content-Type: application/json",
+ data=json.dumps({"username": user, "password": pw, "email": "admin@felhom.invalid", "name": "Felhom"}), method="POST")
+ say(f" grimmory: POST /api/v1/setup (the first admin) http={code}")
+ if code != "200":
+ self.tried = f"setup -> {code} {(out or '')[:120]}"
+ return None
+ code, tok = self._token(w, sub, user, pw)
+ if not tok:
+ self.tried = f"login -> {code}"
+ return None
+ auth = ["-H", f"Authorization: Bearer {tok}"]
+ rc, code, out = w.app_curl(sub, "/api/v1/libraries", *auth, "-H", "Content-Type: application/json",
+ data=json.dumps({"name": "Konyvek", "icon": "book", "iconType": "LUCIDE", "paths": [{"path": "/books"}],
+ "watch": True, "metadataSource": "EMBEDDED", "organizationMode": "BOOK_PER_FILE"}), method="POST")
+ try:
+ lib = json.loads(out)
+ lid, pid = lib["id"], lib["paths"][0]["id"]
+ except Exception:
+ self.tried = f"create library -> {code} {(out or '')[:120]}"
+ return None
+ title = "Felhom Teszt " + secrets.token_hex(4)
+ fn = tempfile.mktemp(suffix=".epub")
+ open(fn, "wb").write(self._epub(title))
+ if hasattr(w, "put_file"):
+ fn = w.put_file(fn)
+ rc, code, out = w.app_curl(sub, "/api/v1/files/upload", *auth, "-F", f"file=@{fn};type=application/epub+zip",
+ "-F", f"libraryId={lid}", "-F", f"pathId={pid}", method="POST")
+ say(f" grimmory: library {lid}, upload of an EPUB http={code}")
+ if code not in ("200", "201", "204"):
+ self.tried = f"upload -> {code} {(out or '')[:120]}"
+ return None
+ return {"user": user, "pw": pw, "title": title}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/api/v1/healthcheck", want=("200",), tries=90):
+ say(" grimmory: /api/v1/healthcheck never answered")
+ return False
+ rc, c_none, _ = w.app_curl(sub, "/api/v1/books")
+ c_wrong, _ = self._token(w, sub, t["user"], t["pw"] + "x")
+ rc, c_setup, _ = w.app_curl(sub, "/api/v1/setup", "-H", "Content-Type: application/json",
+ data=json.dumps({"username": "x" + secrets.token_hex(2), "password": "Gm-" + secrets.token_hex(8),
+ "email": "x@felhom.invalid", "name": "X"}), method="POST")
+ if c_none != "401" or c_wrong != "401" or c_setup != "403":
+ say(f" grimmory: READBACK UNUSABLE — no token {c_none}, wrong password {c_wrong}, second setup {c_setup}")
+ return False
+ code, tok = self._token(w, sub, t["user"], t["pw"])
+ found = False
+ for _ in range(12):
+ rc, code, out = w.app_curl(sub, "/api/v1/books", "-H", f"Authorization: Bearer {tok}")
+ found = code == "200" and t["title"] in (out or "")
+ if found:
+ break
+ time.sleep(5)
+ say(f" grimmory: readback http={code} found={found} (controls: no token {c_none}, wrong {c_wrong}, second setup {c_setup})")
+ return found
+
+
+class MeTube:
+ """MeTube (2026-10-02, new app through NEW-APP-CHECKLIST.md, published behind the family gate). THE FRONT DOOR is its
+ own web API, the one its page calls: `POST /add` a link, then `GET /history` until the item is `finished`; the file is
+ served back at `GET /download/`. The link is a 1 MB public test video (yt-dlp's generic extractor — no
+ video-service account, no cookies). Negative control on every readback: a file never downloaded answers 404, so a
+ read that says "found" cannot be a catch-all. On the box the family gate is passed as the household (box_walk)."""
+ sub = "video"
+ URL = "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4"
+
+ @classmethod
+ def add_body(cls):
+ """The `POST /add` body. `download_type` is listed as REQUIRED by upstream's validator; 2026.09.28/.29 answered
+ 200 without it (R-799), a later tag may not. Pinned by test_upgrade_fixtures_metube.py."""
+ return {"url": cls.URL, "download_type": "video", "quality": "best", "format": "any", "auto_start": True}
+
+ def _hist(self, w, sub):
+ rc, code, out = w.app_curl(sub, "/history")
+ try:
+ return code, json.loads(out)
+ except Exception:
+ return code, {}
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/", want=("200",), tries=60):
+ self.tried = "/ never answered 200"
+ return None
+ rc, code, out = w.app_curl(sub, "/add", "-H", "Content-Type: application/json", "-H", f"Origin: https://{sub}.{w.DOMAIN}",
+ data=json.dumps(self.add_body()), method="POST")
+ say(f" metube: POST /add http={code} {(out or '')[:40]}")
+ if code != "200":
+ self.tried = f"add -> {code} {(out or '')[:80]}"
+ return None
+ for _ in range(60):
+ code, h = self._hist(w, sub)
+ done = [d for d in h.get("done", []) if d.get("url") == self.URL and d.get("status") == "finished"]
+ if done:
+ fn = done[0].get("filename") or (done[0].get("title", "") + ".mp4")
+ say(f" metube: the download finished ({done[0].get('size')} bytes)")
+ return {"filename": fn, "size": done[0].get("size")}
+ time.sleep(3)
+ self.tried = "the download never finished"
+ return None
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/", want=("200",), tries=60):
+ say(" metube: / never answered")
+ return False
+ import urllib.parse
+ rc, c_absent, _ = w.app_curl(sub, "/download/never-" + secrets.token_hex(4) + ".mp4")
+ if c_absent != "404":
+ say(f" metube: READBACK UNUSABLE — a file never downloaded answered {c_absent}")
+ return False
+ code, h = self._hist(w, sub)
+ in_hist = any(d.get("url") == self.URL and d.get("status") == "finished" for d in h.get("done", []))
+ rc, code, out = w.app_curl(sub, "/download/" + urllib.parse.quote(t["filename"]), "-o", "/dev/null")
+ say(f" metube: history has it={in_hist}; GET /download/ http={code}")
+ return code == "200" and in_hist
+
+
+# The NZB both Usenet box fixtures seed with: article names that do not exist, because without a
+# paid provider nothing can be fetched anyway and what is being measured is the QUEUE.
+BOX_NZB = (
+ '\n'
+ '\n'
+ '%(name)s\n'
+ '\n'
+ 'alt.binaries.test\n'
+ '%(name)s-1@example.invalid\n'
+ '\n\n'
+)
+
+
+class SABnzbdBox:
+ """SABnzbd through traefik, with the household's own generated API key.
+
+ The web UI is session-based and requires a login for every proxied visitor (this template sets
+ local_ranges so that nothing a proxy presents counts as local), but the API authenticates with
+ the key - which is the route Radarr and Sonarr use, so it is the route the fixture uses too.
+ Both stores are seeded: a queued job (the queue index, /config/admin/queue10.sab) and a category
+ (sabnzbd.ini)."""
+ sub = "usenet"
+
+ def _key(self, w):
+ """The key the household was given. `walk.GENERATED` does not hold it - deploy_values skips
+ an OPTIONAL `type: secret` field, because the controller generates those itself - so the box
+ is asked for the value out of the app's own app.yaml, which is where the household reads it
+ too (measured on 9202, 2026-10-12: the first run had no key and could not seed)."""
+ k = (w.GENERATED.get("sabnzbd") or {}).get("SAB_API_KEY", "")
+ if k:
+ return k
+ # app.yaml stores a deploy secret ENCRYPTED (`SAB_API_KEY: ENC:...`), so app_env returns
+ # ciphertext and the app answers "API Key Incorrect" (measured on 9202, 2026-10-12). The
+ # value the APP holds is in its own environment - the same place the bench fixture reads it.
+ return w.guest("docker exec sabnzbd printenv SAB_API_KEY").strip()
+
+ def _pw(self, w):
+ p = (w.GENERATED.get("sabnzbd") or {}).get("SAB_ADMIN_PASSWORD", "")
+ return p or w.guest("docker exec sabnzbd printenv SAB_ADMIN_PASSWORD").strip()
+
+ def _api(self, w, sub, query, say, extra=None):
+ key = self._key(w)
+ if not key:
+ say(" sabnzbd: this run holds no generated API key for the app")
+ return "", ""
+ args = ["curl", "-sSk", "--max-time", "40", "-H", f"Host: {sub}.{w.DOMAIN}",
+ "-w", "\n%{http_code}"]
+ if extra:
+ args += extra
+ args.append(f"{w.BASE}/api?output=json&apikey={key}&{query}")
+ r = w.sh(args)
+ out, _, code = (r.stdout or "").rpartition("\n")
+ return code.strip(), out
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/", want=("200", "303", "401", "403")):
+ return None
+ name = "felhom" + secrets.token_hex(4)
+ # the NZB is written on the harness host and posted through the front door
+ path = os.path.join(w.SC, name + ".nzb")
+ with open(path, "w") as f:
+ f.write(BOX_NZB % {"name": name})
+ code, out = self._api(w, sub, "mode=addfile", say,
+ extra=["-F", f"name=@{path}", "-F", f"nzbname={name}"])
+ ok = code == "200" and '"status"' in out and "true" in out
+ say(f" sabnzbd: addfile {name} http={code} ok={ok}")
+ if not ok:
+ say(f" sabnzbd: refused {out[:200]}")
+ return None
+ code, out = self._api(w, sub,
+ f"mode=set_config§ion=categories&keyword={name}&name={name}&dir={name}", say)
+ if code != "200":
+ say(f" sabnzbd: the category was refused (http={code}) {out[:160]}")
+ return None
+ say(f" sabnzbd: category {name} created")
+ return {"name": name}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/", want=("200", "303", "401", "403"), tries=36):
+ return False
+ code, out = self._api(w, sub, "mode=queue", say)
+ if code != "200":
+ say(f" sabnzbd: mode=queue http={code}")
+ return False
+ ghost = "felhom" + secrets.token_hex(4)
+ if ghost in out:
+ say(" sabnzbd: READBACK UNUSABLE - a job nobody queued is present")
+ return False
+ if t["name"] not in out:
+ say(f" sabnzbd: the queued job {t['name']} is GONE")
+ return False
+ code, out = self._api(w, sub, "mode=get_config§ion=categories", say)
+ ok = code == "200" and t["name"] in out
+ say(f" sabnzbd: job kept, category present={ok}")
+ return ok
+
+
+class NZBGetBox:
+ """NZBGet through traefik, with the household's own generated password over Basic auth.
+
+ One store, and it is the one that matters: the queue, which this template keeps in the config
+ volume (the app ships it on the drive, which the backup classification calls optional)."""
+ sub = "nzbget"
+
+ def _pw(self, w):
+ p = (w.GENERATED.get("nzbget") or {}).get("NZB_ADMIN_PASSWORD", "")
+ # app.yaml keeps deploy secrets encrypted, so the app's own environment is the source
+ return p or w.guest("docker exec nzbget printenv NZBGET_PASS").strip()
+
+ def _rpc(self, w, sub, say, payload_file=None, path=""):
+ pw = self._pw(w)
+ if not pw:
+ say(" nzbget: this run holds no generated password for the app")
+ return "", ""
+ args = ["curl", "-sSk", "--max-time", "40", "-H", f"Host: {sub}.{w.DOMAIN}",
+ "-u", f"admin:{pw}", "-w", "\n%{http_code}"]
+ if payload_file:
+ args += ["-H", "Content-Type: application/json", "--data", "@" + payload_file]
+ args.append(f"{w.BASE}/jsonrpc/{path}")
+ r = w.sh(args)
+ out, _, code = (r.stdout or "").rpartition("\n")
+ return code.strip(), out
+
+ def seed(self, w, sub, say):
+ if not w.wait_app(sub, "/", want=("200", "401")):
+ return None
+ name = "felhom" + secrets.token_hex(4)
+ nzb = (BOX_NZB % {"name": name}).encode()
+ payload = json.dumps({"method": "append",
+ "params": [name + ".nzb", base64.b64encode(nzb).decode(), "",
+ 0, False, True, "", 0, "SCORE", []],
+ "id": 1})
+ pf = os.path.join(w.SC, name + ".json")
+ with open(pf, "w") as f:
+ f.write(payload)
+ code, out = self._rpc(w, sub, say, payload_file=pf)
+ ok = code == "200" and '"result" : -1' not in out and '"result":-1' not in out
+ say(f" nzbget: append {name} http={code} ok={ok}")
+ if not ok:
+ say(f" nzbget: refused {out[:200]}")
+ return None
+ return {"name": name}
+
+ def verify(self, w, sub, t, say):
+ if not w.wait_app(sub, "/", want=("200", "401"), tries=36):
+ return False
+ code, out = self._rpc(w, sub, say, path="listgroups")
+ if code != "200":
+ say(f" nzbget: listgroups http={code}")
+ return False
+ ghost = "felhom" + secrets.token_hex(4)
+ if ghost in out:
+ say(" nzbget: READBACK UNUSABLE - a job nobody queued is present")
+ return False
+ ok = t["name"] in out
+ say(f" nzbget: the queued job is present={ok}")
+ return ok
+
+
+FIXTURES = {
+ "uptime-kuma": UptimeKuma(),
+ "crafty-controller": Crafty(),
+ "wger": Wger(),
+ "calibre-web": CalibreWeb(),
+ "sparkyfitness": Sparkyfitness(),
+ "metube": MeTube(),
+ "rallly": Rallly(),
+ "outline": Outline(),
+ "home-assistant": HomeAssistant(),
+ "romm": Romm(),
+ "vikunja": Vikunja(),
+ "opengist": OpenGist(),
+ "papra": Papra(),
+ "mealie": Mealie(),
+ "n8n": N8n(),
+ "zipline": Zipline(),
+ "grafana": Grafana(),
+ "audiobookshelf": AudiobookShelf(),
+ "actualbudget": ActualBudget(),
+ "nextcloud": Nextcloud(),
+ "adventurelog": Django("adventurelog", "travel", "/admin/login/"),
+ "tandoor": Django("tandoor", "recipes", "/accounts/login/",
+ python="/opt/recipes/venv/bin/python", workdir="/opt/recipes"),
+ # 2026-09-26 (version-travel Part B): paperless-ngx is Django too — `manage.py` in its WORKDIR
+ # (/usr/src/paperless/src), python3 on PATH; measured on 9202 (the readback answered False for a
+ # username that cannot exist) before this line was written.
+ "paperless-ngx": Django("paperless-webserver", "paperless", "/accounts/login/"),
+ "privatebin": PrivateBin(),
+ "docmost": Docmost(),
+ "bookstack": BookStack(),
+ "gitea": Gitea(),
+ "navidrome": Navidrome(),
+ "vaultwarden": Vaultwarden(),
+ "wishlist": Wishlist(),
+ "claper": Claper(),
+ "calcom": Calcom(),
+ "radicale": Radicale(),
+ "karakeep": Karakeep(),
+ "dawarich": Dawarich(),
+ "grimmory": Grimmory(),
+ "grocy": Grocy(),
+ "lubelogger": LubeLogger(),
+ "qbittorrent": QBittorrentBox(),
+ "prowlarr": ProwlarrBox(),
+ "transmission": TransmissionBox(),
+ "sabnzbd": SABnzbdBox(),
+ "nzbget": NZBGetBox(),
+}
diff --git a/documentation/audits/catalog-sweep-2026-10-24/tools/vmctl.sh b/documentation/audits/catalog-sweep-2026-10-24/tools/vmctl.sh
new file mode 100755
index 00000000..43607833
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/tools/vmctl.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+# vmctl.sh — drive a nested VM's console on demo-hp from DooPlex (rehearsal 2026-10-20).
+# The installer keeps the HUNGARIAN keyboard (as a household would), so characters are sent as the
+# scancodes a Hungarian-layout keyboard produces: y<->z swapped, '-' on the US '/' key, '0' on the
+# US '`' key, '@' = AltGr+V. Only the characters below are supported — anything else is refused.
+#
+# vmctl.sh shot console screenshot (QEMU screendump → PNG on DooPlex)
+# vmctl.sh key ... send raw keys (e.g. ret, tab, right, alt-n)
+# vmctl.sh type type text with the Hungarian mapping
+# vmctl.sh typevar type the value of an env var (use inside `sec run`; never echoed)
+set -euo pipefail
+VMID=$1; CMD=$2; shift 2
+HOST=${VMHOST:-demo-hp}
+
+map_char() {
+ local c=$1
+ case "$c" in
+ [a-x]) echo "$c" ;;
+ y) echo "z" ;; z) echo "y" ;;
+ [A-X]) echo "shift-${c,,}" ;;
+ Y) echo "shift-z" ;; Z) echo "shift-y" ;;
+ [1-9]) echo "$c" ;;
+ 0) echo "grave_accent" ;;
+ .) echo "dot" ;;
+ ,) echo "comma" ;;
+ -) echo "slash" ;;
+ _) echo "shift-slash" ;;
+ @) echo "alt_r-v" ;;
+ " ") echo "spc" ;;
+ *) echo "UNSUPPORTED" ;;
+ esac
+}
+
+send_text() {
+ local s=$1 keys=() k i
+ for (( i=0; i<${#s}; i++ )); do
+ k=$(map_char "${s:$i:1}")
+ if [ "$k" = UNSUPPORTED ]; then echo "vmctl: unsupported character at position $i" >&2; exit 2; fi
+ keys+=("$k")
+ done
+ # one ssh, one qm sendkey per key (qm sendkey takes one key combo)
+ printf '%s\n' "${keys[@]}" | ssh "$HOST" "while read -r k; do LC_ALL=C qm sendkey $VMID \"\$k\" >/dev/null 2>&1 || exit 3; sleep 0.08; done"
+}
+
+case "$CMD" in
+ shot)
+ out=$1
+ ssh "$HOST" "rm -f /tmp/vmshot-$VMID.ppm; echo 'screendump /tmp/vmshot-$VMID.ppm' | LC_ALL=C qm monitor $VMID >/dev/null 2>&1; sleep 1; cat /tmp/vmshot-$VMID.ppm" > "$out.ppm"
+ convert "$out.ppm" "$out"; rm -f "$out.ppm"; echo "shot: $out" ;;
+ key)
+ for k in "$@"; do ssh "$HOST" "LC_ALL=C qm sendkey $VMID '$k'"; sleep 0.3; done ;;
+ type)
+ send_text "$1" ;;
+ typevar)
+ v=${!1:-}; [ -n "$v" ] || { echo "vmctl: env $1 empty" >&2; exit 2; }
+ send_text "$v" ;;
+ *) echo "usage: see header" >&2; exit 1 ;;
+esac
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission.console.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission.console.txt
new file mode 100644
index 00000000..0be88c68
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission.console.txt
@@ -0,0 +1,15 @@
+14:39:44Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'TR_ADMIN_PASSWORD']
+14:39:44Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+14:40:04Z [1] deployed, controller state=running, pinned={'transmission': 'lscr.io/linuxserver/transmission:version-4.1.3-r0'}
+14:40:04Z [1] installed: deployed 20 s, front door 20 s
+14:40:04Z transmission: session-set speed-limit-down=529 http=200
+14:40:04Z transmission: torrent-add http=200 ok=True
+14:40:05Z transmission: limit kept, torrent present=True
+14:40:19Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+14:41:05Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'transmission', 'volumes_removed': ['transmission_transmission_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-drives/hdd_
+14:41:14Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['TR_ADMIN_PASSWORD', 'HDD_PATH']
+14:41:29Z transmission: the seeded limit 529 is GONE
+14:41:29Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:41:45Z transmission: limit kept, torrent present=True
+14:42:27Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'transmission', 'volumes_removed': ['transmission_transmission_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-drives/hdd_
+14:42:36Z == transmission done in 172 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-guide-en.txt
new file mode 100644
index 00000000..8145675f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-guide-en.txt
@@ -0,0 +1 @@
+Transmission — Guide — Felhom.eu ← Apps Transmission Simple torrent downloading, on almost no resources ● Running transmission.tester4.test Open ↗ Files ↗ What is it for? Download torrents to your own drive from a simple interface You see the finished files in the file browser and in your media player It uses very little: it fits on a small machine beside everything else If you want full control (queues, scheduling, detailed rules), qBittorrent is the stronger choice First steps Open transmission.tester4.test and sign in as admin with the password generated at install Finished downloads land on your drive, in the media/transmission/complete folder. Sonarr and Radarr take them from there without using extra space Download only what you have the right to. Downloads go out from your household's internet address, and by the nature of a torrent the other participants see that address. Before you start Downloading uses your household's internet connection, and so does the uploading It accepts no incoming connections, because the box opens no port at home. Downloading works anyway: measured at 34 seeds and 4 MB/s on a well-seeded torrent. Only poorly seeded torrents are slower, and you upload less. If you want it, you can switch port forwarding on yourself in the app's own settings Add a torrent Add only a torrent whose content you have the right to, for example a Linux installer from its publisher's own site. Select „Open” in the bar at the top: the „Add Torrents” window opens. Choose the torrent file, or paste the torrent or magnet link into the URL box. Leave „Start when added” ticked and select „Add”. A torrent file in the watched folder Transmission starts a torrent file by itself when you put it into its watched folder. In the file browser, open the media/transmission/watch folder on the downloads drive. Upload the torrent file there. A few seconds later the torrent appears in Transmission's list and starts. Stop and remove You can stop or remove a torrent at any time. Select the torrent and select „Pause”. „Start” carries on. To remove it, select „Delete”, then „Remove”. The downloaded files stay. To delete the files as well, right-click the torrent and choose „Trash data and remove from list…”. Slower downloads by day You can make it use less of your internet line during the day. Select the menu button in the bar at the top, then „Edit preferences”. Open the „Speed” tab, and under „Alternative Speed Limits” enter lower values. Tick „Scheduled times” and set when and on which days it applies. The setting applies at once; there is no separate save. Frequently asked questions Do I have to connect it to Sonarr and Radarr? No. For every drive, the box connected Transmission to Sonarr and Radarr. What they ask for goes into the media/transmission/tv or media/transmission/movies folder of that drive. If I remove the torrent, does the film leave the library too? No. Sonarr and Radarr put the same file into the library under a second name, and that stays after the torrent and its files are deleted. Can I switch on the temporary folder? Do not. „Use temporary folder:” is one folder for every drive, so every download bound for another drive would have to be copied over at the end. The box switches it off at every start. Can I change where it saves? Do not. Transmission sees only the media/transmission folder on your drives; a file saved anywhere else is not on the drive, and Sonarr and Radarr cannot find it. A setting was lost after a power cut. Why? Transmission writes its settings only when it shuts down properly. After a power cut, check your settings and enter them again if needed. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-guide-hu.txt
new file mode 100644
index 00000000..68ffbf51
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-guide-hu.txt
@@ -0,0 +1 @@
+Transmission — Felhom.eu ← Alkalmazások Transmission Torrent letöltés egyszerűen, alig észrevehető erőforrásból ● Fut transmission.tester4.test Megnyitás ↗ Fájlok ↗ Mire használható? Torrentek letöltése a saját meghajtódra, egyszerű felületről A kész fájlokat a fájlböngészőben és a médialejátszódban is látod Nagyon keveset fogyaszt: kisebb gépen is elfér a többi alkalmazás mellett Ha a teljes vezérlést szeretnéd (sorok, ütemezés, részletes szabályok), a qBittorrent az erősebb választás Első lépések Nyisd meg a transmission.tester4.test címet, és lépj be az admin névvel és a telepítéskor kapott jelszóval A kész letöltések a meghajtódon, a media/transmission/complete mappába kerülnek. A Sonarr és a Radarr innen veszi át őket, külön hely nélkül Csak olyan tartalmat tölts le, amihez jogod van. A letöltés a háztartásod internetcíméről történik, és a torrent természetéből adódóan a többi résztvevő látja a címedet. Előfeltételek A letöltés a háztartásod internetkapcsolatát használja, és a feltöltés is onnan megy Befelé irányuló kapcsolatot nem fogad, mert a doboz otthon egyetlen portot sem nyit. A letöltés ettől működik: mérve 34 forrás és 4 MB/s egy jól ellátott torrenten. Csak a kevés forrású torrentek lassabbak, és keveset tudsz visszatölteni. Ha szeretnéd, az alkalmazás saját beállításaiban te magad bekapcsolhatod a port-nyitást Torrent hozzáadása Csak olyan torrentet adj hozzá, amelynek a tartalmához jogod van, például egy Linux telepítőét a kiadó saját oldaláról. Kattints a felső sávban az „Open” (megnyitás) gombra: megnyílik az „Add Torrents” (torrentek hozzáadása) ablak. Válaszd ki a torrentfájlt, vagy illeszd be a torrent vagy a magnet linkjét az URL mezőbe. Hagyd bejelölve a „Start when added” (indítás hozzáadáskor) jelölőt, és kattints az „Add” (hozzáadás) gombra. Torrentfájl a figyelt mappába A Transmission magától elindítja a torrentfájlt, amelyet a figyelt mappájába teszel. Nyisd meg a fájlböngészőben a letöltések meghajtóján a media/transmission/watch mappát. Töltsd fel ide a torrentfájlt. Néhány másodperc múlva a torrent megjelenik a Transmission listájában, és elindul. Leállítás és törlés Egy torrentet bármikor megállíthatsz vagy eltávolíthatsz. Jelöld ki a torrentet, és kattints a „Pause” (szünet) gombra. A „Start” (indítás) folytatja. Eltávolításhoz kattints a „Delete” (törlés) gombra, majd a „Remove” (eltávolítás) gombra. A letöltött fájlok megmaradnak. Ha a fájlokat is törölnéd, kattints jobb gombbal a torrentre, és válaszd a „Trash data and remove from list…” (fájlok törlése és eltávolítás) pontot. Lassabb letöltés napközben Beállíthatod, hogy napközben kevésbé terhelje az internetkapcsolatodat. Kattints a felső sávban a menü gombra, majd az „Edit preferences” (beállítások) pontra. Nyisd meg a „Speed” (sebesség) lapot, és az „Alternative Speed Limits” (másodlagos korlát) részben adj meg alacsonyabb értékeket. Jelöld be a „Scheduled times” (ütemezés) jelölőt, és add meg, mikor és mely napokon legyen érvényes. A beállítás azonnal érvényes, külön mentés nem kell. Gyakori kérdések Be kell állítanom a Sonarr és a Radarr kapcsolatát? Nem. A doboz minden meghajtódhoz bekötötte a Transmissiont a Sonarrba és a Radarrba. Amit ők kérnek, az a meghajtó media/transmission/tv vagy media/transmission/movies mappájába kerül. Ha eltávolítom a torrentet, eltűnik a film a könyvtárból is? Nem. A Sonarr és a Radarr ugyanazt a fájlt egy második néven tette a könyvtárba, ez a torrent és a fájljai törlése után is megmarad. Bekapcsolhatom az ideiglenes mappát? Ne tedd. A „Use temporary folder:” (ideiglenes mappa) egyetlen mappa minden meghajtónak, így minden más meghajtóra menő letöltést a végén át kellene másolni. A doboz minden indításkor kikapcsolja. Megváltoztathatom, hová mentsen? Ne tedd. A Transmission csak a media/transmission mappát látja a meghajtóidon, máshová mentett fájl nem a meghajtóra kerül, és a Sonarr meg a Radarr sem találja. Áramszünet után elveszett egy beállításom. Miért? A Transmission a beállításait csak szabályos leálláskor írja ki. Áramszünet után nézd meg a beállításaidat, és ha kell, add meg őket újra. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-install-en.txt
new file mode 100644
index 00000000..2cb16b2f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-install-en.txt
@@ -0,0 +1 @@
+Transmission — Install — Felhom.eu ← Back Transmission — Install A simple torrent downloader that barely uses the machine ~64M RAM Needs a hard drive Full description, screenshots Memory 64 MB / 7479 MB (0%) Current usage (0 MB) Transmission (+64 MB) The app’s data goes to the data drive chosen below. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Sign-in password * cannot be changed after install 👁 Generate The web interface password (username: admin). Generated at install; the box uses it to link the downloader with Sonarr and Radarr. Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-install-hu.txt
new file mode 100644
index 00000000..b7b528cf
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-install-hu.txt
@@ -0,0 +1 @@
+Transmission — Telepítés — Felhom.eu ← Vissza Transmission — Telepítés Egyszerű torrent letöltő, kevés erőforrásból ~64M RAM HDD szükséges Részletes leírás, képernyőképek Memória 64 MB / 7479 MB (0%) Jelenlegi használat (0 MB) Transmission (+64 MB) Az alkalmazás adatai az alább kiválasztott adatmeghajtóra kerülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Belépési jelszó * telepítés után nem módosítható 👁 Generálás A webes felület jelszava (felhasználónév: admin). A telepítéskor készül, és a doboz ezzel köti össze a letöltőt a Sonarrral és a Radarrral. Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-overview-en.txt
new file mode 100644
index 00000000..e5306ffb
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-overview-en.txt
@@ -0,0 +1 @@
+Transmission — Settings — Felhom.eu ← Apps Transmission Simple torrent downloading, on almost no resources ● Running transmission.tester4.test Open ↗ Files ↗ Running Running Restart Stop Signing in to the app For the first sign-in. If you change the password in the app, the old one stays here. Sign-in password Show Address and keys These were created at install time and cannot be changed. Address transmission.tester4.test Storage Külső tárhely (hdd_1)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-overview-hu.txt
new file mode 100644
index 00000000..230aa346
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/page-overview-hu.txt
@@ -0,0 +1 @@
+Transmission — Felhom.eu ← Alkalmazások Transmission Torrent letöltés egyszerűen, alig észrevehető erőforrásból ● Fut transmission.tester4.test Megnyitás ↗ Fájlok ↗ Működés Fut Újraindítás Leállítás Belépés az alkalmazásba Az első bejelentkezéshez. Ha az alkalmazásban megváltoztatod a jelszót, itt a régi marad. Belépési jelszó Megjelenítés Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím transmission.tester4.test Tárhely Külső tárhely (hdd_1)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/record.json b/documentation/audits/catalog-sweep-2026-10-24/transmission/record.json
new file mode 100644
index 00000000..0fa3da6a
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/record.json
@@ -0,0 +1,130 @@
+{
+ "app": "transmission",
+ "sub": "transmission",
+ "fixture": "TransmissionBox",
+ "started": "2026-10-24T14:39:27Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "HDD_PATH",
+ "path",
+ true
+ ],
+ [
+ "TR_ADMIN_PASSWORD",
+ "password",
+ true
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/transmission/install",
+ "hu_len": 987,
+ "en_len": 921,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/transmission/install -> 200 'Transmission — Telepítés — Felhom.eu' | shot /root/shots/transmission-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/transmission/install -> 200 'Transmission — Telepítés — Felhom.eu' | shot /root/shots/transmission-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 20,
+ "front_door": true,
+ "seconds_to_front_door": 20
+ },
+ "stranger": "401",
+ "http_port_80": "301 https://transmission.tester4.test/",
+ "guide": {
+ "path": "/apps/transmission/guide",
+ "hu_len": 4133,
+ "en_len": 3681,
+ "english_words_in_hu": [
+ "and",
+ "open"
+ ],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/transmission",
+ "hu_len": 469,
+ "en_len": 455,
+ "english_words_in_hu": [],
+ "accented_in_en": 3,
+ "same_text": false
+ },
+ "seed": true,
+ "seed_read_now": true,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/transmission/guide -> 200 'Transmission — Felhom.eu' | shot /root/shots/transmission-after-guide-phone-hu.png hscroll=False",
+ "STEP FAILED {'goto': 'https://transmission.tester4.test/', 'until': 'load'}: Error: Page.goto: net::ERR_INVALID_AUTH_CREDENTIALS at https://transmission.tester4"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"5.327514644s\", \"last_run\": \"2026-10-24T14:40:24.827374382Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "seed_read_after_reinstall": false,
+ "restore": {
+ "points": 1,
+ "location": [
+ "location: /backups/restore?flash=flash.restore.started"
+ ],
+ "seconds": 15,
+ "status": "{\"running\": false, \"op\": \"restore\", \"stack\": \"transmission\", \"started_at\": \"2026-10-24T14:41:29.853837603Z\", \"last\": {\"op\": \"restore\", \"stack\": \"transmission\", \"ok\": true, \"message\": \"A(z) transmission: 1 adatkötet visszaállítva — az alkalmazás újraindult.\", \"finished_at\": \"2026-10-24T14:41:44.19114893Z\"}, \"last_recent\": true}",
+ "state": "running"
+ },
+ "seed_read_after_unit_restore": true,
+ "containers": {
+ "transmission": {
+ "limit_mib": 512,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "transmission": 6.2
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 172
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-after-guide-phone-hu.png
new file mode 100644
index 00000000..45012dd8
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-install-install-desktop-en.png
new file mode 100644
index 00000000..ba126976
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-install-install-phone-hu.png
new file mode 100644
index 00000000..2207778b
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/transmission/screens/transmission-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/transmission/walk.log b/documentation/audits/catalog-sweep-2026-10-24/transmission/walk.log
new file mode 100644
index 00000000..0be88c68
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/transmission/walk.log
@@ -0,0 +1,15 @@
+14:39:44Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'TR_ADMIN_PASSWORD']
+14:39:44Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+14:40:04Z [1] deployed, controller state=running, pinned={'transmission': 'lscr.io/linuxserver/transmission:version-4.1.3-r0'}
+14:40:04Z [1] installed: deployed 20 s, front door 20 s
+14:40:04Z transmission: session-set speed-limit-down=529 http=200
+14:40:04Z transmission: torrent-add http=200 ok=True
+14:40:05Z transmission: limit kept, torrent present=True
+14:40:19Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+14:41:05Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'transmission', 'volumes_removed': ['transmission_transmission_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-drives/hdd_
+14:41:14Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['TR_ADMIN_PASSWORD', 'HDD_PATH']
+14:41:29Z transmission: the seeded limit 529 is GONE
+14:41:29Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:41:45Z transmission: limit kept, torrent present=True
+14:42:27Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'transmission', 'volumes_removed': ['transmission_transmission_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-drives/hdd_
+14:42:36Z == transmission done in 172 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma.console.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma.console.txt
new file mode 100644
index 00000000..ba9c8308
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma.console.txt
@@ -0,0 +1,14 @@
+14:05:20Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+14:06:35Z [1] deployed, controller state=running, pinned={'uptime-kuma': 'louislam/uptime-kuma:2.5.5'}
+14:06:35Z gate: status is gated — passed as the household (cookie set)
+14:06:35Z [1] installed: deployed 76 s, front door 76 s
+14:06:36Z uptime-kuma: setup ok=True successAdded
+14:06:36Z uptime-kuma: addStatusPage ok=True successAdded
+14:06:36Z uptime-kuma: readback of the seeded status page http=200 found=True
+14:06:55Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+14:07:42Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'uptime-kuma', 'volumes_removed': ['uptime-kuma_uptime_kuma_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verified': True}, 'messag
+14:09:51Z uptime-kuma: readback of the seeded status page http=404 found=False
+14:09:51Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:10:06Z uptime-kuma: readback of the seeded status page http=200 found=True
+14:10:48Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'uptime-kuma', 'volumes_removed': ['uptime-kuma_uptime_kuma_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás nem tárolt saját ada
+14:10:57Z == uptime-kuma done in 337 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-guide-en.txt
new file mode 100644
index 00000000..d15f5361
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-guide-en.txt
@@ -0,0 +1 @@
+Uptime Kuma — Guide — Felhom.eu ← Apps Uptime Kuma Service monitoring - it tells you when something stops working ● Running status.tester4.test Open ↗ What is it for? Watch whether your websites and services answer HTTP, TCP, DNS, ping and other checks Alerts by e-mail, Telegram, Discord and more A public status page for the people who use them Clear graphs of how much of the time things were up First steps Open status.tester4.test in your browser Create the admin account the first time you open it Add your first monitor (your own website, for example) Set up alerts (e-mail, Telegram and so on) Optional: build a public status page Announce maintenance When you switch something off on purpose, you get no alerts during the maintenance. In the top right corner, open your profile menu and select „Maintenance”. Select „Schedule Maintenance” and fill in its „Title”, for example: new router. In „Affected Monitors”, choose what you are switching off. In „Strategy”, choose „Single Maintenance Window”, set the start and the end, then select „Save”. Fewer false alerts A new monitor alerts at the first failed check, and you can relax that. Open the monitor in the list on the left and select „Edit”. In „Retries”, type 2 or 3. Select „Save”. The monitor then goes to „Pending” first and alerts only if the retries fail too. Sort monitors into groups With many monitors, groups and tags help you find your way. Select „Add New Monitor” and in „Monitor Type” choose „Group”, for example: Home. For the other monitors, on the „Edit” page choose this group in „Monitor Group”. In the „Tags” part you can also give a monitor a coloured tag, for example: family. If one member of the group goes down, the group itself shows as down. Protect your account With two factor authentication you need your phone as well as your password to sign in. In your profile menu select „Settings”, then the „Security” page. Select „2FA Settings”, type your password into „Current Password” and select „Enable 2FA”. Scan the QR code with the authenticator app on your phone, type the six-digit code and select „Verify Token”. If the code is right, select „Save”. Frequently asked questions Does Uptime Kuma tell me when the box itself goes down? It cannot: Uptime Kuma runs on the box, so when the box or the home internet goes down, it goes down too. It watches other devices and websites. How do I stop a monitor for a while? Open the monitor, select „Pause” and confirm. To watch it again, select „Resume”. Can I switch off the sign-in? Do not. After „Disable Auth” on the „Security” page, anyone who knows the status.tester4.test address gets in and can change everything. How long does it keep the history? 365 days by default. On the „Monitor History” page of „Settings” you can make it shorter to use less space. Why is some text in English? Uptime Kuma follows your browser's language and shows English where a translation is missing. You can change it in „Language” on the „Appearance” page of „Settings”. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-guide-hu.txt
new file mode 100644
index 00000000..c789cd2d
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-guide-hu.txt
@@ -0,0 +1 @@
+Uptime Kuma — Felhom.eu ← Alkalmazások Uptime Kuma Szolgáltatás monitoring - értesítés ha valami nem működik ● Fut status.tester4.test Megnyitás ↗ Mire használható? Weboldalak és szolgáltatások elérhetőségének figyelése HTTP, TCP, DNS, ping és egyéb protokollok támogatása Értesítések emailben, Telegramon, Discord-on, stb. Nyilvános státusz oldal a felhasználóknak Szép grafikonok a rendelkezésre állásról Első lépések Nyisd meg a status.tester4.test címet a böngészőben Hozd létre az admin fiókot az első megnyitáskor Add hozzá az első monitort (pl. a saját weboldalad) Állíts be értesítéseket (email, Telegram, stb.) Opcionálisan: hozz létre egy nyilvános státusz oldalt Karbantartás bejelentése Ha szándékosan kikapcsolsz valamit, a karbantartás idejére nem kapsz riasztást. A jobb felső sarokban nyisd meg a profilod menüjét, és kattints a „Karbantartás” pontra. Kattints a „Karbantartás ütemezése” gombra, és töltsd ki a „Cím” mezőt, például: router csere. Az „Érintett monitorok” mezőben válaszd ki, mit kapcsolsz ki. A „Stratégia” mezőben válaszd az „Egyetlen karbantartási ablak” lehetőséget, add meg a kezdést és a véget, majd kattints a „Mentés” gombra. Kevesebb téves riasztás Egy új monitor már az első sikertelen próbánál riaszt, ezt lazíthatod. Nyisd meg a monitort a bal oldali listában, és kattints a „Szerkesztés” gombra. Az „Újrapróbálkozás” mezőbe írj 2-t vagy 3-at. Kattints a „Mentés” gombra. A monitor ezután „Függőben” állapotba kerül, és csak akkor riaszt, ha az újrapróbálkozások is sikertelenek. Monitorok csoportba rendezése Sok monitornál a csoport és a címke segít eligazodni. Kattints az „Új monitor hozzáadása” gombra, és a „Monitor típusa” mezőben válaszd a „Csoport” lehetőséget, például: Otthon. A többi monitornál a „Szerkesztés” oldalon a „Monitor csoport” mezőben válaszd ki ezt a csoportot. A „Címkék” résznél színes címkét is adhatsz egy monitornak, például: család. Ha a csoport egy tagja leáll, maga a csoport is leállást mutat. A fiókod védelme A kétfaktoros hitelesítéssel a jelszó mellett a telefonod is kell a belépéshez. A profilod menüjében kattints a „Beállítások” pontra, majd a „Biztonság” lapra. Kattints a „2FA beállítások” gombra, írd be a „Jelenlegi jelszó” mezőbe a jelszavad, és kattints a „2FA engedélyezése” gombra. Olvasd be a QR-kódot a telefonod hitelesítő appjával, írd be a hatjegyű kódot, és kattints a „Token ellenőrzése” gombra. Ha a kód jó, kattints a „Mentés” gombra. Gyakori kérdések Szól az Uptime Kuma, ha maga a doboz áll le? Nem tud: az Uptime Kuma a dobozon fut, ezért ha a doboz vagy az otthoni internet leáll, vele együtt áll le. Más eszközöket és weboldalakat figyel. Hogyan állítok le egy monitort egy időre? Nyisd meg a monitort, kattints a „Szünet” gombra, és erősítsd meg. Ha újra figyelnéd, kattints a „Folytatás” gombra. Kikapcsolhatom a bejelentkezést? Ne tedd. A „Biztonság” lapon a „Hitelesítés tiltása” után bárki, aki ismeri a status.tester4.test címet, belép és mindent átírhat. Meddig őrzi az előzményeket? Alapból 365 napig. A „Beállítások” „Vizsgálatok előzményei” lapján ezt rövidebbre is veheted, ha kevesebb helyet használnál. Miért angol egy-egy felirat? Az Uptime Kuma a böngésződ nyelvét követi, és ahol nincs magyar fordítás, angolul ír. A nyelvet a „Beállítások” „Megjelenés” lapján a „Nyelv” mezőben válthatod. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-install-en.txt
new file mode 100644
index 00000000..e9e83711
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-install-en.txt
@@ -0,0 +1 @@
+Uptime Kuma — Install — Felhom.eu ← Back Uptime Kuma — Install Watch your services and websites ~150M RAM Full description, screenshots Memory 150 MB / 7479 MB (2%) Current usage (0 MB) Uptime Kuma (+150 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-install-hu.txt
new file mode 100644
index 00000000..9b99a357
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-install-hu.txt
@@ -0,0 +1 @@
+Uptime Kuma — Telepítés — Felhom.eu ← Vissza Uptime Kuma — Telepítés Szolgáltatás és weboldal monitoring ~150M RAM Részletes leírás, képernyőképek Memória 150 MB / 7479 MB (2%) Jelenlegi használat (0 MB) Uptime Kuma (+150 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-overview-en.txt
new file mode 100644
index 00000000..91b450b4
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-overview-en.txt
@@ -0,0 +1 @@
+Uptime Kuma — Settings — Felhom.eu ← Apps Uptime Kuma Service monitoring - it tells you when something stops working ● Running status.tester4.test Open ↗ Running Running Restart Stop First setup Right now only you can reach this app, while you are signed in to the dashboard. So nobody else can create its first admin account. Open it and finish the first setup. When you are done, press this button. Until then, phone apps and the rest of your family cannot reach it. Done, I set it up Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Address and keys These were created at install time and cannot be changed. Address status.tester4.test
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-overview-hu.txt
new file mode 100644
index 00000000..5ec529f0
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/page-overview-hu.txt
@@ -0,0 +1 @@
+Uptime Kuma — Felhom.eu ← Alkalmazások Uptime Kuma Szolgáltatás monitoring - értesítés ha valami nem működik ● Fut status.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Első beállítás Most csak te éred el ezt az alkalmazást, amíg be vagy jelentkezve a vezérlőpultba. Így más nem hozhatja létre az első admin fiókot. Nyisd meg, és végezd el az első beállítást. Ha kész, nyomd meg ezt a gombot. Addig a telefonos alkalmazások és a család többi tagja nem éri el. Kész, beállítottam Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím status.tester4.test
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/record.json b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/record.json
new file mode 100644
index 00000000..0ea1d002
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/record.json
@@ -0,0 +1,117 @@
+{
+ "app": "uptime-kuma",
+ "sub": "status",
+ "fixture": "UptimeKuma",
+ "started": "2026-10-24T14:05:04Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/uptime-kuma/install",
+ "hu_len": 874,
+ "en_len": 790,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/uptime-kuma/install -> 200 'Uptime Kuma — Telepítés — Felhom.eu' | shot /root/shots/uptime-kuma-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/uptime-kuma/install -> 200 'Uptime Kuma — Telepítés — Felhom.eu' | shot /root/shots/uptime-kuma-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 76,
+ "front_door": true,
+ "seconds_to_front_door": 76
+ },
+ "stranger": "302 https://felhom.tester4.test/__gate/start?rd=https%3A%2F%2Fstatus.tester4.test%2F",
+ "http_port_80": "301 https://status.tester4.test/",
+ "guide": {
+ "path": "/apps/uptime-kuma/guide",
+ "hu_len": 3350,
+ "en_len": 3036,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/uptime-kuma",
+ "hu_len": 716,
+ "en_len": 731,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": true,
+ "seed_read_now": true,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/uptime-kuma/guide -> 200 'Uptime Kuma — Felhom.eu' | shot /root/shots/uptime-kuma-after-guide-phone-hu.png hscroll=False",
+ "goto https://status.tester4.test/dashboard -> 200 'Uptime Kuma - Login' | shot /root/shots/uptime-kuma-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"5.664357159s\", \"last_run\": \"2026-10-24T14:07:01.396839236Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "seed_read_after_reinstall": false,
+ "restore": {
+ "points": 1,
+ "location": [
+ "location: /backups/restore?flash=flash.restore.started"
+ ],
+ "seconds": 15,
+ "status": "{\"running\": false, \"op\": \"restore\", \"stack\": \"uptime-kuma\", \"started_at\": \"2026-10-24T14:09:51.366636218Z\", \"last\": {\"op\": \"restore\", \"stack\": \"uptime-kuma\", \"ok\": true, \"message\": \"A(z) uptime-kuma: 1 adatkötet visszaállítva — az alkalmazás újraindult.\", \"finished_at\": \"2026-10-24T14:10:05.630465442Z\"}, \"last_recent\": true}",
+ "state": "running"
+ },
+ "seed_read_after_unit_restore": true,
+ "containers": {
+ "uptime-kuma": {
+ "limit_mib": 384,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "uptime-kuma": 120.1
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 337
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-after-front-desktop-hu.png
new file mode 100644
index 00000000..8bfce0dd
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-after-guide-phone-hu.png
new file mode 100644
index 00000000..508b2c83
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-install-install-desktop-en.png
new file mode 100644
index 00000000..1b730175
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-install-install-phone-hu.png
new file mode 100644
index 00000000..0331ceba
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/screens/uptime-kuma-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/walk.log b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/walk.log
new file mode 100644
index 00000000..ba9c8308
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/uptime-kuma/walk.log
@@ -0,0 +1,14 @@
+14:05:20Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+14:06:35Z [1] deployed, controller state=running, pinned={'uptime-kuma': 'louislam/uptime-kuma:2.5.5'}
+14:06:35Z gate: status is gated — passed as the household (cookie set)
+14:06:35Z [1] installed: deployed 76 s, front door 76 s
+14:06:36Z uptime-kuma: setup ok=True successAdded
+14:06:36Z uptime-kuma: addStatusPage ok=True successAdded
+14:06:36Z uptime-kuma: readback of the seeded status page http=200 found=True
+14:06:55Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+14:07:42Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'uptime-kuma', 'volumes_removed': ['uptime-kuma_uptime_kuma_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verified': True}, 'messag
+14:09:51Z uptime-kuma: readback of the seeded status page http=404 found=False
+14:09:51Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:10:06Z uptime-kuma: readback of the seeded status page http=200 found=True
+14:10:48Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'uptime-kuma', 'volumes_removed': ['uptime-kuma_uptime_kuma_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás nem tárolt saját ada
+14:10:57Z == uptime-kuma done in 337 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden.console.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden.console.txt
new file mode 100644
index 00000000..fe3bb9ba
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden.console.txt
@@ -0,0 +1,9 @@
+21:46:40Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+21:47:05Z [1] deployed, controller state=running, pinned={'vaultwarden': 'vaultwarden/server:1.37.4-alpine'}
+21:47:05Z [1] installed: deployed 25 s, front door 25 s
+21:47:05Z vaultwarden: self-registration http=404 (closed by design, R-512 — 400 expected)
+21:47:08Z vaultwarden: POST /identity/accounts/register -> 404 (sign-up closed by design); the admin invite was NOT tried: bench — not the bench venue (the box walk never holds an admin secret); box — the box is not on the drill catalog — not a test run
+21:47:33Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+21:48:15Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'vaultwarden', 'volumes_removed': ['vaultwarden_vaultwarden_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verified': True}, 'messag
+21:49:18Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'vaultwarden', 'volumes_removed': ['vaultwarden_vaultwarden_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás nem tárolt saját ada
+21:49:27Z == vaultwarden done in 167 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-guide-en.txt
new file mode 100644
index 00000000..828ce560
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-guide-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Guide — Felhom.eu ← Apps Vaultwarden A password manager - Bitwarden-compatible, on your own server ● Running vault.tester4.test Open ↗ What is it for? Keep your passwords safely and let them fill themselves in Every Bitwarden client works (browser, phone, desktop) Share a password with the household inside an organisation Keep two-factor (TOTP) codes Keep secure notes and card details First steps Open vault.tester4.test/admin and sign in with the admin panel token (Settings -> Automatically generated values) On the "Users" tab, use "Invite User" to invite your own and the household's e-mail addresses - unless you allowed sign-ups at the installation (not recommended), only an invited address can sign up Open vault.tester4.test, choose "Create account" with the invited address, and set a strong master password Install the Bitwarden extension in your browser Install the Bitwarden app on your phone Import the passwords you already have (Chrome, Firefox, LastPass and so on) Connect the Bitwarden extension and app to your box By default the Bitwarden apps look for Bitwarden's own server, so you enter your box's address once. Open the Bitwarden extension or app and go to the sign-in screen. In the server choice, pick the self-hosted server. As the server address, type vault.tester4.test and save it. Sign in with your e-mail address and your master password. Save a new password Whatever you put into the vault, the extension and the app see too, and fill in for you. On vault.tester4.test, in the „Vaults” menu, select „New” and choose „Login”. Fill in the „Item name”, „Username” and „Password” fields. In the „Website” field, type the address of the site: the extension offers to fill in on that site. Select „Save”. Turn on two-step login Besides the master password, a code from your phone is needed too, so a stolen password alone is not enough. In the menu on the left, open „Settings”, then „Security”. Choose the „Two-step login” tab. In the „Authenticator app” row, select „Manage” and follow the steps in the window. Then select „View recovery code” and write the code down on paper. Find weak passwords Vaultwarden shows which of your passwords are weak and which you use in more than one place. In the menu on the left, open „Reports”. Choose „Weak passwords” or „Reused passwords”. Change the password on the site concerned, then change it in the vault too. Frequently asked questions I forgot my master password. What can I do? Nobody is able to reset it, not even the box: your master password encrypts your vault. Write it down and keep it somewhere safe. Why can my family member not sign up? Signing up is closed by default. Invite them in the admin panel as the first steps say, or allow sign-ups on the dashboard, on Vaultwarden's „Settings” tab. Can I share a password with the family? Yes, with an organisation. In the filter of the „Vaults” page, select „New organization”, then invite the family on the organisation's „Members” page. Do I need an account with Bitwarden? No. Vaultwarden is a server running on your box, and the Bitwarden apps and extensions connect to it. Where are my passwords, and are they backed up? On the box, encrypted. For their backup, look at the „Data and backup” tab of Vaultwarden. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-guide-hu.txt
new file mode 100644
index 00000000..7d382b66
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-guide-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Felhom.eu ← Alkalmazások Vaultwarden Jelszókezelő - Bitwarden kompatibilis, a saját szerveren ● Fut vault.tester4.test Megnyitás ↗ Mire használható? Jelszavak biztonságos tárolása és automatikus kitöltése Bitwarden kliensek teljes kompatibilitása (böngésző, mobil, asztali) Jelszavak megosztása családtagokkal szervezeten belül Kétfaktoros hitelesítés (TOTP) kódok tárolása Biztonságos jegyzetek és bankkártya adatok tárolása Első lépések Nyisd meg a vault.tester4.test/admin címet, és lépj be az admin panel tokenjével (Beállítások → Automatikusan generált értékek) A „Users" fülön az „Invite User" mezőben hívd meg a saját és a családtagok e-mail címét. Ha a telepítéskor nem engedélyezted a regisztrációt (ez az ajánlott), csak meghívott cím nyithat fiókot Nyisd meg a vault.tester4.test címet, válaszd a „Create account" lehetőséget a meghívott címmel, és adj meg erős mesterjelszót Telepítsd a Bitwarden bővítményt a böngésződbe Telepítsd a Bitwarden alkalmazást a telefonodra Importáld a meglévő jelszavaidat (Chrome, Firefox, LastPass, stb.) A Bitwarden bővítmény és app összekötése a dobozzal A Bitwarden appok alapból a Bitwarden saját szerverét keresik, ezért egyszer meg kell adnod a dobozod címét. Nyisd meg a Bitwarden bővítményt vagy appot, és menj a bejelentkező képernyőre. A szerverválasztóban válaszd a saját üzemeltetésű (self-hosted) szervert. Szervercímnek írd be: vault.tester4.test, és mentsd el. Jelentkezz be az e-mail címeddel és a mesterjelszavaddal. Új jelszó mentése Amit a széfbe teszel, azt a bővítmény és az app is látja, és kitölti helyetted. A vault.tester4.test oldalon a „Széfek” menüben kattints az „Új” gombra, és válaszd a „Bejelentkezés” pontot. Töltsd ki az „Elem neve”, a „Felhasználónév” és a „Jelszó” mezőt. A „Webhely” mezőbe írd be az oldal címét: a bővítmény ezen az oldalon ajánlja fel a kitöltést. Kattints a „Mentés” gombra. Kétlépcsős bejelentkezés bekapcsolása A mesterjelszó mellé egy telefonos kód is kell, így egy ellopott jelszó önmagában kevés. A bal oldali menüben nyisd meg a „Beállítások”, majd a „Biztonság” pontot. Válaszd a „Kétlépcsős bejelentkezés” lapot. A „Hitelesítő alkalmazás” sorában kattints a „Kezelés” gombra, és kövesd az ablak lépéseit. Utána kattints a „Helyreállító kód megtekintése” gombra, és írd le a kódot papírra. Gyenge jelszavak keresése A Vaultwarden megmutatja, melyik jelszavad gyenge, és melyiket használod több helyen. A bal oldali menüben nyisd meg a „Jelentések” pontot. Válaszd a „Gyenge jelszavak jelentés” vagy az „Újrahasznált jelszavak jelentés” lehetőséget. Cseréld le a jelszót az érintett oldalon, majd írd át a széfben is. Gyakori kérdések Elfelejtettem a mesterjelszót. Mit tehetek? Senki nem tudja visszaállítani, a doboz sem: a széfedet a mesterjelszó titkosítja. Írd le, és tartsd biztos helyen. Miért nem tud regisztrálni a családtagom? A regisztráció alapból le van zárva. Hívd meg az admin panelen az első lépések szerint, vagy a vezérlőpulton, a Vaultwarden „Beállítások” fülén engedélyezd a regisztrációt. Megoszthatok jelszót a családdal? Igen, egy szervezettel. A „Széfek” oldal szűrőjében kattints az „Új szervezet” pontra, majd a szervezet „Tagok” oldalán hívd meg a családtagokat. Kell fiókot nyitnom a Bitwardennél? Nem. A Vaultwarden a te dobozodon futó szerver, a Bitwarden appok és bővítmények ehhez kapcsolódnak. Hol vannak a jelszavaim, és van róluk mentés? A dobozon, titkosítva. A mentésükről a Vaultwarden „Adatok és mentés” fülén tájékozódhatsz. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-install-en.txt
new file mode 100644
index 00000000..4d48c5c0
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-install-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Install — Felhom.eu ← Back Vaultwarden — Install A password manager (Bitwarden-compatible) ~50M RAM Full description, screenshots Memory 50 MB / 7479 MB (0%) Current usage (0 MB) Vaultwarden (+50 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Admin panel token Generated automatically Show Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Allow sign-ups No - by invitation only (recommended) Yes - anybody who knows the address can sign up Closed by default: you invite the household from the admin panel (see First steps). With sign-ups open, anybody who guesses the address can sign up. Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-install-hu.txt
new file mode 100644
index 00000000..4bfc6763
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-install-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Telepítés — Felhom.eu ← Vissza Vaultwarden — Telepítés Jelszókezelő (Bitwarden-kompatibilis) ~50M RAM Részletes leírás, képernyőképek Memória 50 MB / 7479 MB (0%) Jelenlegi használat (0 MB) Vaultwarden (+50 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Admin panel token Automatikusan generálva Megjelenítés Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Regisztráció engedélyezése Nem – csak meghívással (ajánlott) Igen – bárki regisztrálhat, aki ismeri a címet Alapból lezárva: a család tagjait az admin panelen hívod meg (lásd Első lépések). Nyitott regisztrációval bárki fiókot nyithat, aki kitalálja a címet. Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-overview-en.txt
new file mode 100644
index 00000000..37516c26
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-overview-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Settings — Felhom.eu ← Apps Vaultwarden A password manager - Bitwarden-compatible, on your own server ● Running vault.tester4.test Open ↗ Running Running Restart Stop Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Sending e-mail This app can send e-mail (for example password resets, invitations) through Felhom, without setting up a separate provider. The sender address: vaultwarden@felhom.eu . App e-mail is turned off globally right now. Turn it on on the Settings page for it to work here too. Allow sending e-mail for this app Save Saving restarts the app. Address and keys These were created at install time and cannot be changed. Address vault.tester4.test Admin panel token Show Allow sign-ups No - by invitation only (recommended)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-overview-hu.txt
new file mode 100644
index 00000000..6d1c7779
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/page-overview-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Felhom.eu ← Alkalmazások Vaultwarden Jelszókezelő - Bitwarden kompatibilis, a saját szerveren ● Fut vault.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Email-küldés Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, külön szolgáltató beállítása nélkül. A feladó címe: vaultwarden@felhom.eu . Az alkalmazás-email jelenleg ki van kapcsolva globálisan. Kapcsold be a Beállítások oldalon, hogy itt is működjön. Email-küldés engedélyezése ennél az alkalmazásnál Mentés A mentés újraindítja az alkalmazást. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím vault.tester4.test Admin panel token Megjelenítés Regisztráció engedélyezése Nem – csak meghívással (ajánlott)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/record.json b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/record.json
new file mode 100644
index 00000000..11f7416a
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/record.json
@@ -0,0 +1,118 @@
+{
+ "app": "vaultwarden",
+ "sub": "vault",
+ "fixture": "Vaultwarden",
+ "started": "2026-10-24T21:46:19Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "ADMIN_TOKEN",
+ "secret",
+ false
+ ],
+ [
+ "SIGNUPS_ALLOWED",
+ "select",
+ false
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/vaultwarden/install",
+ "hu_len": 1187,
+ "en_len": 1093,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/vaultwarden/install -> 200 'Vaultwarden — Telepítés — Felhom.eu' | shot /root/shots/vaultwarden-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/vaultwarden/install -> 200 'Vaultwarden — Telepítés — Felhom.eu' | shot /root/shots/vaultwarden-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 25,
+ "front_door": true,
+ "seconds_to_front_door": 25
+ },
+ "stranger": "200",
+ "http_port_80": "301 https://vault.tester4.test/",
+ "guide": {
+ "path": "/apps/vaultwarden/guide",
+ "hu_len": 3522,
+ "en_len": 3304,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/vaultwarden",
+ "hu_len": 889,
+ "en_len": 849,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": false,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/vaultwarden/guide -> 200 'Vaultwarden — Felhom.eu' | shot /root/shots/vaultwarden-after-guide-phone-hu.png hscroll=False",
+ "goto https://vault.tester4.test/ -> 200 'Vaultwarden Web' | shot /root/shots/vaultwarden-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"1.635660342s\", \"last_run\": \"2026-10-24T21:47:34.786906087Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "containers": {
+ "vaultwarden": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "vaultwarden": 38.3
+ },
+ "mem_anon_peak_mib": {
+ "vaultwarden": 36.9
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 167
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-guide-en.txt
new file mode 100644
index 00000000..828ce560
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-guide-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Guide — Felhom.eu ← Apps Vaultwarden A password manager - Bitwarden-compatible, on your own server ● Running vault.tester4.test Open ↗ What is it for? Keep your passwords safely and let them fill themselves in Every Bitwarden client works (browser, phone, desktop) Share a password with the household inside an organisation Keep two-factor (TOTP) codes Keep secure notes and card details First steps Open vault.tester4.test/admin and sign in with the admin panel token (Settings -> Automatically generated values) On the "Users" tab, use "Invite User" to invite your own and the household's e-mail addresses - unless you allowed sign-ups at the installation (not recommended), only an invited address can sign up Open vault.tester4.test, choose "Create account" with the invited address, and set a strong master password Install the Bitwarden extension in your browser Install the Bitwarden app on your phone Import the passwords you already have (Chrome, Firefox, LastPass and so on) Connect the Bitwarden extension and app to your box By default the Bitwarden apps look for Bitwarden's own server, so you enter your box's address once. Open the Bitwarden extension or app and go to the sign-in screen. In the server choice, pick the self-hosted server. As the server address, type vault.tester4.test and save it. Sign in with your e-mail address and your master password. Save a new password Whatever you put into the vault, the extension and the app see too, and fill in for you. On vault.tester4.test, in the „Vaults” menu, select „New” and choose „Login”. Fill in the „Item name”, „Username” and „Password” fields. In the „Website” field, type the address of the site: the extension offers to fill in on that site. Select „Save”. Turn on two-step login Besides the master password, a code from your phone is needed too, so a stolen password alone is not enough. In the menu on the left, open „Settings”, then „Security”. Choose the „Two-step login” tab. In the „Authenticator app” row, select „Manage” and follow the steps in the window. Then select „View recovery code” and write the code down on paper. Find weak passwords Vaultwarden shows which of your passwords are weak and which you use in more than one place. In the menu on the left, open „Reports”. Choose „Weak passwords” or „Reused passwords”. Change the password on the site concerned, then change it in the vault too. Frequently asked questions I forgot my master password. What can I do? Nobody is able to reset it, not even the box: your master password encrypts your vault. Write it down and keep it somewhere safe. Why can my family member not sign up? Signing up is closed by default. Invite them in the admin panel as the first steps say, or allow sign-ups on the dashboard, on Vaultwarden's „Settings” tab. Can I share a password with the family? Yes, with an organisation. In the filter of the „Vaults” page, select „New organization”, then invite the family on the organisation's „Members” page. Do I need an account with Bitwarden? No. Vaultwarden is a server running on your box, and the Bitwarden apps and extensions connect to it. Where are my passwords, and are they backed up? On the box, encrypted. For their backup, look at the „Data and backup” tab of Vaultwarden. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-guide-hu.txt
new file mode 100644
index 00000000..7d382b66
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-guide-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Felhom.eu ← Alkalmazások Vaultwarden Jelszókezelő - Bitwarden kompatibilis, a saját szerveren ● Fut vault.tester4.test Megnyitás ↗ Mire használható? Jelszavak biztonságos tárolása és automatikus kitöltése Bitwarden kliensek teljes kompatibilitása (böngésző, mobil, asztali) Jelszavak megosztása családtagokkal szervezeten belül Kétfaktoros hitelesítés (TOTP) kódok tárolása Biztonságos jegyzetek és bankkártya adatok tárolása Első lépések Nyisd meg a vault.tester4.test/admin címet, és lépj be az admin panel tokenjével (Beállítások → Automatikusan generált értékek) A „Users" fülön az „Invite User" mezőben hívd meg a saját és a családtagok e-mail címét. Ha a telepítéskor nem engedélyezted a regisztrációt (ez az ajánlott), csak meghívott cím nyithat fiókot Nyisd meg a vault.tester4.test címet, válaszd a „Create account" lehetőséget a meghívott címmel, és adj meg erős mesterjelszót Telepítsd a Bitwarden bővítményt a böngésződbe Telepítsd a Bitwarden alkalmazást a telefonodra Importáld a meglévő jelszavaidat (Chrome, Firefox, LastPass, stb.) A Bitwarden bővítmény és app összekötése a dobozzal A Bitwarden appok alapból a Bitwarden saját szerverét keresik, ezért egyszer meg kell adnod a dobozod címét. Nyisd meg a Bitwarden bővítményt vagy appot, és menj a bejelentkező képernyőre. A szerverválasztóban válaszd a saját üzemeltetésű (self-hosted) szervert. Szervercímnek írd be: vault.tester4.test, és mentsd el. Jelentkezz be az e-mail címeddel és a mesterjelszavaddal. Új jelszó mentése Amit a széfbe teszel, azt a bővítmény és az app is látja, és kitölti helyetted. A vault.tester4.test oldalon a „Széfek” menüben kattints az „Új” gombra, és válaszd a „Bejelentkezés” pontot. Töltsd ki az „Elem neve”, a „Felhasználónév” és a „Jelszó” mezőt. A „Webhely” mezőbe írd be az oldal címét: a bővítmény ezen az oldalon ajánlja fel a kitöltést. Kattints a „Mentés” gombra. Kétlépcsős bejelentkezés bekapcsolása A mesterjelszó mellé egy telefonos kód is kell, így egy ellopott jelszó önmagában kevés. A bal oldali menüben nyisd meg a „Beállítások”, majd a „Biztonság” pontot. Válaszd a „Kétlépcsős bejelentkezés” lapot. A „Hitelesítő alkalmazás” sorában kattints a „Kezelés” gombra, és kövesd az ablak lépéseit. Utána kattints a „Helyreállító kód megtekintése” gombra, és írd le a kódot papírra. Gyenge jelszavak keresése A Vaultwarden megmutatja, melyik jelszavad gyenge, és melyiket használod több helyen. A bal oldali menüben nyisd meg a „Jelentések” pontot. Válaszd a „Gyenge jelszavak jelentés” vagy az „Újrahasznált jelszavak jelentés” lehetőséget. Cseréld le a jelszót az érintett oldalon, majd írd át a széfben is. Gyakori kérdések Elfelejtettem a mesterjelszót. Mit tehetek? Senki nem tudja visszaállítani, a doboz sem: a széfedet a mesterjelszó titkosítja. Írd le, és tartsd biztos helyen. Miért nem tud regisztrálni a családtagom? A regisztráció alapból le van zárva. Hívd meg az admin panelen az első lépések szerint, vagy a vezérlőpulton, a Vaultwarden „Beállítások” fülén engedélyezd a regisztrációt. Megoszthatok jelszót a családdal? Igen, egy szervezettel. A „Széfek” oldal szűrőjében kattints az „Új szervezet” pontra, majd a szervezet „Tagok” oldalán hívd meg a családtagokat. Kell fiókot nyitnom a Bitwardennél? Nem. A Vaultwarden a te dobozodon futó szerver, a Bitwarden appok és bővítmények ehhez kapcsolódnak. Hol vannak a jelszavaim, és van róluk mentés? A dobozon, titkosítva. A mentésükről a Vaultwarden „Adatok és mentés” fülén tájékozódhatsz. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-install-en.txt
new file mode 100644
index 00000000..4d48c5c0
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-install-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Install — Felhom.eu ← Back Vaultwarden — Install A password manager (Bitwarden-compatible) ~50M RAM Full description, screenshots Memory 50 MB / 7479 MB (0%) Current usage (0 MB) Vaultwarden (+50 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Admin panel token Generated automatically Show Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Allow sign-ups No - by invitation only (recommended) Yes - anybody who knows the address can sign up Closed by default: you invite the household from the admin panel (see First steps). With sign-ups open, anybody who guesses the address can sign up. Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-install-hu.txt
new file mode 100644
index 00000000..4bfc6763
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-install-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Telepítés — Felhom.eu ← Vissza Vaultwarden — Telepítés Jelszókezelő (Bitwarden-kompatibilis) ~50M RAM Részletes leírás, képernyőképek Memória 50 MB / 7479 MB (0%) Jelenlegi használat (0 MB) Vaultwarden (+50 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Admin panel token Automatikusan generálva Megjelenítés Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Regisztráció engedélyezése Nem – csak meghívással (ajánlott) Igen – bárki regisztrálhat, aki ismeri a címet Alapból lezárva: a család tagjait az admin panelen hívod meg (lásd Első lépések). Nyitott regisztrációval bárki fiókot nyithat, aki kitalálja a címet. Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-overview-en.txt
new file mode 100644
index 00000000..37516c26
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-overview-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Settings — Felhom.eu ← Apps Vaultwarden A password manager - Bitwarden-compatible, on your own server ● Running vault.tester4.test Open ↗ Running Running Restart Stop Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Sending e-mail This app can send e-mail (for example password resets, invitations) through Felhom, without setting up a separate provider. The sender address: vaultwarden@felhom.eu . App e-mail is turned off globally right now. Turn it on on the Settings page for it to work here too. Allow sending e-mail for this app Save Saving restarts the app. Address and keys These were created at install time and cannot be changed. Address vault.tester4.test Admin panel token Show Allow sign-ups No - by invitation only (recommended)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-overview-hu.txt
new file mode 100644
index 00000000..6d1c7779
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/page-overview-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Felhom.eu ← Alkalmazások Vaultwarden Jelszókezelő - Bitwarden kompatibilis, a saját szerveren ● Fut vault.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Email-küldés Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, külön szolgáltató beállítása nélkül. A feladó címe: vaultwarden@felhom.eu . Az alkalmazás-email jelenleg ki van kapcsolva globálisan. Kapcsold be a Beállítások oldalon, hogy itt is működjön. Email-küldés engedélyezése ennél az alkalmazásnál Mentés A mentés újraindítja az alkalmazást. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím vault.tester4.test Admin panel token Megjelenítés Regisztráció engedélyezése Nem – csak meghívással (ajánlott)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/record.json b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/record.json
new file mode 100644
index 00000000..43c6ccf1
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/record.json
@@ -0,0 +1,115 @@
+{
+ "app": "vaultwarden",
+ "sub": "vault",
+ "fixture": "Vaultwarden",
+ "started": "2026-10-24T13:32:05Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "ADMIN_TOKEN",
+ "secret",
+ false
+ ],
+ [
+ "SIGNUPS_ALLOWED",
+ "select",
+ false
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/vaultwarden/install",
+ "hu_len": 1187,
+ "en_len": 1093,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/vaultwarden/install -> 200 'Vaultwarden — Telepítés — Felhom.eu' | shot /root/shots/vaultwarden-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/vaultwarden/install -> 200 'Vaultwarden — Telepítés — Felhom.eu' | shot /root/shots/vaultwarden-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 25,
+ "front_door": true,
+ "seconds_to_front_door": 25
+ },
+ "stranger": "200",
+ "http_port_80": "301 https://vault.tester4.test/",
+ "guide": {
+ "path": "/apps/vaultwarden/guide",
+ "hu_len": 3522,
+ "en_len": 3304,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/vaultwarden",
+ "hu_len": 889,
+ "en_len": 849,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": false,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/vaultwarden/guide -> 200 'Vaultwarden — Felhom.eu' | shot /root/shots/vaultwarden-after-guide-phone-hu.png hscroll=False",
+ "goto https://vault.tester4.test/ -> 200 'Vaultwarden Web' | shot /root/shots/vaultwarden-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"1.228124005s\", \"last_run\": \"2026-10-24T13:33:07.631034942Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "containers": {
+ "vaultwarden": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "vaultwarden": 38.5
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 159
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-after-front-desktop-hu.png
new file mode 100644
index 00000000..17edf490
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-after-guide-phone-hu.png
new file mode 100644
index 00000000..80328476
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-install-install-desktop-en.png
new file mode 100644
index 00000000..519dab88
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-install-install-phone-hu.png
new file mode 100644
index 00000000..6095cb3a
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/screens/vaultwarden-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/walk.log b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/walk.log
new file mode 100644
index 00000000..495584ec
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-drill-pre/walk.log
@@ -0,0 +1,9 @@
+13:32:21Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+13:32:46Z [1] deployed, controller state=running, pinned={'vaultwarden': 'vaultwarden/server:1.37.4-alpine'}
+13:32:46Z [1] installed: deployed 25 s, front door 25 s
+13:32:46Z vaultwarden: self-registration http=404 (closed by design, R-512 — 400 expected)
+13:32:46Z vaultwarden: POST /identity/accounts/register -> 404 (sign-up closed by design); the admin invite was NOT tried: bench — not the bench venue (the box walk never holds an admin secret); box — FELHOM_BOX_ADMIN_SEED=1 is not set for this run
+13:33:06Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+13:33:48Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'vaultwarden', 'volumes_removed': ['vaultwarden_vaultwarden_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verified': True}, 'messag
+13:34:51Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'vaultwarden', 'volumes_removed': ['vaultwarden_vaultwarden_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás nem tárolt saját ada
+13:35:00Z == vaultwarden done in 159 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-guide-en.txt
new file mode 100644
index 00000000..828ce560
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-guide-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Guide — Felhom.eu ← Apps Vaultwarden A password manager - Bitwarden-compatible, on your own server ● Running vault.tester4.test Open ↗ What is it for? Keep your passwords safely and let them fill themselves in Every Bitwarden client works (browser, phone, desktop) Share a password with the household inside an organisation Keep two-factor (TOTP) codes Keep secure notes and card details First steps Open vault.tester4.test/admin and sign in with the admin panel token (Settings -> Automatically generated values) On the "Users" tab, use "Invite User" to invite your own and the household's e-mail addresses - unless you allowed sign-ups at the installation (not recommended), only an invited address can sign up Open vault.tester4.test, choose "Create account" with the invited address, and set a strong master password Install the Bitwarden extension in your browser Install the Bitwarden app on your phone Import the passwords you already have (Chrome, Firefox, LastPass and so on) Connect the Bitwarden extension and app to your box By default the Bitwarden apps look for Bitwarden's own server, so you enter your box's address once. Open the Bitwarden extension or app and go to the sign-in screen. In the server choice, pick the self-hosted server. As the server address, type vault.tester4.test and save it. Sign in with your e-mail address and your master password. Save a new password Whatever you put into the vault, the extension and the app see too, and fill in for you. On vault.tester4.test, in the „Vaults” menu, select „New” and choose „Login”. Fill in the „Item name”, „Username” and „Password” fields. In the „Website” field, type the address of the site: the extension offers to fill in on that site. Select „Save”. Turn on two-step login Besides the master password, a code from your phone is needed too, so a stolen password alone is not enough. In the menu on the left, open „Settings”, then „Security”. Choose the „Two-step login” tab. In the „Authenticator app” row, select „Manage” and follow the steps in the window. Then select „View recovery code” and write the code down on paper. Find weak passwords Vaultwarden shows which of your passwords are weak and which you use in more than one place. In the menu on the left, open „Reports”. Choose „Weak passwords” or „Reused passwords”. Change the password on the site concerned, then change it in the vault too. Frequently asked questions I forgot my master password. What can I do? Nobody is able to reset it, not even the box: your master password encrypts your vault. Write it down and keep it somewhere safe. Why can my family member not sign up? Signing up is closed by default. Invite them in the admin panel as the first steps say, or allow sign-ups on the dashboard, on Vaultwarden's „Settings” tab. Can I share a password with the family? Yes, with an organisation. In the filter of the „Vaults” page, select „New organization”, then invite the family on the organisation's „Members” page. Do I need an account with Bitwarden? No. Vaultwarden is a server running on your box, and the Bitwarden apps and extensions connect to it. Where are my passwords, and are they backed up? On the box, encrypted. For their backup, look at the „Data and backup” tab of Vaultwarden. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-guide-hu.txt
new file mode 100644
index 00000000..7d382b66
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-guide-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Felhom.eu ← Alkalmazások Vaultwarden Jelszókezelő - Bitwarden kompatibilis, a saját szerveren ● Fut vault.tester4.test Megnyitás ↗ Mire használható? Jelszavak biztonságos tárolása és automatikus kitöltése Bitwarden kliensek teljes kompatibilitása (böngésző, mobil, asztali) Jelszavak megosztása családtagokkal szervezeten belül Kétfaktoros hitelesítés (TOTP) kódok tárolása Biztonságos jegyzetek és bankkártya adatok tárolása Első lépések Nyisd meg a vault.tester4.test/admin címet, és lépj be az admin panel tokenjével (Beállítások → Automatikusan generált értékek) A „Users" fülön az „Invite User" mezőben hívd meg a saját és a családtagok e-mail címét. Ha a telepítéskor nem engedélyezted a regisztrációt (ez az ajánlott), csak meghívott cím nyithat fiókot Nyisd meg a vault.tester4.test címet, válaszd a „Create account" lehetőséget a meghívott címmel, és adj meg erős mesterjelszót Telepítsd a Bitwarden bővítményt a böngésződbe Telepítsd a Bitwarden alkalmazást a telefonodra Importáld a meglévő jelszavaidat (Chrome, Firefox, LastPass, stb.) A Bitwarden bővítmény és app összekötése a dobozzal A Bitwarden appok alapból a Bitwarden saját szerverét keresik, ezért egyszer meg kell adnod a dobozod címét. Nyisd meg a Bitwarden bővítményt vagy appot, és menj a bejelentkező képernyőre. A szerverválasztóban válaszd a saját üzemeltetésű (self-hosted) szervert. Szervercímnek írd be: vault.tester4.test, és mentsd el. Jelentkezz be az e-mail címeddel és a mesterjelszavaddal. Új jelszó mentése Amit a széfbe teszel, azt a bővítmény és az app is látja, és kitölti helyetted. A vault.tester4.test oldalon a „Széfek” menüben kattints az „Új” gombra, és válaszd a „Bejelentkezés” pontot. Töltsd ki az „Elem neve”, a „Felhasználónév” és a „Jelszó” mezőt. A „Webhely” mezőbe írd be az oldal címét: a bővítmény ezen az oldalon ajánlja fel a kitöltést. Kattints a „Mentés” gombra. Kétlépcsős bejelentkezés bekapcsolása A mesterjelszó mellé egy telefonos kód is kell, így egy ellopott jelszó önmagában kevés. A bal oldali menüben nyisd meg a „Beállítások”, majd a „Biztonság” pontot. Válaszd a „Kétlépcsős bejelentkezés” lapot. A „Hitelesítő alkalmazás” sorában kattints a „Kezelés” gombra, és kövesd az ablak lépéseit. Utána kattints a „Helyreállító kód megtekintése” gombra, és írd le a kódot papírra. Gyenge jelszavak keresése A Vaultwarden megmutatja, melyik jelszavad gyenge, és melyiket használod több helyen. A bal oldali menüben nyisd meg a „Jelentések” pontot. Válaszd a „Gyenge jelszavak jelentés” vagy az „Újrahasznált jelszavak jelentés” lehetőséget. Cseréld le a jelszót az érintett oldalon, majd írd át a széfben is. Gyakori kérdések Elfelejtettem a mesterjelszót. Mit tehetek? Senki nem tudja visszaállítani, a doboz sem: a széfedet a mesterjelszó titkosítja. Írd le, és tartsd biztos helyen. Miért nem tud regisztrálni a családtagom? A regisztráció alapból le van zárva. Hívd meg az admin panelen az első lépések szerint, vagy a vezérlőpulton, a Vaultwarden „Beállítások” fülén engedélyezd a regisztrációt. Megoszthatok jelszót a családdal? Igen, egy szervezettel. A „Széfek” oldal szűrőjében kattints az „Új szervezet” pontra, majd a szervezet „Tagok” oldalán hívd meg a családtagokat. Kell fiókot nyitnom a Bitwardennél? Nem. A Vaultwarden a te dobozodon futó szerver, a Bitwarden appok és bővítmények ehhez kapcsolódnak. Hol vannak a jelszavaim, és van róluk mentés? A dobozon, titkosítva. A mentésükről a Vaultwarden „Adatok és mentés” fülén tájékozódhatsz. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-install-en.txt
new file mode 100644
index 00000000..4d48c5c0
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-install-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Install — Felhom.eu ← Back Vaultwarden — Install A password manager (Bitwarden-compatible) ~50M RAM Full description, screenshots Memory 50 MB / 7479 MB (0%) Current usage (0 MB) Vaultwarden (+50 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Admin panel token Generated automatically Show Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Allow sign-ups No - by invitation only (recommended) Yes - anybody who knows the address can sign up Closed by default: you invite the household from the admin panel (see First steps). With sign-ups open, anybody who guesses the address can sign up. Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-install-hu.txt
new file mode 100644
index 00000000..4bfc6763
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-install-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Telepítés — Felhom.eu ← Vissza Vaultwarden — Telepítés Jelszókezelő (Bitwarden-kompatibilis) ~50M RAM Részletes leírás, képernyőképek Memória 50 MB / 7479 MB (0%) Jelenlegi használat (0 MB) Vaultwarden (+50 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Admin panel token Automatikusan generálva Megjelenítés Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Regisztráció engedélyezése Nem – csak meghívással (ajánlott) Igen – bárki regisztrálhat, aki ismeri a címet Alapból lezárva: a család tagjait az admin panelen hívod meg (lásd Első lépések). Nyitott regisztrációval bárki fiókot nyithat, aki kitalálja a címet. Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-overview-en.txt
new file mode 100644
index 00000000..37516c26
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-overview-en.txt
@@ -0,0 +1 @@
+Vaultwarden — Settings — Felhom.eu ← Apps Vaultwarden A password manager - Bitwarden-compatible, on your own server ● Running vault.tester4.test Open ↗ Running Running Restart Stop Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Sending e-mail This app can send e-mail (for example password resets, invitations) through Felhom, without setting up a separate provider. The sender address: vaultwarden@felhom.eu . App e-mail is turned off globally right now. Turn it on on the Settings page for it to work here too. Allow sending e-mail for this app Save Saving restarts the app. Address and keys These were created at install time and cannot be changed. Address vault.tester4.test Admin panel token Show Allow sign-ups No - by invitation only (recommended)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-overview-hu.txt
new file mode 100644
index 00000000..6d1c7779
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/page-overview-hu.txt
@@ -0,0 +1 @@
+Vaultwarden — Felhom.eu ← Alkalmazások Vaultwarden Jelszókezelő - Bitwarden kompatibilis, a saját szerveren ● Fut vault.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Email-küldés Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, külön szolgáltató beállítása nélkül. A feladó címe: vaultwarden@felhom.eu . Az alkalmazás-email jelenleg ki van kapcsolva globálisan. Kapcsold be a Beállítások oldalon, hogy itt is működjön. Email-küldés engedélyezése ennél az alkalmazásnál Mentés A mentés újraindítja az alkalmazást. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím vault.tester4.test Admin panel token Megjelenítés Regisztráció engedélyezése Nem – csak meghívással (ajánlott)
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/record.json b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/record.json
new file mode 100644
index 00000000..f641b272
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/record.json
@@ -0,0 +1,118 @@
+{
+ "app": "vaultwarden",
+ "sub": "vault",
+ "fixture": "Vaultwarden",
+ "started": "2026-10-24T21:30:00Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "ADMIN_TOKEN",
+ "secret",
+ false
+ ],
+ [
+ "SIGNUPS_ALLOWED",
+ "select",
+ false
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/vaultwarden/install",
+ "hu_len": 1187,
+ "en_len": 1093,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/vaultwarden/install -> 200 'Vaultwarden — Telepítés — Felhom.eu' | shot /root/shots/vaultwarden-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/vaultwarden/install -> 200 'Vaultwarden — Telepítés — Felhom.eu' | shot /root/shots/vaultwarden-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 25,
+ "front_door": true,
+ "seconds_to_front_door": 25
+ },
+ "stranger": "200",
+ "http_port_80": "301 https://vault.tester4.test/",
+ "guide": {
+ "path": "/apps/vaultwarden/guide",
+ "hu_len": 3522,
+ "en_len": 3304,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/vaultwarden",
+ "hu_len": 889,
+ "en_len": 849,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": false,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/vaultwarden/guide -> 200 'Vaultwarden — Felhom.eu' | shot /root/shots/vaultwarden-after-guide-phone-hu.png hscroll=False",
+ "goto https://vault.tester4.test/ -> 200 'Vaultwarden Web' | shot /root/shots/vaultwarden-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"1.283893367s\", \"last_run\": \"2026-10-24T21:31:19.640595204Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "containers": {
+ "vaultwarden": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "vaultwarden": 36.2
+ },
+ "mem_anon_peak_mib": {
+ "vaultwarden": 34.7
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 171
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-after-front-desktop-hu.png
new file mode 100644
index 00000000..17edf490
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-after-guide-phone-hu.png
new file mode 100644
index 00000000..80328476
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-install-install-desktop-en.png
new file mode 100644
index 00000000..519dab88
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-install-install-phone-hu.png
new file mode 100644
index 00000000..6095cb3a
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/screens/vaultwarden-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/walk.log b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/walk.log
new file mode 100644
index 00000000..627b1acd
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vaultwarden/run-live-2/walk.log
@@ -0,0 +1,15 @@
+21:30:20Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+21:30:45Z [1] deployed, controller state=running, pinned={'vaultwarden': 'vaultwarden/server:1.37.4-alpine'}
+21:30:46Z [1] installed: deployed 25 s, front door 25 s
+21:30:46Z vaultwarden: self-registration http=404 (closed by design, R-512 — 400 expected)
+21:30:54Z vaultwarden: test-box admin sign-in and invite (inside the box) -> ('200', 'yes', '200')
+21:30:54Z vaultwarden: invited registration http=404
+21:30:54Z vaultwarden: refused
+
+
+
+ HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+13:36:59Z vikunja: readback of the seeded project http=200 ok=True
+13:37:38Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'vikunja', 'volumes_removed': ['vikunja_vikunja_data', 'vikunja_vikunja_db'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás nem tárolt
+13:37:47Z == vikunja done in 150 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-guide-en.txt
new file mode 100644
index 00000000..ce2df416
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-guide-en.txt
@@ -0,0 +1 @@
+Vikunja — Guide — Felhom.eu ← Apps Vikunja Task management - lists, Kanban boards and Gantt charts ● Running tasks.tester4.test Open ↗ What is it for? Keep your task lists and to-dos A Kanban board view (Trello-like) A Gantt chart for scheduling a project Shared lists, so a team can work together Reminders, due dates, labels and priorities First steps Open tasks.tester4.test in your browser Create your account Create your first project and task list Try the Kanban and List views Invite the household, or your colleagues Add a task quickly In one line you can give the task, its label and its priority. Open the project and click into the top field where you type a new task. Type the task and add a label with an asterisk, for example: Milk *shop. Set the priority with an exclamation mark and a number from 1 to 5, for example: !4. The higher the number, the more important it is. Press Enter. If the label does not exist yet, Vikunja creates it. A repeating chore Taking out the bins every week or paying a monthly bill only has to be added once. Open the task, select „Set Due Date” and set the first time. Select „Set Repeating Interval” and choose „Every Week”. When you mark the task done, Vikunja moves the due date to the next time and the task stays open. Share a project with the family Everyone sees and adds to the shared shopping list from their own account. The family member needs their own account: on the dashboard, on the Vikunja page, select „Open sign-up for 15 minutes”, and they sign up meanwhile. In the list on the left, open the project's menu and select „Share”. In the users part, type the family member's exact username, choose them and select „Share”. Next to them you can set whether they only read the project or can edit it too. What is due this week? You see the coming tasks of all your projects in one place. In the menu on the left, select „Upcoming”. It shows the tasks due from today until a week from now. Tick „Show overdue tasks” to see the tasks you missed as well. Frequently asked questions Do I get reminders? No. Vikunja would send reminders by e-mail, but the box did not set up mail for it, so „Set Reminders” does not reach you here. The „Upcoming” view shows what is due. Why can I not find my family member when sharing? They have to sign up with their own account first. Type their exact username into the search, not their full name. Can I give a due date in the quick add? Yes, but Vikunja understands the words only in English, for example tomorrow or next monday. Otherwise use „Set Due Date”. Why is some text in English? Vikunja follows your browser's language, and its Hungarian translation is not complete. You can change it in „Language” under „General Settings” in „Settings”. How do I hide a finished project? In the project's menu, select „Archive”. An archived project stays, but you cannot edit it until you take it back. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-guide-hu.txt
new file mode 100644
index 00000000..983f70ca
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-guide-hu.txt
@@ -0,0 +1 @@
+Vikunja — Felhom.eu ← Alkalmazások Vikunja Feladatkezelő - listák, Kanban táblák és Gantt diagramok ● Fut tasks.tester4.test Megnyitás ↗ Mire használható? Feladatlisták és teendők kezelése Kanban tábla nézet (Trello-szerű) Gantt diagram projekt ütemezéshez Megosztott listák és csapat együttműködés Emlékeztetők, lejárati dátumok, címkék és prioritások Első lépések Nyisd meg a tasks.tester4.test címet a böngészőben Hozd létre a fiókodat Hozd létre az első projektet és feladatlistát Próbáld ki a Kanban és Lista nézeteket Hívd meg a családtagokat vagy kollégákat Feladat gyors felvétele Egy sorban megadhatod a feladatot, a címkéjét és a fontosságát. Nyisd meg a projektet, és kattints a felső mezőbe, ahová az új feladatot írod. Írd be a feladatot, és csillaggal tegyél mellé címkét, például: Tej *bolt. A fontosságot felkiáltójellel és egy 1 és 5 közötti számmal adod meg, például: !4. Minél nagyobb a szám, annál fontosabb. Nyomj Entert. Ha a címke még nem létezik, a Vikunja létrehozza. Ismétlődő teendő A heti szemétkihordást vagy a havi számlát elég egyszer felvenni. Nyisd meg a feladatot, kattints a „Határidő beállítása” gombra, és add meg az első alkalmat. Kattints az „Állítsa be az ismétlési intervallumot” gombra, és válaszd a „Minden héten” lehetőséget. Ha a feladatot késznek jelölöd, a Vikunja a határidőt a következő alkalomra teszi, és a feladat nyitva marad. Projekt megosztása a családdal A közös bevásárlólistát mindenki a saját fiókjából látja és bővíti. A családtagnak saját fiók kell: a vezérlőpulton, a Vikunja oldalán kattints a „Regisztráció megnyitása 15 percre” gombra, és ő közben regisztrál. A bal oldali listában nyisd meg a projekt menüjét, és kattints a „Megosztás” pontra. A felhasználók résznél írd be pontosan a családtag felhasználónevét, válaszd ki, és kattints a „Megosztás” gombra. Mellette beállíthatod, hogy csak olvassa vagy szerkessze is a projektet. Mi esedékes a héten? Egy helyen látod az összes projekt közelgő feladatait. A bal oldali menüben kattints a „Hamarosan” pontra. Itt a mai naptól egy hétig esedékes feladatok látszanak. Jelöld be „A lejárt feladatok megjelenítése” jelölőt, hogy a lekésett feladatok is látszódjanak. Gyakori kérdések Kapok emlékeztetőt? Nem. A Vikunja az emlékeztetőt e-mailben küldené, de a doboz nem állított be neki levelezést, ezért az „Emlékeztető beállítása” itt nem jut el hozzád. A „Hamarosan” nézet mutatja, mi esedékes. Miért nem találom a családtagomat a megosztásnál? Előbb regisztrálnia kell a saját fiókjával. A keresőbe a pontos felhasználónevét írd, nem a teljes nevét. Megadhatok határidőt a gyors felvételnél? Igen, de a Vikunja a szavakat csak angolul érti, például tomorrow vagy next monday. Magyarul inkább a „Határidő beállítása” gombot használd. Miért angol néhány felirat? A Vikunja a böngésződ nyelvét követi, és a magyar fordítása nem teljes. A nyelvet a „Beállítások” „Általános beállítások” részén, a „Nyelv” mezőben válthatod. Hogyan tüntetem el a lezárt projektet? A projekt menüjében kattints az „Archiválás” pontra. Az archivált projekt megmarad, de nem szerkeszthető, amíg vissza nem veszed. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-install-en.txt
new file mode 100644
index 00000000..8ae5eb43
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-install-en.txt
@@ -0,0 +1 @@
+Vikunja — Install — Felhom.eu ← Back Vikunja — Install Task lists and boards (a Todoist/Trello alternative) ~50M RAM Full description, screenshots Memory 50 MB / 7479 MB (0%) Current usage (0 MB) Vikunja (+50 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain JWT encryption key Generated automatically Show Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-install-hu.txt
new file mode 100644
index 00000000..e27e41e9
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-install-hu.txt
@@ -0,0 +1 @@
+Vikunja — Telepítés — Felhom.eu ← Vissza Vikunja — Telepítés Feladatkezelő listák és táblák (Todoist/Trello alternatíva) ~50M RAM Részletes leírás, képernyőképek Memória 50 MB / 7479 MB (0%) Jelenlegi használat (0 MB) Vikunja (+50 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain JWT titkosítási kulcs Automatikusan generálva Megjelenítés Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-overview-en.txt
new file mode 100644
index 00000000..ecda1492
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-overview-en.txt
@@ -0,0 +1 @@
+Vikunja — Settings — Felhom.eu ← Apps Vikunja Task management - lists, Kanban boards and Gantt charts ● Running tasks.tester4.test Open ↗ Running Running Restart Stop First setup Right now only you can reach this app, while you are signed in to the dashboard. So nobody else can create its first admin account. Open it and finish the first setup. For this the app restarts once and is briefly unavailable meanwhile. When you are done, press this button. Until then, phone apps and the rest of your family cannot reach it. Done, I set it up Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Address and keys These were created at install time and cannot be changed. Address tasks.tester4.test JWT encryption key Show
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-overview-hu.txt
new file mode 100644
index 00000000..d06d5d31
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/page-overview-hu.txt
@@ -0,0 +1 @@
+Vikunja — Felhom.eu ← Alkalmazások Vikunja Feladatkezelő - listák, Kanban táblák és Gantt diagramok ● Fut tasks.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Első beállítás Most csak te éred el ezt az alkalmazást, amíg be vagy jelentkezve a vezérlőpultba. Így más nem hozhatja létre az első admin fiókot. Nyisd meg, és végezd el az első beállítást. Ehhez az alkalmazás egyszer újraindul, és közben rövid ideig nem érhető el. Ha kész, nyomd meg ezt a gombot. Addig a telefonos alkalmazások és a család többi tagja nem éri el. Kész, beállítottam Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím tasks.tester4.test JWT titkosítási kulcs Megjelenítés
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/record.json b/documentation/audits/catalog-sweep-2026-10-24/vikunja/record.json
new file mode 100644
index 00000000..ae50c353
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/record.json
@@ -0,0 +1,124 @@
+{
+ "app": "vikunja",
+ "sub": "tasks",
+ "fixture": "Vikunja",
+ "started": "2026-10-24T13:35:01Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "VIKUNJA_SERVICE_JWTSECRET",
+ "secret",
+ false
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/vikunja/install",
+ "hu_len": 942,
+ "en_len": 843,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/vikunja/install -> 200 'Vikunja — Telepítés — Felhom.eu' | shot /root/shots/vikunja-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/vikunja/install -> 200 'Vikunja — Telepítés — Felhom.eu' | shot /root/shots/vikunja-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 10,
+ "front_door": true,
+ "seconds_to_front_door": 10
+ },
+ "stranger": "302 https://felhom.tester4.test/__gate/start?rd=https%3A%2F%2Ftasks.tester4.test%2F",
+ "http_port_80": "301 https://tasks.tester4.test/",
+ "guide": {
+ "path": "/apps/vikunja/guide",
+ "hu_len": 3142,
+ "en_len": 2931,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/vikunja",
+ "hu_len": 816,
+ "en_len": 807,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": true,
+ "seed_read_now": true,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/vikunja/guide -> 200 'Vikunja — Felhom.eu' | shot /root/shots/vikunja-after-guide-phone-hu.png hscroll=False",
+ "goto https://tasks.tester4.test/ -> 200 'Vikunja' | shot /root/shots/vikunja-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"1.83657661s\", \"last_run\": \"2026-10-24T13:35:48.677171356Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "seed_read_after_reinstall": false,
+ "restore": {
+ "points": 1,
+ "location": [
+ "location: /backups/restore?flash=flash.restore.started"
+ ],
+ "seconds": 10,
+ "status": "{\"running\": false, \"op\": \"restore\", \"stack\": \"vikunja\", \"started_at\": \"2026-10-24T13:36:49.511179197Z\", \"last\": {\"op\": \"restore\", \"stack\": \"vikunja\", \"ok\": true, \"message\": \"A(z) vikunja: 2 adatkötet visszaállítva — az alkalmazás újraindult.\", \"finished_at\": \"2026-10-24T13:36:55.912262348Z\"}, \"last_recent\": true}",
+ "state": "running"
+ },
+ "seed_read_after_unit_restore": true,
+ "containers": {
+ "vikunja": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": ""
+ }
+ },
+ "errors": {
+ "count": 1,
+ "sample": [
+ "vikunja: time=2026-10-24T15:36:59.764+02:00 level=ERROR component=http remote_ip=192.168.0.180 method=POST uri=/api/v1/login status=403 latency=129.145722ms user_agent=curl/8.14.1 err=\"Wrong username "
+ ]
+ },
+ "mem_peak_mib": {
+ "vikunja": 37.4
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 150
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-after-front-desktop-hu.png
new file mode 100644
index 00000000..ea6e6bb5
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-after-guide-phone-hu.png
new file mode 100644
index 00000000..9597ab07
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-install-install-desktop-en.png
new file mode 100644
index 00000000..d36b1917
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-install-install-phone-hu.png
new file mode 100644
index 00000000..40d320a5
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/vikunja/screens/vikunja-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/vikunja/walk.log b/documentation/audits/catalog-sweep-2026-10-24/vikunja/walk.log
new file mode 100644
index 00000000..cca2be7f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/vikunja/walk.log
@@ -0,0 +1,15 @@
+13:35:17Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+13:35:27Z [1] deployed, controller state=running, pinned={'vikunja': 'vikunja/vikunja:2.6.0'}
+13:35:27Z gate: tasks is gated — passed as the household (cookie set)
+13:35:27Z [1] installed: deployed 10 s, front door 10 s
+13:35:27Z vikunja: register http=200
+13:35:28Z vikunja: create project http=201
+13:35:28Z vikunja: readback of the seeded project http=200 ok=True
+13:35:46Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+13:36:29Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'vikunja', 'volumes_removed': ['vikunja_vikunja_data', 'vikunja_vikunja_db'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verified': True
+13:36:48Z vikunja: the seeded account no longer authenticates :: http=403 {"code":1011,"message":"Wrong username or password."}
+
+13:36:49Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+13:36:59Z vikunja: readback of the seeded project http=200 ok=True
+13:37:38Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'vikunja', 'volumes_removed': ['vikunja_vikunja_data', 'vikunja_vikunja_db'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás nem tárolt
+13:37:47Z == vikunja done in 150 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer.console.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer.console.txt
new file mode 100644
index 00000000..50327468
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer.console.txt
@@ -0,0 +1,193 @@
+16:31:23Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['SUBDOMAIN_DB']
+16:31:23Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+16:33:54Z [1] deployed, controller state=unhealthy, pinned={'wanderer': 'flomp/wanderer-web:v0.20.0', 'wanderer-db': 'flomp/wanderer-db:v0.20.0', 'wanderer-search': 'getmeili/meilisearch:v1.36.0'}
+16:33:54Z [1] NOTE: the controller's own state is 'unhealthy', not 'running' — recorded, not treated as a failure; the fixture's front-door wait is the real gate
+16:33:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:33:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:14Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:19Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:24Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:29Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:34Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:39Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:44Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:49Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:15Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:20Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:25Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:00Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:05Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:10Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:15Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:20Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:25Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:01Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:06Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:11Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:16Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:21Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:26Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:31Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:36Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:41Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:46Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:51Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:56Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:01Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:06Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:11Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:16Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:21Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:26Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:31Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:36Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:41Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:46Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:52Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:57Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:42Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:47Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:52Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:57Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:43Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:48Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:53Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:58Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:03Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:08Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:13Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:18Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:23Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:28Z app never answered on wanderer/ (last rc=0 code=404)
+16:41:28Z [1] installed: deployed 151 s, front door 605 s
+16:41:28Z [3] no fixture for this app — the front door answering is the smallest honest check
+16:41:48Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+16:42:37Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'wanderer', 'volumes_removed': ['wanderer_wanderer_data', 'wanderer_wanderer_meili_data', 'wanderer_wanderer_plugins', 'wanderer_wanderer_uploads'], 'hdd_paths_removed
+16:42:46Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['SUBDOMAIN_DB']
+16:43:36Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:41Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:46Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:51Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:56Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:42Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:47Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:52Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:57Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:42Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:48Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:53Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:58Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:03Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:08Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:13Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:18Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:23Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:28Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:33Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:38Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:43Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:48Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:53Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:58Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:03Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:08Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:13Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:18Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:23Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:28Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:33Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:39Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:44Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:49Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:14Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:19Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:24Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:29Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:34Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:39Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:44Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:49Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:14Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:19Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:24Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:00Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:05Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:10Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:15Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:20Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:25Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:51:00Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:51:05Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:51:10Z app never answered on wanderer/ (last rc=0 code=404)
+16:51:52Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'wanderer', 'volumes_removed': ['wanderer_wanderer_data', 'wanderer_wanderer_meili_data', 'wanderer_wanderer_plugins', 'wanderer_wanderer_uploads'], 'hdd_paths_removed
+16:52:01Z == wanderer done in 1238 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-guide-en.txt
new file mode 100644
index 00000000..c6dbbd04
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-guide-en.txt
@@ -0,0 +1 @@
+Wanderer — Guide — Felhom.eu ← Apps Wanderer A hike planner - routes, GPX tracks and terrain maps ● Not healthy Up to date wanderer.tester4.test Open ↗ What is it for? Plan and keep hiking routes Import and export GPX files Terrain profiles and statistics Add photos and notes to a route Share a route with other people First steps Open wanderer.tester4.test in your browser Create your account right after the install, then close sign-up on the app page. Until then, anyone who finds the address can make an account. Import a GPX file, or plan a new route Have a look at the map view Record a finished hike In the summit book you keep when and with whom you walked the route. Open the route and choose the „Summit Book” tab at the bottom. Select „Add Entry”. Set the „Date”, write a few lines in „Text”, upload photos and select „Save”. After the first entry, Wanderer asks whether to mark the route as completed. Sort routes into lists With a list you keep, for example, the family's summer hikes in one place. In the top menu, open the lists page and select the plus button. Give the list a name and select „Save List”. On a route's page, open the three-dot menu, select „Manage lists” and choose the list. Share a route with the family Your family member sees a shared route in their own account. The family member needs their own account: on the dashboard, on the Wanderer page, select „Open sign-up for 15 minutes”, and they sign up meanwhile. Open the route's three-dot menu and select „Share”. Type the family member's username into the search and select their name. Next to it you can choose: „View” (they can only look) or „Edit”. A route on your GPS or phone You can download the route as a file and load it into your hiking watch or map app. Open the route's three-dot menu and select „Export”. In „File format”, keep GPX: most devices know it. Select „Export” and copy the file to your device. Frequently asked questions Who sees my routes? Only you, by default. You can change this on the „Privacy” page of „Settings”, and decide for each route too. How do I switch between kilometres and miles? On the „Settings” page, in the language and „Units” part, choose „Metric” or „Imperial”. Why is so much text in English? Wanderer follows your browser's language, but its Hungarian translation is not complete, so many buttons stay in English there. The Hungarian guide writes them as they appear on screen. Can I download all my routes at once? Yes: on the import and export page of „Settings”, select „Export all trails”. Where does Wanderer keep my data? On the box, not with an outside provider. You see the state of its backup on the dashboard, on the „Data and backup” tab. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-guide-hu.txt
new file mode 100644
index 00000000..3e262335
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-guide-hu.txt
@@ -0,0 +1 @@
+Wanderer — Felhom.eu ← Alkalmazások Wanderer Túra tervező - útvonalak, GPX nyomok és domborzati térképek ● Nem egészséges Naprakész wanderer.tester4.test Megnyitás ↗ Mire használható? Túra útvonalak tervezése és mentése GPX fájlok importálása és exportálása Domborzati profilok és statisztikák Fotók és jegyzetek hozzáadása az útvonalakhoz Útvonalak megosztása másokkal Első lépések Nyisd meg a wanderer.tester4.test címet a böngészőben Hozd létre a fiókodat azonnal a telepítés után, aztán az alkalmazás oldalán zárd le a regisztrációt. Addig bárki, aki megtalálja a címet, fiókot hozhat létre. Importálj egy GPX fájlt vagy tervezz új útvonalat Fedezd fel a térképes megjelenítést Teljesített túra rögzítése A csúcspont könyvben eltárolod, mikor és kivel jártad végig az útvonalat. Nyisd meg az útvonalat, és lent válaszd a „Csúcspont könyv” fület. Kattints a „Bejegyzés hozzáadása” gombra. Add meg a „Dátum” mezőt, a „Szöveg” mezőbe írj pár sort, tölts fel képeket, és kattints a „Mentés” gombra. Az első bejegyzés után a Wanderer megkérdezi, hogy teljesítettnek jelölje-e az útvonalat. Útvonalak listába rendezése A listával egy helyre gyűjtöd például a nyári családi túrákat. A felső menüben nyisd meg a listák oldalát, és kattints a plusz gombra. Adj nevet a listának, és kattints a „Save List” (lista mentése) gombra. Egy útvonal oldalán nyisd meg a három pontos menüt, kattints a „Hozzáadás a listához” pontra, és válaszd ki a listát. Útvonal megosztása a családdal A megosztott útvonalat a családtag a saját fiókjában látja. A családtagnak saját fiók kell: a vezérlőpulton, a Wanderer oldalán kattints a „Regisztráció megnyitása 15 percre” gombra, és ő közben regisztrál. Nyisd meg az útvonal három pontos menüjét, és kattints a „Share” (megosztás) pontra. A keresőbe írd be a családtag felhasználónevét, és kattints a nevére. Mellette választhatsz: „View” (csak megnézheti) vagy „Szerkesztés”. Útvonal a GPS-re vagy a telefonra Az útvonalat fájlként letöltheted, és betöltheted a túraórádba vagy a térképes appodba. Nyisd meg az útvonal három pontos menüjét, és kattints az „Export” pontra. A „File format” (fájlformátum) mezőben hagyd a GPX-et, ezt a legtöbb eszköz ismeri. Kattints az „Export” gombra, és a fájlt másold át az eszközödre. Gyakori kérdések Ki látja az útvonalaimat? Alapból csak te. A „Beállítások” „Privacy” (adatvédelem) oldalán ezt megváltoztathatod, és útvonalanként is eldöntheted. Hogyan válthatok kilométerre vagy mérföldre? A „Beállítások” oldalon, a nyelv és a „Mértékegységek” résznél válaszd a „Metrikus” vagy az „Angolszász” lehetőséget. Miért angol sok felirat? A Wanderer a böngésződ nyelvét követi, de a magyar fordítása nem teljes, ezért sok gomb angolul marad. Az útmutató ezeket úgy írja, ahogy a képernyőn látod. Le tudom tölteni egyszerre az összes útvonalamat? Igen: a „Beállítások” import és export oldalán kattints az „Export all trails” (összes útvonal exportálása) gombra. Hol tárolja a Wanderer az adataimat? A dobozon, nem külső szolgáltatónál. A mentésük állapotát a vezérlőpulton, az „Adatok és mentés” fülön látod. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-install-en.txt
new file mode 100644
index 00000000..cf33c1f5
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-install-en.txt
@@ -0,0 +1 @@
+Wanderer — Install — Felhom.eu ← Back Wanderer — Install A hike planner that follows your tracks ~350M RAM Full description, screenshots Memory 350 MB / 7479 MB (4%) Current usage (0 MB) Wanderer (+350 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Search engine key Generated automatically Show Database encryption key Generated automatically Show Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Database subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-install-hu.txt
new file mode 100644
index 00000000..4f838a33
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-install-hu.txt
@@ -0,0 +1 @@
+Wanderer — Telepítés — Felhom.eu ← Vissza Wanderer — Telepítés Túra tervező és nyomkövetéssel ~350M RAM Részletes leírás, képernyőképek Memória 350 MB / 7479 MB (4%) Jelenlegi használat (0 MB) Wanderer (+350 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Keresőmotor kulcs Automatikusan generálva Megjelenítés Adatbázis titkosítási kulcs Automatikusan generálva Megjelenítés Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Adatbázis aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-overview-en.txt
new file mode 100644
index 00000000..9b043928
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-overview-en.txt
@@ -0,0 +1 @@
+Wanderer — Settings — Felhom.eu ← Apps Wanderer A hike planner - routes, GPX tracks and terrain maps ● Not healthy Up to date wanderer.tester4.test Open ↗ Running Not healthy Restart Stop Sign-up Anyone who finds this app's address can sign up. Close sign-up now — you can still add your family afterwards. For this the app restarts once and is briefly unavailable meanwhile. Close sign-up now Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Address and keys These were created at install time and cannot be changed. Address wanderer.tester4.test Search engine key Show Database encryption key Show
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-overview-hu.txt
new file mode 100644
index 00000000..efd85403
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/page-overview-hu.txt
@@ -0,0 +1 @@
+Wanderer — Felhom.eu ← Alkalmazások Wanderer Túra tervező - útvonalak, GPX nyomok és domborzati térképek ● Nem egészséges Naprakész wanderer.tester4.test Megnyitás ↗ Működés Nem egészséges Újraindítás Leállítás Regisztráció Ennél az alkalmazásnál bárki regisztrálhat, aki megtalálja a címét. Zárd le a regisztrációt most — a családtagjaidat utána is fel tudod venni. Ehhez az alkalmazás egyszer újraindul, és közben rövid ideig nem érhető el. Regisztráció lezárása most Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím wanderer.tester4.test Keresőmotor kulcs Megjelenítés Adatbázis titkosítási kulcs Megjelenítés
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/record.json b/documentation/audits/catalog-sweep-2026-10-24/wanderer/record.json
new file mode 100644
index 00000000..1257dc37
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/record.json
@@ -0,0 +1,136 @@
+{
+ "app": "wanderer",
+ "sub": "wanderer",
+ "fixture": null,
+ "started": "2026-10-24T16:31:04Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "SUBDOMAIN_DB",
+ "subdomain",
+ true
+ ],
+ [
+ "MEILI_MASTER_KEY",
+ "secret",
+ false
+ ],
+ [
+ "POCKETBASE_ENCRYPTION_KEY",
+ "secret",
+ false
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/wanderer/install",
+ "hu_len": 1187,
+ "en_len": 1075,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/wanderer/install -> 200 'Wanderer — Telepítés — Felhom.eu' | shot /root/shots/wanderer-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/wanderer/install -> 200 'Wanderer — Telepítés — Felhom.eu' | shot /root/shots/wanderer-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 151,
+ "front_door": false,
+ "seconds_to_front_door": 605
+ },
+ "stranger": "404",
+ "http_port_80": "301 https://wanderer.tester4.test/",
+ "guide": {
+ "path": "/apps/wanderer/guide",
+ "hu_len": 3108,
+ "en_len": 2727,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/wanderer",
+ "hu_len": 769,
+ "en_len": 692,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": null,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/wanderer/guide -> 200 'Wanderer — Felhom.eu' | shot /root/shots/wanderer-after-guide-phone-hu.png hscroll=False",
+ "goto https://wanderer.tester4.test/ -> 404 '' | shot /root/shots/wanderer-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 15,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"14.729222959s\", \"last_run\": \"2026-10-24T16:42:03.717608703Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "containers": {
+ "wanderer": {
+ "limit_mib": 512,
+ "restarts": 0,
+ "status": "running",
+ "health": "unhealthy"
+ },
+ "wanderer-db": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ },
+ "wanderer-search": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 1,
+ "sample": [
+ "wanderer-search: \u001b[2m2026-10-24T16:43:31.338784Z\u001b[0m \u001b[33m WARN\u001b[0m \u001b[1mHTTP request\u001b[0m\u001b[1m{\u001b[0m\u001b[3mmethod\u001b[0m\u001b[2m=\u001b[0mGET \u001b[3mhost\u001b[0m\u001b[2m=\u001b[0m\"wanderer-search:7700\" \u001b[3mroute\u001b[0m\u001b[2m=\u001b[0m/indexes/a"
+ ]
+ },
+ "mem_peak_mib": {
+ "wanderer-db": 15.5,
+ "wanderer-search": 60.0,
+ "wanderer": 65.0
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 1238
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-after-front-desktop-hu.png
new file mode 100644
index 00000000..2969e2aa
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-after-guide-phone-hu.png
new file mode 100644
index 00000000..f4a56d41
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-install-install-desktop-en.png
new file mode 100644
index 00000000..77e83001
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-install-install-phone-hu.png
new file mode 100644
index 00000000..aebafe98
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wanderer/screens/wanderer-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wanderer/walk.log b/documentation/audits/catalog-sweep-2026-10-24/wanderer/walk.log
new file mode 100644
index 00000000..50327468
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wanderer/walk.log
@@ -0,0 +1,193 @@
+16:31:23Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['SUBDOMAIN_DB']
+16:31:23Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+16:33:54Z [1] deployed, controller state=unhealthy, pinned={'wanderer': 'flomp/wanderer-web:v0.20.0', 'wanderer-db': 'flomp/wanderer-db:v0.20.0', 'wanderer-search': 'getmeili/meilisearch:v1.36.0'}
+16:33:54Z [1] NOTE: the controller's own state is 'unhealthy', not 'running' — recorded, not treated as a failure; the fixture's front-door wait is the real gate
+16:33:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:33:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:14Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:19Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:24Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:29Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:34Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:39Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:44Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:49Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:34:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:15Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:20Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:25Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:35:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:00Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:05Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:10Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:15Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:20Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:25Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:36:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:01Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:06Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:11Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:16Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:21Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:26Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:31Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:36Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:41Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:46Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:51Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:37:56Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:01Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:06Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:11Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:16Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:21Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:26Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:31Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:36Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:41Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:46Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:52Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:38:57Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:42Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:47Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:52Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:39:57Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:43Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:48Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:53Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:40:58Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:03Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:08Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:13Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:18Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:23Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:41:28Z app never answered on wanderer/ (last rc=0 code=404)
+16:41:28Z [1] installed: deployed 151 s, front door 605 s
+16:41:28Z [3] no fixture for this app — the front door answering is the smallest honest check
+16:41:48Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+16:42:37Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'wanderer', 'volumes_removed': ['wanderer_wanderer_data', 'wanderer_wanderer_meili_data', 'wanderer_wanderer_plugins', 'wanderer_wanderer_uploads'], 'hdd_paths_removed
+16:42:46Z [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['SUBDOMAIN_DB']
+16:43:36Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:41Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:46Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:51Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:43:56Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:42Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:47Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:52Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:44:57Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:02Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:07Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:12Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:17Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:22Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:27Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:32Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:37Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:42Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:48Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:53Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:45:58Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:03Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:08Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:13Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:18Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:23Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:28Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:33Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:38Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:43Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:48Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:53Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:46:58Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:03Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:08Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:13Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:18Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:23Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:28Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:33Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:39Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:44Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:49Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:47:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:14Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:19Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:24Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:29Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:34Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:39Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:44Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:49Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:54Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:48:59Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:04Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:09Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:14Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:19Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:24Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:49:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:00Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:05Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:10Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:15Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:20Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:25Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:30Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:35Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:40Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:45Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:50Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:50:55Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:51:00Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:51:05Z gate: wanderer not routed right now (404) — not cached, asked again next call
+16:51:10Z app never answered on wanderer/ (last rc=0 code=404)
+16:51:52Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'wanderer', 'volumes_removed': ['wanderer_wanderer_data', 'wanderer_wanderer_meili_data', 'wanderer_wanderer_plugins', 'wanderer_wanderer_uploads'], 'hdd_paths_removed
+16:52:01Z == wanderer done in 1238 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist.console.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist.console.txt
new file mode 100644
index 00000000..0249d26f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist.console.txt
@@ -0,0 +1,16 @@
+14:42:55Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+14:44:05Z [1] deployed, controller state=running, pinned={'wishlist': 'ghcr.io/cmintey/wishlist:v0.67.1'}
+14:44:05Z gate: wishlist is gated — passed as the household (cookie set)
+14:44:05Z [1] installed: deployed 71 s, front door 71 s
+14:44:06Z wishlist: /signup http=200 type=success
+14:44:07Z wishlist: sign-in as the seeded user type=success ok=True (wrong password refused)
+14:44:27Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+14:44:37Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:44:58Z wishlist: sign-in as the seeded user type=success ok=True (wrong password refused)
+14:45:30Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'wishlist', 'volumes_removed': ['wishlist_wishlist_data', 'wishlist_wishlist_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verif
+14:52:51Z app never answered on wishlist/login (last rc=0 code=302)
+14:52:51Z wishlist: /login never came back
+14:52:51Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:53:12Z wishlist: sign-in as the seeded user type=success ok=True (wrong password refused)
+14:53:51Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'wishlist', 'volumes_removed': ['wishlist_wishlist_data', 'wishlist_wishlist_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás
+14:54:00Z == wishlist done in 665 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-guide-en.txt
new file mode 100644
index 00000000..7aa68cae
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-guide-en.txt
@@ -0,0 +1 @@
+Wishlist — Guide — Felhom.eu ← Apps Wishlist A family wish list - for Christmas and birthdays ● Running wishlist.tester4.test Open ↗ What is it for? Make wish lists for Christmas and birthdays Invite the household so each keeps their own list Claim a gift without spoiling the surprise Add prices and links to the gifts Organise a present several people chip in for First steps Open wishlist.tester4.test in your browser Create your account Create your first wish list Invite the household Add a wish from a web shop link When you have the product's link, Wishlist fills in its name, price and picture by itself. On the „My Lists” page, open your list and select the plus button in the bottom right corner. Paste the product's link into „Item URL” and wait while the data loads. In „Notes”, write what matters, for example the size or the colour. If you want this most of all, switch on „Most wanted”, then select „Create item”. Claim a gift Claim what you are going to buy, so that two people do not buy the same thing. On the „Home” page, open the family member's list. At the gift, select „Claim”, then „Claim” again in the window that opens. The owner of the list does not see what was claimed, but the other family members see your name next to the gift. The gifts you claimed You see in one place what you took on and what you have already bought. Select „My Claims”. When you have bought the gift, select the bag icon next to it, the „Mark item as purchased” button. If you are not going to buy it after all, select „Unclaim”, then again in the window that opens, so that someone else can claim it. An idea for someone else's list You can suggest a wish to someone else too, but it only goes on the list if they accept it. Open the family member's list and select the plus button in the bottom right corner. Fill in the wish the same way as your own and select „Create item”. The owner of the list sees the suggestion under „Approvals” and accepts or declines it. Frequently asked questions Does my family member see what I claimed from their list? No: the owner of a list does not see the claims. The other family members see that you claimed it, so nobody buys it twice. Why does the invite link not work? Sign-up is open only after you press „Open sign-up for 15 minutes” on the dashboard, on the Wishlist page. Open the invite link during that time. Is there a Hungarian version? Not in this version: Wishlist shows in English, whatever your browser's language. That is why the Hungarian guide gives the meaning of the labels in brackets. Can I upload my own picture for a wish? Yes: when you edit the wish, select „Upload Image”. This helps when the product is not from a web shop. How do I put my wishes in order? On your list, select „Reorder”, set the order, then select „Finish”. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-guide-hu.txt
new file mode 100644
index 00000000..8bbaf335
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-guide-hu.txt
@@ -0,0 +1 @@
+Wishlist — Felhom.eu ← Alkalmazások Wishlist Családi kívánságlista - karácsonyra, születésnapokra ● Fut wishlist.tester4.test Megnyitás ↗ Mire használható? Kívánságlisták létrehozása karácsonyra, születésnapokra Családtagok meghívása saját listáik kezeléséhez Ajándékok lefoglalása meglepetés nélkül Árak és linkek hozzáadása az ajándékokhoz Csoportos ajándékok szervezése Első lépések Nyisd meg a wishlist.tester4.test címet a böngészőben Hozd létre a fiókodat Hozd létre az első kívánságlistádat Hívd meg a családtagokat Kívánság felvétele webshop linkből Ha megvan a termék linkje, a Wishlist maga tölti ki a nevét, az árát és a képét. A „My Lists” (saját listáim) oldalon nyisd meg a listádat, és kattints a jobb alsó sarokban a plusz gombra. Másold be a termék linkjét az „Item URL” (termék címe) mezőbe, és várd meg, amíg az adatok betöltődnek. A „Notes” (megjegyzés) mezőbe írd be, ami fontos, például méretet vagy színt. Ha ez a legnagyobb vágyad, kapcsold be a „Most wanted” (legjobban vágyott) jelölőt, majd kattints a „Create item” (létrehozás) gombra. Ajándék lefoglalása Foglald le, amit megveszel, így ketten nem veszik meg ugyanazt. A „Home” (kezdőlap) oldalon nyisd meg a családtag listáját. Az ajándéknál kattints a „Claim” (lefoglalom) gombra, majd a megjelenő ablakban is a „Claim” gombra. A lista gazdája nem látja, hogy mit foglaltak le, a többi családtag viszont látja a neved az ajándék mellett. A lefoglalt ajándékaid Egy helyen látod, mit vállaltál, és mit vettél már meg. Kattints a „My Claims” (foglalásaim) pontra. Ha megvetted az ajándékot, kattints a mellette lévő táska ikonra, a „Mark item as purchased” (megvettem) gombra. Ha mégsem veszed meg, kattints az „Unclaim” (foglalás törlése) gombra, majd a megjelenő ablakban is, hogy más lefoglalhassa. Ötlet más listájára Másnak is javasolhatsz kívánságot, de az csak akkor kerül fel, ha ő elfogadja. Nyisd meg a családtag listáját, és kattints a jobb alsó sarokban a plusz gombra. Töltsd ki a kívánságot ugyanúgy, mint a sajátodnál, és kattints a „Create item” gombra. A lista gazdája az „Approvals” (jóváhagyások) résznél látja a javaslatot, és elfogadja vagy elutasítja. Gyakori kérdések Látja a családtag, hogy mit foglaltam le a listájáról? Nem: a lista gazdája nem látja a foglalásokat. A többi családtag látja, hogy te foglaltad le, így nem veszik meg kétszer. Miért nem működik a meghívó link? A regisztráció csak akkor nyitott, amikor a vezérlőpulton, a Wishlist oldalán a „Regisztráció megnyitása 15 percre” gombot megnyomod. A meghívó linket ebben az időben kell megnyitni. Van magyar nyelve? Ebben a változatban nincs: a Wishlist angolul jelenik meg, a böngésző nyelvétől függetlenül. Az útmutató ezért zárójelben megadja a feliratok jelentését. Feltölthetek saját képet egy kívánsághoz? Igen: a kívánság szerkesztésekor kattints az „Upload Image” (kép feltöltése) gombra. Ez akkor jó, ha a termék nem webshopból van. Hogyan rendezem a kívánságaimat? A listádon kattints a „Reorder” (átrendezés) gombra, állítsd be a sorrendet, majd kattints a „Finish” (kész) gombra. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-install-en.txt
new file mode 100644
index 00000000..4873398f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-install-en.txt
@@ -0,0 +1 @@
+Wishlist — Install — Felhom.eu ← Back Wishlist — Install Wish lists shared across the household ~120M RAM Full description, screenshots Memory 120 MB / 7479 MB (1%) Current usage (0 MB) Wishlist (+120 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-install-hu.txt
new file mode 100644
index 00000000..e5e2827f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-install-hu.txt
@@ -0,0 +1 @@
+Wishlist — Telepítés — Felhom.eu ← Vissza Wishlist — Telepítés Családi kívánságlista megosztás ~120M RAM Részletes leírás, képernyőképek Memória 120 MB / 7479 MB (1%) Jelenlegi használat (0 MB) Wishlist (+120 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-overview-en.txt
new file mode 100644
index 00000000..cc7213b8
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-overview-en.txt
@@ -0,0 +1 @@
+Wishlist — Settings — Felhom.eu ← Apps Wishlist A family wish list - for Christmas and birthdays ● Running wishlist.tester4.test Open ↗ Running Running Restart Stop First setup Right now only you can reach this app, while you are signed in to the dashboard. So nobody else can create its first admin account. Open it and finish the first setup. When you are done, press this button. Until then, phone apps and the rest of your family cannot reach it. Done, I set it up Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Address and keys These were created at install time and cannot be changed. Address wishlist.tester4.test
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-overview-hu.txt
new file mode 100644
index 00000000..80ceee6f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/page-overview-hu.txt
@@ -0,0 +1 @@
+Wishlist — Felhom.eu ← Alkalmazások Wishlist Családi kívánságlista - karácsonyra, születésnapokra ● Fut wishlist.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Első beállítás Most csak te éred el ezt az alkalmazást, amíg be vagy jelentkezve a vezérlőpultba. Így más nem hozhatja létre az első admin fiókot. Nyisd meg, és végezd el az első beállítást. Ha kész, nyomd meg ezt a gombot. Addig a telefonos alkalmazások és a család többi tagja nem éri el. Kész, beállítottam Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím wishlist.tester4.test
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/record.json b/documentation/audits/catalog-sweep-2026-10-24/wishlist/record.json
new file mode 100644
index 00000000..0eb281c5
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/record.json
@@ -0,0 +1,118 @@
+{
+ "app": "wishlist",
+ "sub": "wishlist",
+ "fixture": "Wishlist",
+ "started": "2026-10-24T14:42:38Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/wishlist/install",
+ "hu_len": 861,
+ "en_len": 787,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/wishlist/install -> 200 'Wishlist — Telepítés — Felhom.eu' | shot /root/shots/wishlist-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/wishlist/install -> 200 'Wishlist — Telepítés — Felhom.eu' | shot /root/shots/wishlist-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 71,
+ "front_door": true,
+ "seconds_to_front_door": 71
+ },
+ "stranger": "302 https://felhom.tester4.test/__gate/start?rd=https%3A%2F%2Fwishlist.tester4.test%2F",
+ "http_port_80": "301 https://wishlist.tester4.test/",
+ "guide": {
+ "path": "/apps/wishlist/guide",
+ "hu_len": 3096,
+ "en_len": 2834,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/wishlist",
+ "hu_len": 709,
+ "en_len": 715,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": true,
+ "seed_read_now": true,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/wishlist/guide -> 200 'Wishlist — Felhom.eu' | shot /root/shots/wishlist-after-guide-phone-hu.png hscroll=False",
+ "goto https://wishlist.tester4.test/login?redirectTo=%2F -> 200 'Sign in' | shot /root/shots/wishlist-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 10,
+ "status": "{\"db_dump\": {\"count\": 0, \"duration\": \"1.695388609s\", \"last_run\": \"2026-10-24T14:44:28.716028086Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "restore": {
+ "points": 1,
+ "location": [
+ "location: /backups/restore?flash=flash.restore.started"
+ ],
+ "seconds": 20,
+ "status": "{\"running\": false, \"op\": \"restore\", \"stack\": \"wishlist\", \"started_at\": \"2026-10-24T14:52:51.472432603Z\", \"last\": {\"op\": \"restore\", \"stack\": \"wishlist\", \"ok\": true, \"message\": \"A(z) wishlist: 2 adatkötet visszaállítva — az alkalmazás újraindult.\", \"finished_at\": \"2026-10-24T14:53:07.949444237Z\"}, \"last_recent\": true}",
+ "state": "running"
+ },
+ "seed_read_after_restore": true,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "seed_read_after_reinstall": false,
+ "seed_read_after_unit_restore": true,
+ "containers": {
+ "wishlist": {
+ "limit_mib": 512,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "wishlist": 199.7
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 665
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-after-front-desktop-hu.png
new file mode 100644
index 00000000..8bebf440
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-after-guide-phone-hu.png
new file mode 100644
index 00000000..f43b805c
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-install-install-desktop-en.png
new file mode 100644
index 00000000..2abc9ac6
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-install-install-phone-hu.png
new file mode 100644
index 00000000..d9741c35
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/wishlist/screens/wishlist-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/wishlist/walk.log b/documentation/audits/catalog-sweep-2026-10-24/wishlist/walk.log
new file mode 100644
index 00000000..0249d26f
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/wishlist/walk.log
@@ -0,0 +1,16 @@
+14:42:55Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+14:44:05Z [1] deployed, controller state=running, pinned={'wishlist': 'ghcr.io/cmintey/wishlist:v0.67.1'}
+14:44:05Z gate: wishlist is gated — passed as the household (cookie set)
+14:44:05Z [1] installed: deployed 71 s, front door 71 s
+14:44:06Z wishlist: /signup http=200 type=success
+14:44:07Z wishlist: sign-in as the seeded user type=success ok=True (wrong password refused)
+14:44:27Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+14:44:37Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:44:58Z wishlist: sign-in as the seeded user type=success ok=True (wrong password refused)
+14:45:30Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'wishlist', 'volumes_removed': ['wishlist_wishlist_data', 'wishlist_wishlist_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': [], 'verif
+14:52:51Z app never answered on wishlist/login (last rc=0 code=302)
+14:52:51Z wishlist: /login never came back
+14:52:51Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+14:53:12Z wishlist: sign-in as the seeded user type=success ok=True (wrong password refused)
+14:53:51Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'wishlist', 'volumes_removed': ['wishlist_wishlist_data', 'wishlist_wishlist_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalmazás
+14:54:00Z == wishlist done in 665 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline.console.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline.console.txt
new file mode 100644
index 00000000..191df724
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline.console.txt
@@ -0,0 +1,13 @@
+15:37:51Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+15:39:12Z [1] deployed, controller state=running, pinned={'zipline': 'ghcr.io/diced/zipline:4.8.0', 'zipline-postgres': 'postgres:16-alpine'}
+15:39:12Z gate: img is gated — passed as the household (cookie set)
+15:39:12Z [1] installed: deployed 81 s, front door 81 s
+15:39:12Z zipline: /api/setup http=200 :: {"firstSetup":false,"user":{"id":"b377itg3lycmhwc35c9ufbjd","username":"drill8de5fa","createdAt":"2026-10-24T15:39:12.712Z","updatedAt":"2026-10-24T15:39:12.715
+15:39:12Z zipline: login as the seeded user http=200 ok=True
+15:39:33Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+15:40:36Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'zipline', 'volumes_removed': ['zipline_zipline_postgres_data', 'zipline_zipline_public', 'zipline_zipline_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [
+15:42:05Z zipline: login as the seeded user http=400 ok=False
+15:42:05Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+15:42:40Z zipline: login as the seeded user http=200 ok=True
+15:43:30Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'zipline', 'volumes_removed': ['zipline_zipline_postgres_data', 'zipline_zipline_public', 'zipline_zipline_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [
+15:43:39Z == zipline done in 348 s
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/page-guide-en.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-guide-en.txt
new file mode 100644
index 00000000..f2ba6151
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-guide-en.txt
@@ -0,0 +1 @@
+Zipline — Guide — Felhom.eu ← Apps Zipline A screenshot and file sharing server that works with ShareX/Flameshot ● Running img.tester4.test Open ↗ What is it for? Screenshots upload themselves from ShareX/Flameshot Shorten a URL and share text (paste) A gallery view and albums An API, for integrations of your own User accounts and invitations First steps Open img.tester4.test in your browser On the first visit, create your admin account Point ShareX or Flameshot at the API address Upload a screenshot to check it works Before you start ShareX (Windows) or Flameshot (Linux) is recommended for uploading screenshots Send a file with a link Zipline gives an uploaded file a link that you can send to anyone. In the menu on the left, open „Upload” and select „File”. Drag the file onto the page, or click the box and choose it. Select the upload button at the bottom. After the upload the link appears: the copy icon puts it on the clipboard so you can send it. A file that deletes itself For a short-lived file you can set it to disappear after a while, or to ask for a password. On the upload page, select „Options”. In the „Upload Options” window, choose after how long the file deletes itself, for example: 1 week. If only the people you tell should open it, type a password into „Password”. Select „Close” and upload the file. Your browser remembers the setting for the next upload too. A shared folder for the family In a public folder you can share several files with one link, for example the holiday photos. On the „Folders” page, select the button that creates a folder. Fill in „Name”, switch on „Public” and select „Create”. When you upload, choose this folder in „Add to a Folder” in the „Options” window. In the folder's menu, „Copy URL” gives you the folder's link. An account for a family member Everyone uploads with their own account, so the files do not get mixed up. In the menu on the left, open „Administrator” and select „Users”. Select „Create”. Fill in „Username” and „Password”, and leave „Role” on „User”. Select „Create” and give the family member the name and the password. Frequently asked questions Who can see an uploaded file? Anyone you send the link to, even without signing in. If you do not want that, set a password in the „Options” window before you upload. How big a file can I upload? By default, up to 100 MB per file. Can I make a short link from a long address? Yes: on the „URLs” page select „Create”, paste the address into „URL” and select „Create”. A family member forgot their password. What do I do? On the „Users” page, in the menu of the family member's card, select „Edit”, type a new password into „Password” and select „Update user”. Why is Zipline in English? Zipline is only available in English. That is why the Hungarian guide gives the meaning of the labels in brackets. Documentation Official documentation ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/page-guide-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-guide-hu.txt
new file mode 100644
index 00000000..2b061141
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-guide-hu.txt
@@ -0,0 +1 @@
+Zipline — Felhom.eu ← Alkalmazások Zipline Screenshot és fájlmegosztó szerver ShareX/Flameshot integrációval ● Fut img.tester4.test Megnyitás ↗ Mire használható? Screenshotok automatikus feltöltése ShareX/Flameshot-ból URL rövidítés és szöveg megosztás (paste) Galéria nézet és album kezelés API támogatás egyedi integrációkhoz Felhasználói fiókok és meghívó rendszer Első lépések Nyisd meg az img.tester4.test címet a böngészőben Az első megnyitáskor hozd létre az admin fiókodat Konfiguráld a ShareX-et vagy Flameshot-ot az API URL-lel Tölts fel egy screenshot-ot a teszteléshez Előfeltételek ShareX (Windows) vagy Flameshot (Linux) ajánlott a screenshot feltöltéshez Fájl küldése linkkel A feltöltött fájlhoz a Zipline linket ad, ezt elküldheted bárkinek. A bal oldali menüben nyisd meg az „Upload” (feltöltés) menüt, és kattints a „File” (fájl) pontra. Húzd a fájlt az oldalra, vagy kattints a mezőre, és válaszd ki. Kattints a lenti feltöltés gombra. A feltöltés után megjelenik a link: a másolás ikonnal vágólapra teszed, és elküldheted. Fájl, ami magától törlődik Egy átmeneti fájlnál beállíthatod, hogy egy idő után eltűnjön, vagy jelszót kérjen. A feltöltés oldalán kattints az „Options” (beállítások) gombra. Az „Upload Options” ablakban válaszd ki, mennyi idő múlva törlődjön a fájl, például: 1 week. Ha csak az nyithassa meg, akinek megmondod, írj jelszót a „Password” (jelszó) mezőbe. Kattints a „Close” (bezárás) gombra, és töltsd fel a fájlt. A beállítást a böngésződ megjegyzi a következő feltöltésre is. Közös mappa a családnak Egy nyilvános mappában egy linkkel több fájlt is megoszthatsz, például a nyaralás képeit. A „Folders” (mappák) oldalon kattints a mappa létrehozása gombra. Írd be a „Name” (név) mezőt, kapcsold be a „Public” (nyilvános) kapcsolót, és kattints a „Create” (létrehozás) gombra. Feltöltéskor az „Options” ablak „Add to a Folder” (mappába tétel) mezőjében válaszd ki ezt a mappát. A mappa menüjében a „Copy URL” (link másolása) ponttal kapod meg a mappa linkjét. Fiók a családtagnak Mindenki a saját fiókjával tölthet fel, így a fájlok nem keverednek. A bal oldali menüben nyisd meg az „Administrator” (adminisztrátor) menüt, és kattints a „Users” (felhasználók) pontra. Kattints a „Create” gombra. Írd be a „Username” (felhasználónév) és a „Password” mezőt, a „Role” (szerep) mezőben hagyd a „User” (felhasználó) értéket. Kattints a „Create” gombra, és add át a családtagnak a nevet és a jelszót. Gyakori kérdések Ki láthatja a feltöltött fájlt? Bárki, akinek elküldöd a linket, bejelentkezés nélkül is. Ha ezt nem szeretnéd, feltöltés előtt adj meg jelszót az „Options” ablakban. Mekkora fájlt tölthetek fel? Alapból fájlonként legfeljebb 100 MB-osat. Tudok rövid linket készíteni egy hosszú címből? Igen: az „URLs” (linkek) oldalon kattints a „Create” gombra, másold be a címet az „URL” mezőbe, és kattints a „Create” gombra. Elfelejtette a jelszavát a családtag. Mit tegyek? A „Users” oldalon a családtag kártyájának menüjében kattints az „Edit” (szerkesztés) pontra, írj új jelszót a „Password” mezőbe, és kattints az „Update user” (mentés) gombra. Miért angol a Zipline? A Zipline csak angolul érhető el. Az útmutató ezért zárójelben megadja a feliratok jelentését. Dokumentáció Hivatalos dokumentáció ↗
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/page-install-en.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-install-en.txt
new file mode 100644
index 00000000..9a38a575
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-install-en.txt
@@ -0,0 +1 @@
+Zipline — Install — Felhom.eu ← Back Zipline — Install A ShareX/Flameshot server - screenshots and file sharing ~200M RAM Full description, screenshots Memory 200 MB / 7479 MB (2%) Current usage (0 MB) Zipline (+200 MB) Where the data goes: this app has no separate data drive choice, so its data goes to the system drive ( /mnt/sys_drive ). Its backups are made all the same. Automatically generated values These values are saved together with the install. Write down the passwords you need! Domain Encryption key Generated automatically Show Database password Generated automatically Show Settings Subdomain * cannot be changed after install .tester4.test The subdomain cannot be changed after install. To change it, remove the app and install it again (all data is deleted). Start install Cancel Installing... Saving the configuration... Starting the container(s)... Initialising the app...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/page-install-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-install-hu.txt
new file mode 100644
index 00000000..32e86df6
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-install-hu.txt
@@ -0,0 +1 @@
+Zipline — Telepítés — Felhom.eu ← Vissza Zipline — Telepítés ShareX/Flameshot szerver - screenshot és fájlmegosztás ~200M RAM Részletes leírás, képernyőképek Memória 200 MB / 7479 MB (2%) Jelenlegi használat (0 MB) Zipline (+200 MB) Hol lesznek az adatok: ennél az alkalmazásnál nincs külön adatmeghajtó-választás, ezért az adatai a rendszermeghajtóra kerülnek ( /mnt/sys_drive ). A mentései így is elkészülnek. Automatikusan generált értékek Ezek az értékek a telepítéssel együtt mentésre kerülnek. Jegyezd fel a szükséges jelszavakat! Domain Titkosítási kulcs Automatikusan generálva Megjelenítés Adatbázis jelszó Automatikusan generálva Megjelenítés Beállítások Aldomain * telepítés után nem módosítható .tester4.test Az aldomain telepítés után nem módosítható. Megváltoztatáshoz az alkalmazás eltávolítása és újratelepítése szükséges (minden adat törlődik). Telepítés indítása Mégsem Telepítés folyamatban... Konfiguráció mentése... Konténer(ek) indítása... Alkalmazás inicializálása...
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/page-overview-en.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-overview-en.txt
new file mode 100644
index 00000000..c846fc9b
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-overview-en.txt
@@ -0,0 +1 @@
+Zipline — Settings — Felhom.eu ← Apps Zipline A screenshot and file sharing server that works with ShareX/Flameshot ● Running img.tester4.test Open ↗ Running Running Restart Stop First setup Right now only you can reach this app, while you are signed in to the dashboard. So nobody else can create its first admin account. Open it and finish the first setup. When you are done, the box notices it by itself and opens the app for everyone. Done, I set it up Signing in to the app You create the admin account on the first visit. The box does not know the password — keep it in your password manager. Address and keys These were created at install time and cannot be changed. Address img.tester4.test Encryption key Show Database password Show
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/page-overview-hu.txt b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-overview-hu.txt
new file mode 100644
index 00000000..359ef66c
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/page-overview-hu.txt
@@ -0,0 +1 @@
+Zipline — Felhom.eu ← Alkalmazások Zipline Screenshot és fájlmegosztó szerver ShareX/Flameshot integrációval ● Fut img.tester4.test Megnyitás ↗ Működés Fut Újraindítás Leállítás Első beállítás Most csak te éred el ezt az alkalmazást, amíg be vagy jelentkezve a vezérlőpultba. Így más nem hozhatja létre az első admin fiókot. Nyisd meg, és végezd el az első beállítást. Ha kész, a doboz magától észreveszi, és mindenkinek megnyitja az alkalmazást. Kész, beállítottam Belépés az alkalmazásba Az admin fiókot az első megnyitáskor te hozod létre. A jelszót a doboz nem tudja — írd fel a jelszókezelődbe. Cím és kulcsok Ezek telepítéskor jöttek létre, és nem módosíthatók. Cím img.tester4.test Titkosítási kulcs Megjelenítés Adatbázis jelszó Megjelenítés
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/record.json b/documentation/audits/catalog-sweep-2026-10-24/zipline/record.json
new file mode 100644
index 00000000..4c72b0aa
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/record.json
@@ -0,0 +1,136 @@
+{
+ "app": "zipline",
+ "sub": "img",
+ "fixture": "Zipline",
+ "started": "2026-10-24T15:37:34Z",
+ "deploy_fields": [
+ [
+ "DOMAIN",
+ "domain",
+ true
+ ],
+ [
+ "SUBDOMAIN",
+ "subdomain",
+ true
+ ],
+ [
+ "CORE_SECRET",
+ "secret",
+ false
+ ],
+ [
+ "DB_PASSWORD",
+ "secret",
+ false
+ ]
+ ],
+ "install_page": {
+ "path": "/apps/zipline/install",
+ "hu_len": 990,
+ "en_len": 893,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "shots_install": [
+ "goto https://felhom.tester4.test/apps/zipline/install -> 200 'Zipline — Telepítés — Felhom.eu' | shot /root/shots/zipline-install-install-phone-hu.png hscroll=False",
+ "goto https://felhom.tester4.test/apps/zipline/install -> 200 'Zipline — Telepítés — Felhom.eu' | shot /root/shots/zipline-install-install-desktop-en.png hscroll=False"
+ ],
+ "install": {
+ "ok": true,
+ "seconds_to_deployed": 81,
+ "front_door": true,
+ "seconds_to_front_door": 81
+ },
+ "stranger": "302 https://felhom.tester4.test/__gate/start?rd=https%3A%2F%2Fimg.tester4.test%2F",
+ "http_port_80": "301 https://img.tester4.test/",
+ "guide": {
+ "path": "/apps/zipline/guide",
+ "hu_len": 3249,
+ "en_len": 2871,
+ "english_words_in_hu": [
+ "password"
+ ],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "overview": {
+ "path": "/apps/zipline",
+ "hu_len": 749,
+ "en_len": 741,
+ "english_words_in_hu": [],
+ "accented_in_en": 0,
+ "same_text": false
+ },
+ "seed": true,
+ "seed_read_now": true,
+ "shots_after": [
+ "goto https://felhom.tester4.test/apps/zipline/guide -> 200 'Zipline — Felhom.eu' | shot /root/shots/zipline-after-guide-phone-hu.png hscroll=False",
+ "goto https://img.tester4.test/auth/login -> 200 'Zipline' | shot /root/shots/zipline-after-front-desktop-hu.png hscroll=False"
+ ],
+ "backup": {
+ "code": "200",
+ "seconds": 20,
+ "status": "{\"db_dump\": {\"count\": 1, \"duration\": \"19.407399992s\", \"last_run\": \"2026-10-24T15:39:52.769748154Z\", \"success\": true}, \"enabled\": true, \"running\": false}"
+ },
+ "snapshots_after_backup": 1,
+ "after_keep_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "reinstall_first_answer": {
+ "code": "202",
+ "body": "{\"ok\": true, \"message\": \"Telepítés elindítva – az állapot a kártyán követhető\"}"
+ },
+ "kept": {
+ "offered": false,
+ "plain_install_code": "202"
+ },
+ "seed_read_after_reinstall": false,
+ "restore": {
+ "points": 1,
+ "location": [
+ "location: /backups/restore?flash=flash.restore.started"
+ ],
+ "seconds": 35,
+ "status": "{\"running\": false, \"op\": \"restore\", \"stack\": \"zipline\", \"started_at\": \"2026-10-24T15:42:05.498157076Z\", \"last\": {\"op\": \"restore\", \"stack\": \"zipline\", \"ok\": true, \"message\": \"A(z) zipline: 3 adatkötet és az adatbázis visszaállítva — az alkalmazás újraindult.\", \"finished_at\": \"2026-10-24T15:42:35.650944262Z\"}, \"last_recent\": true}",
+ "state": "running"
+ },
+ "seed_read_after_unit_restore": true,
+ "containers": {
+ "zipline": {
+ "limit_mib": 512,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ },
+ "zipline-postgres": {
+ "limit_mib": 256,
+ "restarts": 0,
+ "status": "running",
+ "health": "healthy"
+ }
+ },
+ "errors": {
+ "count": 0,
+ "sample": []
+ },
+ "mem_peak_mib": {
+ "zipline": 191.3,
+ "zipline-postgres": 41.8
+ },
+ "after_final_remove": {
+ "containers": "",
+ "volumes": "",
+ "appyaml": "",
+ "appdata": "",
+ "kept": "",
+ "subdomain": "404"
+ },
+ "total_seconds": 348
+}
\ No newline at end of file
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-after-front-desktop-hu.png b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-after-front-desktop-hu.png
new file mode 100644
index 00000000..39a387e8
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-after-front-desktop-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-after-guide-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-after-guide-phone-hu.png
new file mode 100644
index 00000000..ffab9690
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-after-guide-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-install-install-desktop-en.png b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-install-install-desktop-en.png
new file mode 100644
index 00000000..ac050a89
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-install-install-desktop-en.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-install-install-phone-hu.png b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-install-install-phone-hu.png
new file mode 100644
index 00000000..6319bf58
Binary files /dev/null and b/documentation/audits/catalog-sweep-2026-10-24/zipline/screens/zipline-install-install-phone-hu.png differ
diff --git a/documentation/audits/catalog-sweep-2026-10-24/zipline/walk.log b/documentation/audits/catalog-sweep-2026-10-24/zipline/walk.log
new file mode 100644
index 00000000..191df724
--- /dev/null
+++ b/documentation/audits/catalog-sweep-2026-10-24/zipline/walk.log
@@ -0,0 +1,13 @@
+15:37:51Z [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+15:39:12Z [1] deployed, controller state=running, pinned={'zipline': 'ghcr.io/diced/zipline:4.8.0', 'zipline-postgres': 'postgres:16-alpine'}
+15:39:12Z gate: img is gated — passed as the household (cookie set)
+15:39:12Z [1] installed: deployed 81 s, front door 81 s
+15:39:12Z zipline: /api/setup http=200 :: {"firstSetup":false,"user":{"id":"b377itg3lycmhwc35c9ufbjd","username":"drill8de5fa","createdAt":"2026-10-24T15:39:12.712Z","updatedAt":"2026-10-24T15:39:12.715
+15:39:12Z zipline: login as the seeded user http=200 ok=True
+15:39:33Z [4] Mentés most -> 200 {'ok': True, 'message': 'Mentés elindítva'}
+15:40:36Z [5] stop 200, remove KEEPING data -> 200 {'ok': True, 'data': {'removed': 'zipline', 'volumes_removed': ['zipline_zipline_postgres_data', 'zipline_zipline_public', 'zipline_zipline_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [
+15:42:05Z zipline: login as the seeded user http=400 ok=False
+15:42:05Z [6] POST /backup/restore -> HTTP/2 302 ['location: /backups/restore?flash=flash.restore.started']
+15:42:40Z zipline: login as the seeded user http=200 ok=True
+15:43:30Z [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'zipline', 'volumes_removed': ['zipline_zipline_postgres_data', 'zipline_zipline_public', 'zipline_zipline_uploads'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [
+15:43:39Z == zipline done in 348 s
diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md
index 538b1e17..4ddf613f 100644
--- a/documentation/backlog/OPEN-ITEMS.md
+++ b/documentation/backlog/OPEN-ITEMS.md
@@ -113,21 +113,23 @@ match what the reader sees is how an instrument stops being believed (R-421). It
**nothing was proven on the day this line was drawn** and a stopping line that moves a status is a
stopping line that lies.
-## Install & onboarding — 6 rows (P3 4, P4 2)
+## Install & onboarding — 7 rows (P3 5, P4 2)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
| **R-980** | Install & onboarding | P3 | **A person cannot check that the installer is ours: the ISO's first boot runs the install script from a movable tag with no hash or signature, and the ISO checksum sits on the same website as the download.** Fix: a signed manifest (or signature) checked by the ISO before it runs the script, and the public key printed in the guide. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | OPEN — design-proposal | — | Design note, then build | CC |
| **R-250** | Install & onboarding | P3 | **A customer create can fail fail-closed because the host-key scan ladder is shorter than the DNS/AAAA settle time.** Found 2026-08-07 creating the fifth walk's venue. `POST /configs/new` with off-site enabled provisions the Storage Box sub-account and then scans its SSH host key to pin it — **fail-closed by design** (`offsite.go:111-121`, *"don't serve a descriptor the controller can't verify"*), with `defaultScanBackoff` = 2+4+8+16+30 ≈ **60 s**, sized by its own comment to *"the observed DNS propagation lag"*. **Measured, both halves:** the first create exhausted the ladder — five `no such host`, then `dial tcp [2a01:4f8:bacc:2:200::d30]:23: connect: network is unreachable` (the name had just begun resolving, **AAAA-first, into a pod with no IPv6 route**) — and the hub logged `[ERROR] offsite provision for walk5`. An **identical second POST succeeded** ~70 s later on its own final rung (`shared already provisioned … (subaccount 285351)`). **Total settle ≈ 100 s against a 60 s budget.** The endpoint was never the problem: verified afterwards from both the node and the hub pod, by name, `SSH-2.0-OpenSSH_9.6p1`. **Two distinct things are wrong and should not be merged:** (1) the budget is sized against DNS *existence*, but what actually bit is the **AAAA-before-A** window, a different and longer phenomenon — lengthen the ladder and/or prefer the A record for the scan dial; (2) **the operator is told nothing actionable** — the create fails with a generic error, the remedy is "press it again", and nothing says so. The retry is genuinely safe (idempotent on the label; confirmed afterwards — `one_time_secrets` 1, one sub-account, no double-provision) **but that safety is invisible to the person deciding whether pressing again will double-charge them.** **Severity LOW-MEDIUM:** self-clearing, no data at risk — but it is the first thing a new customer's provisioning does and it fails looking like an outage. | **VERIFY** — **2026-10-12: hub 0.147.0 live** (S29, decision 224): the host-key scan dials IPv4 first, waits ~2 min (was ~1), and when it still runs out says the store was created and it is safe to press Save again (`TestScannerDialsIPv4First`, `TestScanOutOfRetriesSaysSafeToPressAgain`, red-proved). Known limit: the hub Ingress reads for 60 s, so a very slow first try can show a gateway timeout while provisioning finishes in the background (pressing again is safe). **READY** — operator ruling 2026-10-12 (S29, `09` §3 decision 224): yes — the scan prefers IPv4, waits longer, and the error says „safe to press again". **READY** — owner Viktor | — | The next real off-site setup (a new customer): read the hub log for the scan; success or the new message → close | CC |
| **R-516** | Install & onboarding | P3 | **[P3-LOW] English a customer meets on a fresh box and its apps' first screens — enumerated by the big night.** MEASURED 2026-09-14 (BIGNIGHT, VM 333, ISO 1.27.1, controller 0.242.0). Felhom-owned: (1) the dashboard menu item **„Debug"**; (2) the dashboard CPU tile **„Load: 0.29 / 0.39 / 0.37"**; (3) the launcher tile **„Filebrowser"** opens a login in English with no Felhom text (R-513); (4) the storage page mixes formal „Adjon hozzá / Csatlakoztasson" with the product's „te". App first screens a household meets before any Felhom text helps: (5) **Uptime Kuma 2.4 opens on „Which database would you like to use?"** (SQLite / Embedded MariaDB, „Next") — the app card's „Első lépések" does not mention it; (6) PrivateBin, Gokapi, AdventureLog and FileBrowser UIs are English (the apps' own). Already rows: the Proxmox installer screens (R-495, answered by the guide), `wiki.DOMAIN` (R-498). **Fix shape:** rename „Debug"/„Load" (controller); add the Uptime Kuma database step to its card, or pre-seed `db-config.json` for SQLite in the template (catalog). **Added by F4 (20:04:54Z):** (7) the storage page prints the disconnect time as a raw ISO UTC string „Leválasztva: 2026-09-14T19:58:02Z"; (8) the „Meghajtó leválasztva" banner appears twice on every page; (9) „4 telepített alkalmazás nem fut — nézze meg a rendszermonitort" uses the formal form. **Added by F7 (20:50–21:00Z, system disk at 95 %):** (10) a banner on every page in English, „**SSD disk usage high: 90%**"; (11) the dashboard tile reads „Rendszer (/) 61.8 GB / 68.7 GB (**90%**)" while `df` reports **95 %** (reserved blocks ignored), and „(/)" labels the data volume `/mnt/sys_drive`; the deploy page says nothing about free disk. **Added by the i18n spike (2026-09-17, controller v0.247.0):** (12) **six formal („ön") forms in the converted dashboard copy** — „Olvassa be telefonnal" (launcher QR hint), „Biztosan kikapcsolja a megosztást?" (launcher), „Ha újratelepíti … importálnia kell" (the layout's remove-app modal), „Kérjük, vegye fel a kapcsolatot" (backups empty state). They were NOT fixed — a localisation release may not change Hungarian bytes — and are now COUNTED by `controller/scripts/i18n_missing_gate.py` (`HU_FORMAL_CEILING` = 6, a ratchet: a new one convicts, fixing one lowers it). The inventory (`audits/I18N-INVENTORY-2026-09-17.md`) is the list this row closes against in localisation slice 6 (R-561). **Extended 2026-09-17 by slice 1 (controller v0.248.0–v0.250.0):** the converted copy now counts **16** formal forms (`HU_FORMAL_CEILING` 6 → 10 → 12 → 16, each raise stated, Hungarian unchanged by rule) — and the count is an UNDER-count: the gate's stem list sees 4 on the release C pages (storage, drive wizards, debug), while a wider list („írja be”, „adja meg”, „adjon hozzá”, „válassza ki”, „biztosan eltávolítja”, „engedélyezze”, „hozzon létre”, „kattintson”) finds at least **22** keys there alone (login „Adja meg a jelszavát”, the NAS guide, the storage confirms). Widen the stems when this row is worked; the ceiling rises with them. **NARROWED 2026-09-20 by localisation slice 6's walk, item by item** (`audits/i18n-slice6-2026-09-20/R-516-item-by-item.md`): item 2 FIXED (slice 1), items 3 and 6 APP-OWNED (and for an English household item 6 is an advantage), item 11 is a wrong NUMBER rather than a language and needs its own row, item 1 is correct English for an English reader and still open for a Hungarian one. **Items 4, 7, 8, 9 and 10 are NOT DECIDABLE FROM AN ENGLISH WALK** - they are about Hungarian copy quality, a disconnected drive and a full disk, none of which this walk had. **What this row is now waiting for is a HUNGARIAN walk on a box with a second drive**, not another English one; saying it closed would be the kind of closure that makes a register stop meaning anything. **-- 2026-10-08:** the recovery screen's own answers are Go literals in Hungarian only — 14 `renderRecovery` messages in `controller/internal/web/recovery_handlers.go` (seen: the safe default „A művelet nem fejeződött be…" rendered on an English page in a red-proof run). Today's new R-304 sentence is a bundle key in both languages; the 14 old ones are not. | **NARROWED 2026-09-20 - rank P3-LOW; owner: CC; needs a Hungarian walk** **2026-10-05 (burn-down night): items 1 and 4 FIXED on controller `main`** (`d7efa7b`): the menu says „Hibakeresés” (English „Debug”); the storage pages use the te-form (formal-form ceiling 17 → 14; 116 parity fixtures changed by exactly those bytes). Item 2 was already fixed. **Left:** items 5–6 (apps' own screens) and the rest. **2026-10-06: items 1 and 4 DELIVERED** (controller v0.298.0). **2026-10-06 (burn-down night, later): items 7–10 and 12 FIXED on controller `main`** (`e4774e6`, `2e5ef7e`): the disconnect time in local time; one banner per unplugged drive; „nézd meg”; the disk/memory/CPU/temperature banners in the household's language (`health.*` keys; the wire text to the hub unchanged and pinned); the last eleven counted formal forms are te-form (ceiling 14 → 0; 119 parity fixtures changed by exactly those bytes). **Left:** items 5–6 (apps' own screens); about 20 formal forms the gate does not count yet („írja be”, „adja meg”, „hozzon létre”, …) on the debug, storage, network-storage and security pages. Item 11 moved to its own row **R-889**. **2026-10-06 02:40: the bundle has NO formal form left** (controller `4c3c203`, unreleased): 49 sentences in the te-form; the gate's stem list widened (it counted 61 on the previous bundle, 0 now) with decoys and one listed third-person exception. **Left (narrowed):** Felhom-owned formal forms in Go and template literals the gate cannot read yet — the network-storage attach errors, escrow and share handlers, the single-copy notice, a settings refusal, the SMART mail, a fill-watch „Kérjük”, and the setup wizard pages; each moves into the bundle in the te-form. Items 5–6 are the apps' own screens (not ours). **2026-10-06: items 7–10, 12 and the bundle's 49 formal forms DELIVERED** in controller v0.299.0. **2026-10-06 night: the Go-literal leftover moved** (controller main `3d6ba28`, unreleased): 22 Go-literal messages — escrow handler (6), share password page (2), export upload (1), network-storage uid/remove/attach failures (13) — are bundle keys (`api.escrow.*`, `api.share.*`, `api.export.*`, `api.netstorage.*`) in the te-form with English (14 were formal); a detached attach failure renders in the reader's language; the NAS refusal says „Válassz". `TestR516_GoLiteralFormalFormsAreGone` (source scan + positive control), `TestR516_NetAddFailureFollowsTheReader`; red-proofs `audits/night-burndown-2026-10-06/ctrl/R-516-red*.txt`. **Left:** the setup wizard and recovery-info.txt (R-554); the SMART and fill-watch texts (the hub event's message — wire text, needs the household-copy producer shape); items 5–6 (apps' own screens). | — | — | CC |
+| **R-1273** | Install & onboarding | P3 | **An install that fails on the image registry's rate limit tells the household only „exit code 1”.** Catalog sweep 2026-10-24, code-server 16:01:37: `lscr.io … toomanyrequests` → the product cleaned up right (R-649) but the event and the card say „Alkalmazás telepítése nem sikerült: Code-Server — exit code 1”; nothing says the download server is busy and a later try works. The same install went through later (`audits/catalog-sweep-2026-10-24/code-server/`). | OPEN | — | Recognise `toomanyrequests` (and a pull timeout) in the deploy error and say „the app's download server is busy — try again in an hour”; a test with the stderr line | CC |
| **R-494** | Install & onboarding | P4 | **NARROWED 2026-09-14 by operator ruling → [P3-LOW] the hub COULD create the tunnel at customer creation, for a domain already on Cloudflare. Not blocking: every customer has their own domain and the operator creates the tunnel per day-0 A.1 (`architecture/01-topology-and-trust.md`).** *Original finding, kept:* **[P1-HIGH] A new customer's dashboard has NO reachable address unless the operator hand-makes a Cloudflare tunnel — the link in the setup-code mail is dead.** MEASURED 2026-09-14 on a fresh install from the public ISO (drill intervention **I1**): the claim mail points at `https://felhom.drill0242.felhom.eu`; that name has **no A and no AAAA** record (`dig @1.1.1.1`, control `felhom.enkisfelhom.hu` resolves); the hub has **no tunnel- or DNS-creation code** (`hub/internal/cloudflare/` holds only geo-rule removal; `cf_tunnel_token` is a pasted, optional form field, `configs.go:1478`) — day-0 runbook A.1 makes it a manual Cloudflare-dashboard step that nothing on the customer-create page asks for; the box's own split-horizon resolver on the appliance LAN IP answered `google.com` but not the dashboard name at 13:27:39Z; the agent applied the record at **13:27:44Z** (`lanresolver: applied split-horizon record … ip=192.168.0.158`, 3 m 46 s after the controller started), so the box CAN answer the name — **but only to a device that uses the box as its DNS server, and no document, screen or mail tells a household to do that**; the router and the installer-offered DNS answer nothing. The page was reachable only at the guest's LAN address with the name forced (`curl --resolve …:443:192.168.0.158`). **A volunteer could not have done that.** **What it needs:** an operator ruling — the hub creates the tunnel and DNS at customer creation, or the product gives a household a LAN address that works with no DNS change. | **READY — rank P3-LOW; owner: CC** **Re-ranked 2026-10-03: P3→P4: operator-side automation; the operator creates the tunnel by hand per the day-0 runbook.** | — | — | CC |
| **R-504** | Install & onboarding | P4 | **[P3-LOW] `iso.felhom.eu` cannot show an index page on its own — its root returns 404, and the download page lives on the website instead.** MEASURED 2026-09-14: `https://iso.felhom.eu/` and `/index.html` → 404; only named objects answer. The host is an R2 bucket behind a custom domain; whether R2 would serve an uploaded `index.html` at `/` was **not measured** (uploading anything to the public bucket is a publication). The ISO v1.27.0 task puts the Hungarian download page at `felhom.eu/letoltes` (published with the ISO, after the operator's yes). **Remaining:** a redirect from `iso.felhom.eu/` to that page needs a Cloudflare rule the session has no credential for. | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (Cloudflare rule)** **Re-ranked 2026-10-03: P3→P4: households are sent to the website's download page; the bare address is cosmetic.** | — | — | operator |
-## Apps & catalog — 16 rows (P3 6, P4 10)
+## Apps & catalog — 17 rows (P3 7, P4 10)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
| **R-1091** | Apps & catalog | P3 | **Catalog copy that is wrong or stale at the pinned tag, found writing the guides — each needs an operator word or a live check, so none was changed tonight.** From source at each app's tag (evidence per app in `audits/app-guides-2026-10-15/B/`): (1) and (2) **DONE 2026-10-16** (operator decision D12: reword): calcom's use case now names Apple Calendar or a CalDAV calendar instead of Google/Outlook, and bentopdf's tagline and use case say the browser does the work and the file stays on the device (catalog CHANGELOG 2026-10-16); (3) **sabnzbd**, **nzbget** use_cases say Radarr/Sonarr/Jellyseerr hand them jobs — the box wires only qBittorrent and Transmission (`mediawire.go`), and a hand link needs a path mapping; (4) **onlyoffice** first_steps 3–4 tell the household to wire Nextcloud by hand — the integration toggle does it (`internal/integrations/onlyoffice_nextcloud.go`); (5) **glance**, **homepage** first_steps send the household into config files in a Docker volume no household tool reaches; (6) **lubelogger** starts with only the „Dashboard" tab and in miles (shipped `appsettings.json`), so first step 3 cannot be done as written; (7) **home-assistant** first_steps promise auto-discovered devices — the app runs on a Docker bridge, where mDNS/SSDP were measured deaf (spike R-6); (8) **homebox** and **gitea** `add_people` name menus that moved or read differently at the tag; **bookstack** `default_creds` still says `admin@admin.com / password`, which after_install replaces; **dawarich** names the API key's page „Settings" (source suggests the account page); **code-server** says „install your tools" with no sudo; **komga** names the discontinued Tachiyomi; **seerr** `docs_url` points at Overseerr; **wanderer**'s comment still says it cannot close sign-up (R-714 is fixed in the same file); (9) **nzbget** and **grafana** deploy-field descriptions say the password can be changed later — nzbget re-applies its env password at every start and grafana ignores the field after first start (R-1086 is the qBittorrent/Transmission side). | OPEN — filed 2026-10-15 | — | Live-check (5)–(7) and (9) on 9202; fix (3), (4), (8) as copy with the freeze re-admitted; re-run the guide label check for any app whose copy moves | CC |
+| **R-1272** | Apps & catalog | P3 | **Homepage answers a stranger with no gate at all**, while Glance — the same class of dashboard — is behind the family gate (decision 221, S26). A stranger who reaches `homepage.` sees the box's CPU, memory and disk figures and, once the family edits it, their own links (`audits/catalog-sweep-2026-10-24/homepage/`; the stranger request → 200). | WAITING-ON-OPERATOR | the operator's word | Decide: `family_gate: true` like Glance (CC's pick: one line in the template, proven on the drill first) or leave it open | operator |
| **R-1092** | Apps & catalog | P4 | **Three apps show no guide: plant-it and home-assistant carry one HIDDEN (`checked_version: ""`), emby has none.** plant-it: `lifecycle: abandoned`, and its pinned image does not exist upstream, so there is no screen to check labels against. home-assistant: its frontend follows the browser language and the Hungarian strings are fetched at build time, not kept in git, so the Hungarian labels cannot be checked against source (the draft is written; the shipped frontend in the image could check them). emby: its server's web UI is in no public source at 4.11.0.4. Evidence: `audits/app-guides-2026-10-15/B/`. The other 62 templates show a checked guide (controller ≥ 0.315.0). | OPEN — filed 2026-10-15 | — | home-assistant: check the Hungarian labels against the frontend files in the pinned image (read-only, on a box running it), then set checked_version; emby: label-check against the image's own web files the same way; plant-it: nothing while abandoned | CC |
| **R-676** | Apps & catalog | P3 | **[P3-LOW] Watch: immich's first start restarted 12 times — decision 28's crash-loop stop (6 in 10 min) would stop it.** From the 2026-09-17 chaos night (DB connection dropped during the first-start geocoding import on a 6 GB guest; it did not recover that night). No healthy app in any drill evidence restarts on a first start (1831 samples, 40 live containers), so the threshold stands; this row exists so the first immich install under v0.269.x is watched. `audits/night-2026-09-24/A3/40-first-start-restarts.txt` **2026-09-25 night (read from source, v0.271.0): a DEPLOY's first start is NOT covered by decision 28's suppression** — `Deploying` clears when `compose up -d` returns (`deploy.go` "Clear deploying flag"), and `ObserveUnhealthy` then samples the app; an automatic update's step, verify and undo ARE covered (`Updating`, pinned by `TestD28_NoCrashLoopStopDuringAnAutomaticStep`). So a first start that restarts ≥ 6 times in 10 min is stopped — which R-676 already accepts for a broken first start; a healthy slow first start would be stopped too. **-- 2026-09-30: the first-start restarts are explained.** immich's first-start geodata import OOM-kills its database at 512M on a guest with no swap (R-732, measured: 61–104 kills); the 2026-09-17 chaos-night case (DB connection dropped during the import on a 6 GB guest) fits it. Fixed in the catalog (`56c4888`, 768M). The watch itself (decision 28 on a DEPLOY's first start) is unchanged. | **OPEN — P3; owner: CC (watch)** | — | — | CC |
| **R-1028** | Apps & catalog | P3 | **Plex's claim code can run out during the install, and the box cannot recover it.** plex.tv's code lives 4 minutes from the moment the household copies it; the clock covers the wizard, the image pull (`plexinc/pms-docker` is 351 MB, measured) and the first start. Plex reads `PLEX_CLAIM` only on its first run, and the field is `locked_after_deploy` — so a late code leaves an unclaimed server and the only way back is remove + install again. Reported by the operator during the 2026-10-14 test; on Tester 1's line the pull+start took 8.5 s and the claim worked (`audits/media-all-drives-2026-10-14/``G-auth/G3-plex-claim.txt`), so it bites on a slow line or a slow hand. **K6, 2026-10-14 night (`audits/media-drive-events-2026-10-14/``K6-1-unclaimed-plex.txt`):** an unclaimed Plex starts with no code at all, and `POST /myplex/claim?token=` on the RUNNING server reaches plex.tv (a wrong code → 500 after plex.tv's 401). So the box can pull + start first and ask for the code after: no race. A real claim needs the household's code — the morning step on the throwaway `plex-k6` on Tester 1. Narrowed 2026-10-14 night. **PROVEN 2026-10-15 morning (`K6-2-claim-after-start.txt`):** the operator's real code, given to the RUNNING unclaimed `plex-k6` → 200, `claimed` 0→1, `PlexOnlineToken` written, and the open door closed (no token → 401). `ADVERTISE_IP` was unset and the claim did not need it; whether clients find the server without it was not measurable (the throwaway had no published port). **BUILT 2026-10-15 (v0.313.0):** `after_start` field — not asked at install; the Plex page asks for the code once Plex runs and claims the running server; the gate opens only when Plex says claimed. Proven up to the code on 9201 (G5). | **NARROWED** — the dashboard claim with a real code is the last step | a household Plex code | Claim through the Plex page with a real code (G5c); then close | CC |
@@ -142,7 +144,7 @@ stopping line that lies.
| **R-1043** | Apps & catalog | P4 | **Sonarr, Radarr and Prowlarr build their login redirect as an absolute `http://` URL.** They trust forwarded headers only from their „Trusted networks” (the household set `192.168.0.0/24`; traefik is `172.18.x`), so they ignore `X-Forwarded-Proto: https` and answer `Location: http:///login` to an https visitor. Since controller v0.312.0 that hop is sent back to https by traefik (a GET, no password), so it is cosmetic; a template could seed traefik's network as trusted. (`audits/https-only-2026-10-14/``1A-3-4.txt`) | **OPEN** — filed 2026-10-14 | — | Seed the docker network as a trusted proxy in the *arr templates (with the R-1030 seed), measure the redirect | CC |
| **R-1099** | Apps & catalog | P4 | **The N100 may hold RomM games in the old upload place, now shown under a fake „roms” platform.** Until 2026-10-16 RomM's own upload wrote to the drive's `roms/roms//`; after the mapping fix (catalog `fb18471`, R-1089) those files are at RomM's `library/roms/roms/…`. Measured on 9201: such a game showed as missing in its platform and again under a platform „roms” (`audits/romm-ghost-2026-10-16/B/b-after.txt`). Files put in with the file manager are not affected — they are now found. The N100 runs RomM (hub `/apps/romm`); CC does not log in to the lived-in box. | OPEN — filed 2026-10-16 | Operator: look at `roms/roms/` on the N100's drive in the file manager | If it holds platform folders: move them up one level into `roms/`, then run „Scan” in RomM; if it is empty, close | Operator |
| **R-1215** | Apps & catalog | P4 | **One Immich photo upload hung 10 minutes with no answer and was not stored, while the box was healthy.** Night soak 2026-10-21 (`audits/night-2026-10-21/P1-soak/08-load/proof.log`): cycle 36, `IMG_20120021.jpg` sent 19:38:30 UTC, the uploader gave up at its 600 s read limit; Immich's database holds 302 photos for that user, the other cycles 303 (`P1-soak/09-immich-cycle36.txt`). At that moment memory „full" pressure was 3.9 % and `/api/health` answered in 0.26 s. 1 of about 26 000 uploads that night. Not diagnosed: Immich restarted at 02:16 for the off-site dump, so its log of 19:38 is gone. The Immich phone app retries a failed upload. | WATCHING — **2026-10-22 night:** not reproducible tonight; the Immich server log of 19:38 is gone (Immich restarted at 02:16 for the off-site dump). What the household sees: the upload fails after 10 minutes and the Immich phone app sends it again. | — | Watch the next long upload run with the Immich server log saved; file upstream only with a log | CC |
-| **R-1267** | Apps & catalog | P4 | **Every recreate of Immich leaves one empty anonymous Docker volume behind: the image declares `VOLUME /data`, the template does not map it.** Found 2026-10-24 (review round 2, while putting 9202 back): 9202 holds 296 empty anonymous volumes; each night chain's recreate of `immich-server` made a new one (12:58, 13:00, 13:01 — the three test runs; the two dangling ones this session made were removed by name, nothing pruned). The photos are NOT affected: Immich picks `/usr/src/app/upload` whenever both folders exist (`detectMediaLocation` in the image's `server/dist/services/storage.service.js:28-39`), and the template binds that folder (`templates/immich/docker-compose.yml:49`) — NOT-A-FINDING for data placement. **Seen again 2026-10-24 night on Tester 1:** privatebin's image declares `/run`, `/tmp` and `/var/lib/nginx/tmp` as volumes — each recreate (the night dump's stop/start) leaves three empty anonymous volumes; the same class as Immich's `/data` (`audits/restore-holes-2026-10-24/P1-tester1/42-anon-volumes.txt`). | OPEN | — | declare the image's VOLUME paths as tmpfs or named volumes in the catalog (Immich, privatebin), or remove the dangling ones a recreate leaves, by name | CC |
+| **R-1267** | Apps & catalog | P4 | **Every recreate of Immich leaves one empty anonymous Docker volume behind: the image declares `VOLUME /data`, the template does not map it.** Found 2026-10-24 (review round 2, while putting 9202 back): 9202 holds 296 empty anonymous volumes; each night chain's recreate of `immich-server` made a new one (12:58, 13:00, 13:01 — the three test runs; the two dangling ones this session made were removed by name, nothing pruned). The photos are NOT affected: Immich picks `/usr/src/app/upload` whenever both folders exist (`detectMediaLocation` in the image's `server/dist/services/storage.service.js:28-39`), and the template binds that folder (`templates/immich/docker-compose.yml:49`) — NOT-A-FINDING for data placement. **Seen again 2026-10-24 night on Tester 1:** privatebin's image declares `/run`, `/tmp` and `/var/lib/nginx/tmp` as volumes — each recreate (the night dump's stop/start) leaves three empty anonymous volumes; the same class as Immich's `/data` (`audits/restore-holes-2026-10-24/P1-tester1/42-anon-volumes.txt`). | OPEN **2026-10-24 (catalog sweep):** the same class for OnlyOffice and RomM (RomM's image volume `/romm` holds only the empty mount points of its binds); after every catalog app had been removed WITH data, the sweep box still held 52 such volumes (PrivateBin 21, OnlyOffice 8, RomM 8, Immich 3, and 12 from 12:50–12:52 before the batch, holding the same nginx folders as PrivateBin's) — remove-with-data does not see them (no compose project label). All small (4–72 KB), no household data (`audits/catalog-sweep-2026-10-24/_box/anon-volumes.txt`). | — | declare the image's VOLUME paths as tmpfs or named volumes in the catalog (Immich, privatebin), or remove the dangling ones a recreate leaves, by name | CC |
| **R-1268** | Backup & restore | P3 | **Remove with „remove backups” leaves a restore's undo copy on the drive (`backups/restore-undo//`).** Seen 2026-10-24 night on Tester 1 (restore-holes Part 1, run 1): MeTube was held for support after a failed crash put-back, then removed with `remove_backups=true` — the 1.5 GB copy stayed (the removal deletes `backups/primary` and the second-drive mirror, not `restore-undo`), and nothing lists it (`audits/restore-holes-2026-10-24/P1-tester1/14-run1-teardown.txt`; removed by hand, CC's own test data). The copy is kept on purpose while a hold exists; after the app is gone it is orphaned. | OPEN | — | Remove with `remove_backups` also deletes the app's `restore-undo` folder (under the same path guard), or lists it as a kept copy | CC |
@@ -156,7 +158,7 @@ stopping line that lies.
| **R-683** | App updates | P3 | **[P3-LOW] Watch: after a power cut during an update's health check, the hold named an HOUR-OLD second-drive copy, not the one the update's own backup should have just made.** 2026-09-24 chaos round 3 (nextcloud, `backup_max_age: 1m`): no `backing-up` phase was seen and the hold named Tier 2 at 13:04 for an update pressed at 14:04; the pre-cut controller log was lost with the container (the runner now saves it at arm time — R-320). Round 11, the same action without a power cut, named a fresh 14:34 copy and logged the Tier-2 copy. The sentence was TRUE (it named the copy it offered); the question is why the update did not back up first. Not reproduced; watch the next power-cut drill. `audits/night-2026-09-24/E/round-03*.json`, `E/round-11-controller-pre.log` | **OPEN — P3; owner: CC (watch)** | — | — | CC |
| **R-785** | App updates | P3 | **[P3-LOW] SparkyFitness is pinned 11 releases and a major behind upstream (v0.17.3; upstream v1.7.3, v1.6.0 dated 2026-07-24).** READ 2026-10-01 (`audits/visitors-2026-10-01/C/bench/C1-previous-tag.txt`). **Needs:** an update walk 0.17 → 1.x through the ladder (bench + box), after R-784 is decided. | **OPEN — rank P3-LOW; owner: CC (after R-784)** | — | — | CC |
-## Backup & restore — 52 rows (P1 1, P2 11, P3 22, P4 18)
+## Backup & restore — 56 rows (P1 1, P2 14, P3 23, P4 18)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -167,6 +169,9 @@ stopping line that lies.
| **R-1252** | Backup & restore | P2 | **One rejected backup block in an app's `.felhom.yml` makes that night's second-drive copy DELETE the app's copies of the household's files.** REPRODUCED on 9202 2026-10-24 (`audits/review-round-2-2026-10-24/``proofs/H2-bad-backup-block/`): audiobookshelf with a marker file in `media/audiobooks`; two unchanged runs kept the copy (the positive control); one bogus path in the block → „backup block rejected … matches no compose bind” → the legacy legs (appdata only) → „Tier 2 reconcile: removed stale dest dir userdata/media”; the original on the drive untouched. Mechanism: `internal/stacks/metadata.go:550-557` (any defect rejects the WHOLE block) → `appbackup/classify.go:217-221` → `backup/tier2_capture.go:84-100` → `tier2.go:492` `tier2Reconcile` (`:325-329`), against D25's own header (`tier2_kept.go:17-18`). Same family (static): a D25 kept copy is reconciled away when its leg leaves the declared set and its record stays (HUNT-2 H2, `tier2.go:485-492`); Remove with `remove_backups` deletes kept copies and leaves their records (HUNT-2 H9, `api/router.go:1086-1087`). **Fixed on main 2026-10-24 night** (controller `518a135`; Part 2): reconcile only under a valid classification; a rejected block is said on the app's status and once a day to the operator (`backup_run_failures`, leg `tier2-settings-unreadable`); kept copies stay in the keep set (H2); Remove drops the kept records it deleted (H9). **Proven live on 9202** (`audits/restore-holes-2026-10-24/P2-9202/`: two control runs, then the bogus path → „REJECTED … every existing copy … KEPT”). | **VERIFY** — fixed on main, waits for the release | the next controller release | release the controller (Monday list) | CC |
| **R-1253** | Backup & restore | P2 | **An export with „stop the app first” during another app's restore overwrites the ONE app-stop marker file — the restore's crash record and its Undo are lost; a power cut then leaves the restored app on mixed data with no put-back.** Found 2026-10-24 (HUNT-1 H3): `AppStopGuard.Begin` writes unconditionally (`internal/backup/appstop_marker.go:279-292`) and `End()` removes the file (`:306-320`); the exporter takes the guard (`internal/appexport/export.go:139-143,262-266`) and neither `StartExport` (`:173-178`) nor the web handlers (`internal/web/handler_export*.go`, grep: no restore check) look for a running restore. Static. **Fixed on main 2026-10-24 night** (controller `c9b4b82`; Part 3): an export that stops its app refuses (409, „err.appexport.another_operation_running”) while another operation of this process holds the marker (`BusyWith`, `BeginExclusive`); picked over one marker per app (smaller: the exporter and one guard method). **Proven live on 9202** (`audits/restore-holes-2026-10-24/P3-9202/`: refused during a MeTube restore, uptime-kuma never stopped; the same export after it ran). | **VERIFY** — fixed on main, waits for the release | the next controller release | release the controller (Monday list) | CC |
| **R-1254** | Backup & restore | P2 | **The hub saves a household's new escrow package in TWO writes; a failure between them leaves the new repository hash beside the OLD identity package, and the box then marks itself escrowed — on a total loss the written code opens nothing.** Found 2026-10-24 (HUNT-3 H1), read at `file:line`: `hub/internal/api/handler.go:1415` `SaveHostEscrow` commits blob + hash, `:1445` `SaveHostDRBundle` sets `identity_blob` in a second statement (`internal/store/store.go:3788-3796`; the upsert `:3490-3511` never touches it); the controller's confirm reads the hash (`felhom-controller/controller/internal/report/escrow_confirm.go:195-217`); the agent sends once. Same family (H2): a lost or late answer (30 s) tells the household „the previous code still works” when the hub may already hold the new package (`felhom-agent/internal/localapi/escrow_ceremony.go:79,532-534,639-641`). Static. **The hub half is fixed on main 2026-10-24 night** (felhom.eu `dcf4f84c`; Part 3): key, hash and identity blob in ONE transaction (`SaveHostEscrowWithIdentity`), a bad identity refused before any write; hub image `0.170.0-rc.r1254` built locally (`67db584a45d7`), NOT pushed, NOT deployed. The agent ceremony half (H2: „the previous code still works” after a lost answer) is still open. | **NARROWED** — the hub half fixed on main (waits for the hub release); the ceremony half open | the hub release (attended); the agent half | deploy hub v0.170.0 (Monday list); then the ceremony asks the hub what it holds before it says „the previous code still works” | CC |
+| **R-1269** | Backup & restore | P2 | **A reinstall's own capture rewrites the unit that „remove — keep backups” kept, so restoring that unit breaks the app and the household's item is gone.** Catalog sweep 2026-10-24, reproduced on its own (`audits/catalog-sweep-2026-10-24/_unitprobe/tandoor/`): install Tandoor, one account, „Mentés most”, remove keeping data and backups, install again (a volume app: no kept-data question) → 19:50:32 „Recovery unit captured for tandoor” rewrote ONLY the unit's `app.yaml` (checksum `0f366c97…` → `4438c1c5…`, `created_at` 19:45:26 → 19:50:32) beside the OLD data → „Visszaállítás” paired the NEW install's database password with the OLD data: „password authentication failed” ×42 (app) / ×22 (postgres), state `starting`, the account not there. Seen three times (the sweep's Tandoor cycle, this probe, AdventureLog's re-run 20:03:18 → 20:05:32 → restore); AdventureLog's first run worked only because no capture fell between. The comment at `felhom-controller/controller/internal/backup/recovery_unit.go:101-103` says the refresh never rewrites the definition away from its data. Household order: „I reinstalled, my recipes are gone — restore the backup”. The data itself is not deleted (the old volumes are in the unit). | OPEN | — | Design + fix in the controller: a capture of a NEW install must not adopt a unit whose data belongs to an earlier install (a new unit, or the old one set aside); a test in this order that fails today; then `tools/unitprobe.py` again | CC |
+| **R-1270** | Backup & restore | P2 | **A unit restore reports success while the app never came up.** Catalog sweep 2026-10-24: the controller logged „tandoor restored but health check failed: stack tandoor did not reach running state within 1m30s after restore”, and the status the restore page reads said `ok: true` — „A(z) tandoor: 3 adatkötet és az adatbázis visszaállítva — az alkalmazás újraindult.” (17:32:41; again in the unitprobe, 19:52:38). The household is told it worked (`audits/catalog-sweep-2026-10-24/tandoor/`, `_unitprobe/tandoor/record.json`). | OPEN | — | The restore's verdict consults the health result; the message says the app did not start and what to do; a test that fails today | CC |
+| **R-1271** | Backup & restore | P2 | **„Use my kept data” loaded ANOTHER box's database — a future-dated off-site copy of the rehearsal box — under today's kept files.** Catalog sweep 2026-10-24: Tester4's off-site store holds copies from the 2026-10-20 rehearsal, whose box clock was set to 2026-10-28. On the new box the question said „Az adatbázist innen töltjük vissza: távoli mentés, 2026-10-28 07:39” for Paperless-ngx, Nextcloud and Immich, and loaded it: the seeded account / user / album was not there, and Immich never answered again (404 for 20 min). RomM, whose newest copy was its own („saját mentés, 2026-10-24 19:17”), got its item back. `07` §6.5 says the load is refused when the unit „was taken of another drive” — the rehearsal box's drive was another disk, so that check did not hold here (which field it compares: not measured). The household's own local unit stays (nothing deleted). Same future-dated copies as R-1206 (that row: retention only). Evidence `audits/catalog-sweep-2026-10-24/paperless-ngx/`, `nextcloud/`, `immich/`. | OPEN | — | Read which drive identity the load compares and why the rehearsal unit passed; refuse a unit of another drive or one dated after now (or say so); a test with both; then the sweep's kept-data cycle on one app | CC |
| **R-314** | Backup & restore | P3 | **`StopAbandon` has no web route — a customer who telephones is served by a command line.** `--abandon-stop` exists on the controller binary (`cmd/controller/main.go:86`) and refuses rather than silently no-opping, which is right. But there is no handler: the only in-product way to cancel a countdown is the customer finding their recovery code (Scenario G cancels it at the moment the code proves they still have it). **An operator who is telephoned instead has to reach a shell on the customer's machine.** Used this session on the operator's ruling, container stopped first so the running controller could not overwrite `settings.json` from memory — a sequencing subtlety that is itself an argument for a route **-- 2026-10-08 design:** `audits/day-2026-10-08/design-R-314-279-177.md` — the box's own 14-day countdown has no operator door (the hub's 7-day phase does, decision 74); one door for R-314 + R-279: a fixed list of operator actions carried in the report reply. Question D1 on STATUS's decision sheet. **-- 2026-10-08 14:16 operator ruling D1 (`09` §3 decision 185):** yes — option A, a fixed list of operator actions carried in the box's report reply. | **VERIFY — 2026-10-09: DELIVERED (hub 0.144.0 + controller 0.304.0); `run_job fill-watch` proven live on the Tester 1 box (hub row „done — ran to its end"; control: the box log „checked 3 filesystem(s)"; an unknown action is refused 400). `abandon_stop` / `abandon_extend` NOT yet proven — no box has a deletion countdown; prove them on the first one.** **VERIFY — built on main 2026-10-08 (D1, decision 185), ships with tomorrow's controller + hub releases; closes after the live proof on 9202** (`abandon_stop` / `abandon_extend` through the hub's buttons). **READY (S) — NEW 2026-08-12, RANK 3** **2026-10-05 (burn-down night): NEEDS A DESIGN.** There is no operator door into a RUNNING controller (its HTTP surface is the household's session; the CLI runs in a separate process and cannot safely trigger a job in the running one). Same design as R-177 and R-279. | R-241, R-307 | An operator-authenticated POST that calls the same `StopAbandon`, so the telephone path and the code path converge | CC |
| **R-401** | Backup & restore | P3 | **Revisit the off-site integrity depth when a real store is LARGE — the default rests on ONE measurement, on ONE 134 MB store.** Controller v0.228.0 (R-399) made `--read-data-subset=100%` the default for every box. The whole justification is a single data point: `demo-hp`, 2026-08-30, 140 829 678 B / 2 651 blobs / 67 snapshots, structure 35.0 s vs 100% **39.2 s** — four seconds. Re-proven live 2026-08-31 at 38.7 s. **It does not extrapolate, and the reason is structural: the structure check's cost tracks the INDEX, a read-data run's tracks the DATA.** A 50 GB store is ~370x the data and this curve says nothing about it. **Nothing was invented from that one point** — no rotation schedule, no size threshold, no bandwidth budget — because four production designs in this project were specced against unvalidated mechanisms and all four were wrong. **`readDataSubsetRe` already accepts `n/m`**, so a rotating schedule (`1/7` on a different seventh each week) needs no parser work when the time comes; the missing input is a measurement on a large store, not code. **THE TRIGGER IS AN EVENT, NOT A DATE:** the slow-check WARN from v0.228.0 firing on any box (`integritySlowNoticeThreshold`, 5 min) — that line names the duration, the depth and this row. **WHAT HAPPENS IF NOBODY ACTS:** every box re-reads its entire store every week, however large it grows, and the first person to notice is a customer whose upload is saturated. **Whoever acts must also revisit `integrityCheckTimeout` (30 min)**, which is now the number a large store meets first. | **OPEN — WATCHING** | — | When the WARN fires: measure the curve on that store, then choose between a rotation (`n/m`), a size-conditional default, or leaving it. Do NOT choose from this row's numbers — they are the small-store case. | CC |
| **R-409** | Backup & restore | P3 | **Nothing in the product can vouch for the bytes of a restored recovery unit — the only hash record covers 0.002 % of it.** MEASURED on demo-hp 2026-08-31 against kimai's restored unit: `manifest.json`'s `checksums` object carries sha256 for `.felhom.yml` (2 235 B), `app.yaml` (488 B) and `docker-compose.yml` (2 195 B) — **4 918 bytes of a 213 231 242-byte unit**. The database dump (48 217 B) and the two named-volume tars (160 331 776 B + 52 845 056 B) — the recoverable data, 99.998 % of the bytes — have no recorded hash anywhere. **And nothing else supplies one:** restic 0.14.0's `restore --verify` is a size-and-mtime reconciliation (a size-and-mtime-preserving one-byte corruption of a 160 MB tar passed clean, red-proofed), and `restic ls --json` file nodes in 0.14.0 carry name, size, mode, uid/gid and three timestamps and **no content hash**. **So "the restore produced correct files" is currently unanswerable by any automated means.** **What is NOT claimed here:** `restic check --read-data-subset=100%` already proves the STORE's packs, and the config files that ARE hashed are the ones a wrong-content failure would be hardest to spot in. | **OPEN — MEDIUM** | R-87, R-361 | Cheapest fix, and it is already half-built: extend the capture's `checksums` to cover `db_dumps` and `volume_dumps` — R-361 already computes a canonical dump sha256 to prove itself, so the value exists at capture time. Then a restore-test has a real reference and R-87's narrow version becomes a content check rather than a completeness one. Evidence: `audits/SPIKE-restic-restore-test-2026-08-31.md` §Q2, §Q3. | CC |
@@ -177,6 +182,7 @@ stopping line that lies.
| **R-1255** | Backup & restore | P3 | **Escrow edge cases (review round 2, HUNT-3 H3/H4):** the R-1176 carry moves the newest kept package even when it holds no repository password (`hub/internal/store/escrow_carry.go:100-110` checks `identity_blob` only), while the right one stays under the deleted host (`store.go:3533-3534`); two set-asides on the same UTC day reuse a name and the purge can delete a still-stored copy's package (`hub/internal/offsitekeys/offsitekeys.go:378-385`; `store.go:4295-4300`). Static. | OPEN | — | carry the newest package that has a hash; a unique set-aside name per run; store tests | CC |
| **R-1256** | Backup & restore | P3 | **Restore edge cases (review round 2, HUNT-1 H4/H5/H6/H8):** (H4) an off-site restore whose definition write fails AFTER the compose was written restarts the app on the snapshot's compose (`internal/backup/offbox_reconstitute.go:979-986`; `cmd/controller/main.go:3318-3331`); (H5) a put-back whose stop fails goes on and can merge (`restore_crash_putback.go:155-158`; `restore.go:218` ignores `volume rm -f`), then removes the copy; (H6) a second-drive mirror can start between the web refusal and the restore's own record (`web/restore_wizard.go:226`; `opstatus.go:56-66`), and the install-time kept-data load checks only RestoreStatus/IsRunning (`api/kept_install.go:89-92`); (H8) an unused restore copy is never cleaned up. Static. | OPEN | — | one attended pass over the restore paths with these four as tests | CC |
| **R-1259** | Backup & restore | P3 | **The DooPlex→ep0 copy jobs: three edges and tomorrow's clock change (review round 2, HUNT-2 H6–H8, HUNT-4 H1).** The release copy keeps the newest 5 agent versions whether vouched or not, so five unvouched releases drop the vouched one from ep0 (`scripts/release-copy/felhom-release-copy:199,218,237`); its `rsync --delete` removes old versions during the transfer and mirrors a shrinking registry as deletions (`:190,237`); the hub-DB push has no lower age bound (`scripts/hub-db-backup/felhom-hub-db-backup:41,49-50`). VERIFIED on DooPlex: on 2026-10-25 the 02:30 CEST push runs at 00:30Z (`systemd-analyze calendar`) and the hub's 02:00 slot at 01:00Z (Go takes the repeated hour's second pass), so the push re-sends the 20:00 snapshot and the off-site hub DB is ~13.5 h old until 08:30. Operator data only. | OPEN | — | always keep the vouched agent; prune after a verified copy; a future-age bound; the push slot after the hub's in UTC | CC |
+| **R-1274** | Backup & restore | P3 | **The restore refusal tells the household to „turn on remote backup, or connect a second drive” when the box has both and their first copy has not run yet.** Catalog sweep 2026-10-24, Grimmory and Calibre-Web: „Mentés most” makes the local copy only (`07` §8, by design), so the drive files had no copy yet; the refusal's sentence is `restore.refuse.files.none` (`felhom-controller/controller/internal/web/handlers.go:1835`) whatever the box has. The Hungarian sentence is frozen by `i18n_go_parity`, so the fix is a NEW key („the first copy is made in tonight's backup”) chosen when a tier is set up but holds nothing yet. | OPEN | — | The new key + the branch + a test | CC |
| **R-91** | Backup & restore | P4 | Old 13 GB datastore copy at `/srv/pbs-felhom` on ep0's root disk **Checked from source 2026-10-05 (burn-down round 2):** Gate is long past (row waits on demo-felhom's first post-migration PBS backup, migration 2026-07-27). Last positive record of the copy: audits/CAMPAIGN-9-restore-proof-2026-07-28.md:759 'ep0 : /srv/pbs-felhom rollback copy intact (13G)'; CONTEXT.md:3666 still says it is 13 G of dead weight awaiting R-91. No later record of deletion found (grep srv/pbs-felhom across felhom.eu). Deleting is on ep0 (protected) and needs an operator word. | WATCHING | demo-felhom's first **post-migration** PBS backup | Delete once it lands; fix `CONTEXT.md:1018` same commit | CC |
| **R-164** | Backup & restore | P4 | **C2's chain: the DB volume tar cannot be dropped until a SOUND dump predicate exists.** The unit carries both a volume tar and a SQL dump; the restore uses **both** — the dump is authoritative and replayed *after* the tar so it WINS (F17), with only the DB service up (R-47) — `internal/backup/restore_unit.go:262-266`. Dropping the DB container's tar would halve DB-app units **and** close the R-127(b) initdb-skip password trap (restored PGDATA ⇒ `POSTGRES_PASSWORD` ignored). | **BLOCKED** — on the predicate | a dump-validity predicate that is not `accounts has rows` | **The obvious gate is DEAD, measured:** `ValidateDump` warns when the `accounts` table is empty, and that warning was **correct** — the live DB genuinely had 0 accounts, and seeding one stopped the warning and put the row in the dump. But **a fresh appliance legitimately has zero accounts**, so promoting that predicate to a gate would **block every new customer's first backup**. Order: (1) a sound predicate — dump vs **live** per-table counts, not an absolute expectation; (2) warn→gate; (3) tar-drop. **Until (1), the tar is load-bearing** — not because dumps are bad, but because nothing can yet prove one is good. Pairs with **R-127** | CC |
| **R-213** | Backup & restore | P4 | **Putting files back in place — the half the recovery screen deliberately does not do.** The screen (R-193, controller v0.200.0) unlocks the repository and LISTS what is in it; restoring is per-app and lives in the backups area, and the operator ruled the two separate on 2026-08-05: *a screen that unlocks and then offers to overwrite is two decisions wearing one button*. What is missing is the step after the listing — a customer who can now SEE their files still has to work out, per app, which restore to choose. **The operator named its requirement: a live-versus-backup comparison** — the customer must be able to see what would change before anything is overwritten | **DEFERRED** — operator ruling 2026-10-12 (S18, `09` §3 decision 213): designed after the first customers. Stays P4; re-dated: look again when the first paying household has run 30 days. **OPEN — not started, deliberately** | the comparison design (nothing exists for it yet) | After the first customers | Operator + CC |
@@ -213,7 +219,7 @@ stopping line that lies.
| **R-1235** | Backup & restore | P3 | **The release copy on ep0 (D33) is proven to load, not yet to restore a registry — and it follows the newest versions, not the ones the fleet needs.** Built 2026-10-23 (`scripts/release-copy/`, `audits/day-2026-10-23/08-release-copy-D33.txt`). (a) `total-loss-of-dooplex.md` „Restore the release copy” steps 2 (skopeo push back, same digest) and 3 (agent packages back) were never walked into a real new registry — only a `docker load` on 9202. (b) The copy keeps the newest 3 image tags and 5 agent versions; it does not ask the hub for the floor and the vouched agent and always include them — a vouch more than 5 releases behind would fall out. (c) The golden (`felhom-golden`, 637 MB for 0.331.0) is not copied: a new install after a DooPlex loss needs it (the brief named images + agent packages only; one golden fits under the 3 GB cap). | OPEN | — | (a) a throwaway registry on demo-hp, push one tag back, compare digests; (b) read `/configuration`'s floor + vouched agent; (c) the operator says whether the golden goes in | CC |
| **R-1263** | Backup & restore | P4 | **Small items from review round 2:** a LOCAL restore's put-back mails the operator „its off-site restore FAILED” (`felhom-controller/controller/cmd/controller/main.go:1514-1518`, shared via `restore_unit.go:517-518`); Remove — even „keep my data” — deletes undeclared volumes labelled with the app's project, which no tier holds (`internal/stacks/delete.go:763-764`, R-1117); the capped copy's `--delete` reads the source in the daemon's mount view, the emptiness check in the controller's (`tier2.go:834` vs `:464`); stale comments — `felhom-agent/internal/localapi/backup_cap.go:15` („keep-last”) and `restore_crash_putback.go:32` (names a test file that does not exist); the qBittorrent password goes to whatever answers the DNS name `qbittorrent` (`upwatch/explain.go:94,108-113`); kept-copy Remove has a check-to-remove gap (`tier2_kept.go:92-111`); the release-copy restore check trusts hashes stored on ep0 (`runbooks/total-loss-of-dooplex.md`); rrsync without `-munge`/`-wo` (`audits/day-2026-10-23/08-release-copy-D33.txt:6`). | OPEN | — | fix in each repo's next attended pass | CC |
-## Storage & devices — 11 rows (P3 4, P4 7)
+## Storage & devices — 13 rows (P3 4, P4 9)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -228,6 +234,8 @@ stopping line that lies.
| **R-1077** | Storage & devices | P4 | **No USB enclosure that hides or fakes a disk's serial has been measured.** The storage-identity spike (2026-10-15) had none at hand and found none in earlier evidence; the design's `usb_bridge` unknown rule (`architecture/16-storage-physical-identity.md` §3) is therefore an assumption. Cheap single- and dual-bay bridges are known to report one bridge serial for any disk. Evidence: `audits/storage-identity-2026-10-15/README.md` case 4b. | OPEN | — | Buy or borrow one cheap USB enclosure (single and dual bay), run `tools/physdisk_probe.py` against it, and set the rule from what it reports. | Operator (a device) then CC |
| **R-1094** | Storage & devices | P4 | **The whole-disk format refusal tells the household to format the free part — which is refused while the other part is in use.** SEEN 2026-10-16 (controller 0.318.0): 409 „Ezen a lemezen egy használatban lévő meghajtó van, ezért a teljes lemez nem formázható. Csak a szabad részét formázhatod." — since agent 0.158.1 a part next to a mounted part can only be USED (the root wrapper trusts no „Felhom's own" claim). Evidence: `audits/storage-identity-buildB-2026-10-15/live/14-samedisk-refusal-offer.txt`. | READY | — | Reword `err.web.meghajto_hasznalatban_formazas` (hu + en): „… nem formázható. A szabad részét használatba veheted." Next controller release; the copy gates run. | CC |
| **R-1213** | Storage & devices | P4 | **Operator detail still on two household pages:** the registered drive card's `ext4 · /dev/sdb1 · Model` line (`templates/storage.html`; W14 hid only the agent drive cards), and the heading „Távoli mentés (3. mentés) — titkosított, offsite" with the English „offsite". Found by the night helper 2026-10-21 (W11/W14 follow-up). | OPEN | — | Move the line behind „Részletek"; „…titkosított, házon kívüli" | CC |
+| **R-1275** | Storage & devices | P4 | **An English household sees the drive names in Hungarian** on the install page (and wherever a storage label shows): „Belső tárhely — 52.0 GB free (default)”, „Külső tárhely (hdd_1)” (catalog sweep 2026-10-24, `audits/catalog-sweep-2026-10-24/navidrome/page-install-en.txt`). The label is stored once, in Hungarian, when the drive is found (`felhom-controller/controller/internal/settings/settings.go` `InferStorageLabel`); a household may rename it. | OPEN | — | Render a label that still equals the inferred default in the reader's language; a test per language | CC |
+| **R-1276** | Storage & devices | P4 | **„Remove with data” leaves the app's empty parent folder** (`/appdata/`) when the template binds a subfolder: Grimmory, RomM, Paperless-ngx (catalog sweep 2026-10-24; 4 KB each; the bound folders were removed). Harmless (empty, not counted as old data), untidy for a household that browses the drive. | OPEN | — | Remove the parent when it is empty after the bound folders go; a test | CC |
## Security & access — 25 rows (P1 2, P2 4, P3 13, P4 6)
@@ -342,7 +350,7 @@ stopping line that lies.
| **R-990** | Business & legal | P4 | **Operator: read `documentation/audits/forum-research-2026-10-12/FELHOM.md` §5 and rule on each recommendation.** READ-ONLY research 2026-10-12: three years (#7943–#11092, 2,908 posts, 195 people, 82 beginner threads) of the public PROHARDVER! topic „Home server / házi szerver építése”, tagged and counted by person (`FINDINGS.md`, method and spot-check in `METHOD.md`; no username or post text in git). Ten ranked recommendations, none acted on; the top three: a „which machine works” page (8 of 33 beginners who name their hardware own only a Synology, a router disk or a Raspberry Pi — the installer cannot run there; the same gap is R-989's first recommendation from a different source, and the shipped-page half is R-991), „you do not choose an operating system — we do” (the biggest beginner question, 20 of 82 threads), and „bring your old office PC” as the cheap entry. Catalog gap (≥ 3 people): a DLNA server (7), an ad/DNS blocker (5), a camera recorder (5). | **WAITING-ON-OPERATOR** — filed 2026-10-12 | the operator's reading | Operator: rule on each of the ten (yes / no / later). If nothing is done: nothing changes; the research ages | operator |
| **R-1035** | Business & legal | P4 | **Did the „felhő tárhely” page earn anything? Two dated checks.** **Baseline (reported by the operator from Search Console, 2026-10-14, last 3 months):** 1 click, 48 impressions, CTR 2.1 %, average position **73.6**; „felhő tárhely” 19 impressions, „felhőtárhely” 5, „felhő alapú tárhely” 3. CC measured separately that the phrase „felhő tárhely” appeared **0 times** on the home, FAQ and backup pages — Google was showing the home page for those queries by accident. `/sajat-felho-tarhely` + `/en/own-cloud-storage` published **2026-10-14**; full baseline, price sources and the power provenance in `audits/seo-2026-10-14/BASELINE.md`. **What to measure, both times:** impressions and average position for „felhő tárhely” and „saját felhő tárhely”, plus the new page's own impressions, clicks and position. **A null result at +4 weeks means nothing on its own** — a new page on a site at position 73.6 takes weeks to months to move, and „felhő tárhely” alone is held by Microsoft, Google and the big list sites; the page aims at the two longer phrases. That is why there are two checks and not one, and why neither should be read as a verdict on the copy. **There is no Search Console connector in this project, so CC cannot read these numbers** — the operator reads them, CC records and compares. **Blocked until the operator asks for indexing** (Search Console → URL-ellenőrzés → the URL → „Indexelés kérése”): until that happens, or Google finds the page itself, both checks read zero for a reason that is not the page. **This is a slow channel and does not replace talking to people.** | **WATCHING** | operator: request indexing, then supply the Search Console read | 2026-11-11: first read (+4 weeks); 2026-12-09: second (+8 weeks), compared with the first | operator + CC |
-## Process & tooling — 33 rows (P3 9, P4 24)
+## Process & tooling — 34 rows (P3 9, P4 25)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
@@ -363,7 +371,7 @@ stopping line that lies.
| **R-579** | Process & tooling | P4 | **[P3-LOW] Five page shells loaded `style.css` with NO cache-buster, so a browser holding an older copy kept being served CSS that did not know about the newest UI.** FOUND 2026-09-18 by the operator's screenshot of the v0.254.0 language globe: it rendered as a bare, unstyled `` — a stray triangle and two plain words outside the card — because `login.html`, `claim.html`, `recovery.html`, `launcher_shared.html` and `launcher_share_password.html` requested `/static/style.css` with no `?v=`, while `layout.html` has used `?v={{.Version}}` since v0.166.0. **`.Version` was also absent from three of those five data maps.** FIXED AND CLOSED in the same session (controller v0.255.0): the parameter on all five, and `Version` set once in `executeTemplateLang` so a new shell cannot miss it; `TestGlobeOnAnonymousShells` now refuses an absent or EMPTY `?v=`. **The general form, which is the part worth keeping: a template that loads a versioned asset WITHOUT its version is invisible to every test that reads markup — the markup is correct and the browser fetches the wrong file.** A gate over "every stylesheet/script link in a template carries `?v=`" would catch the class; not built, because 8 first-boot-wizard templates would fail it and R-554 deletes them. | **DEFERRED** (2026-10-03 triage: the row's verdict was finished, but it names open work no other row carries — the gate "every stylesheet/script link carries `?v=`" was deliberately not built until R-554 deletes the old wizard; nothing else owns it) — **CLOSED 2026-09-18 - controller v0.255.0** | — | — | CC |
| **R-652** | Process & tooling | P4 | **[P3-LOW] The memory watch counted the kernel's file cache as the app's memory.** MEASURED 2026-09-23 night on the bench: nextcloud 34.0.4 read **100 %** of its 1 GiB and immich's PostgreSQL **100 %**, each with **0** kernel `oom_kill`s — `memory.peak` includes page cache, which the kernel drops before it kills anything. Under the watch as built (R-635 follow-up) both would be marked `memory_tight`, and the gate would demand a raised `mem_limit` — a customer-box capacity figure — for cache. **Done the same night (09 §3 decision 22, CC — operator may reverse):** the watch samples the app's own memory (`anon` of `memory.stat`) every 15 s; the mark and the ladder's `memory_peak_pct` read it where measured; the cgroup peak stays beside it (`memory_cgroup_peak_pct`). **Open:** romm's backfilled entry carries M1's 80.9 % cgroup peak (measured before the anon sample existed) — re-measure it on its next step; and decide whether an app whose anon is low but whose cgroup stays pinned at its limit (cache thrash) should be marked at all. Evidence: `audits/night-2026-09-23/apps/nextcloud/bench-1024M/`, `apps/immich/bench-noanon/`. | **READY — P3; owner: CC (catalog harness)** **Re-ranked 2026-10-03: P3→P4: the main fix is done; what is left is harness tuning, no household meets it.** | — | — | CC |
| **R-693** | Process & tooling | P4 | **[P3-LOW] The memory watch marks a Node app `memory_tight` at any limit — its heap sizes itself from the limit.** Measured 2026-09-25 on the bench (docmost 0.96.0, harness v4): the app's own memory (`anon`) peaked at **349 MB of 384 MB (90.9 %)**, then, with the limit raised to 512 MB, at **431 MB of 512 MB (80.4 %)** — 0 OOM kills and 0 restarts in both 10-minute watches (~12 000 requests each). So the mark (decision 22's "does not fit the memory") fires for an app that fits, and the gate's remedy (raise the limit) cannot clear it. docmost moved with the limit raised to 512 MB (decision 39). **Needs:** a basis that tells growth-to-fill from pressure (e.g. kills/restarts plus a GC-pressure signal, or a second watch at a higher limit showing the peak scales), or a per-app `memory_scales_with_limit` fact. `audits/night-2026-09-26/C/bench-run1/`, `…/bench-run2/` | **OPEN — P3; owner: CC** **Re-ranked 2026-10-03: P3→P4: a harness judgement problem; no household meets it.** **2026-10-06 night: skipped — a design:** changing when an update is marked „memory tight" changes what the update ladder records and accepts; the row offers options. | — | — | CC |
-| **R-739** | Process & tooling | P4 | **[P3-LOW] The test bench cannot run wanderer at all: its web server calls the database at the PUBLIC name `https://.`, which the bench has no name or TLS for.** MEASURED 2026-09-30 (more-night-apps brief, Part B): on bench 9401 the catalog template (v0.20.0) came up `wanderer-db` healthy, `wanderer-search` healthy, `wanderer` **unhealthy** for 12 min, every page 500 („Error 0: Something went wrong"); `PUBLIC_POCKETBASE_URL=https://hike-db.gate.invalid`. So the harness can only ever answer `inconclusive` at FROM for wanderer, never about an update. Its step `v0.20.0 → v0.21.0` (web + db) and meilisearch `v1.36 → v1.54` stay untested; **the brief's question — does the search index survive meilisearch's move or is it rebuilt — is NOT measured.** **Needs:** a bench venue that gives the stack the DB name (an `extra_hosts` + plain-http override in the bench's render only, stated in the verdict), or wanderer proven on the box venue alone with the operator's word. `audits/more-night-apps-2026-09-30/B/wanderer-probe.txt` **-- 2026-09-30 late: the bench CAN run wanderer now** — `upgrade-test.py` `BENCH_ENV_OVERRIDES` points `PUBLIC_POCKETBASE_URL` at the database container on the bench only (the only address the web image reads, measured in v0.20.0 and v0.21.0), recorded in every verdict: web 200, sign-up (`PUT /api/v1/user`) 200, login 200. **The meilisearch question, answered:** v1.54.2 REFUSES v1.36's database („Your database version (1.36.0) is incompatible”); with `MEILI_UPGRADE_DB=true` it upgrades in place and all three indexes (actors, lists, trails) are there — so wanderer's step needs that switch in the template first. Not done: a fixture (creating a list answered PocketBase's „Failed to create record” — likely a rule for unverified users), whether a household's record survives in the index, the step itself. `audits/night-rulings-2026-09-30/` | **NARROWED — the bench runs it; the step needs a fixture and `MEILI_UPGRADE_DB`; owner: CC** **Re-ranked 2026-10-03: P3→P4: test bench coverage; the template switch and fixture are tooling work.** | — | — | CC |
+| **R-739** | Process & tooling | P4 | **[P3-LOW] The test bench cannot run wanderer at all: its web server calls the database at the PUBLIC name `https://.`, which the bench has no name or TLS for.** MEASURED 2026-09-30 (more-night-apps brief, Part B): on bench 9401 the catalog template (v0.20.0) came up `wanderer-db` healthy, `wanderer-search` healthy, `wanderer` **unhealthy** for 12 min, every page 500 („Error 0: Something went wrong"); `PUBLIC_POCKETBASE_URL=https://hike-db.gate.invalid`. So the harness can only ever answer `inconclusive` at FROM for wanderer, never about an update. Its step `v0.20.0 → v0.21.0` (web + db) and meilisearch `v1.36 → v1.54` stay untested; **the brief's question — does the search index survive meilisearch's move or is it rebuilt — is NOT measured.** **Needs:** a bench venue that gives the stack the DB name (an `extra_hosts` + plain-http override in the bench's render only, stated in the verdict), or wanderer proven on the box venue alone with the operator's word. `audits/more-night-apps-2026-09-30/B/wanderer-probe.txt` **-- 2026-09-30 late: the bench CAN run wanderer now** — `upgrade-test.py` `BENCH_ENV_OVERRIDES` points `PUBLIC_POCKETBASE_URL` at the database container on the bench only (the only address the web image reads, measured in v0.20.0 and v0.21.0), recorded in every verdict: web 200, sign-up (`PUT /api/v1/user`) 200, login 200. **The meilisearch question, answered:** v1.54.2 REFUSES v1.36's database („Your database version (1.36.0) is incompatible”); with `MEILI_UPGRADE_DB=true` it upgrades in place and all three indexes (actors, lists, trails) are there — so wanderer's step needs that switch in the template first. Not done: a fixture (creating a list answered PocketBase's „Failed to create record” — likely a rule for unverified users), whether a household's record survives in the index, the step itself. `audits/night-rulings-2026-09-30/` | **NARROWED — the bench runs it; the step needs a fixture and `MEILI_UPGRADE_DB`; owner: CC** **Re-ranked 2026-10-03: P3→P4: test bench coverage; the template switch and fixture are tooling work.** **2026-10-24 (catalog sweep):** seen again on a box without DNS — Wanderer unhealthy and 404 for this reason (`audits/catalog-sweep-2026-10-24/wanderer/`). | — | — | CC |
| **R-759** | Process & tooling | P4 | **[P3-LOW] wger's onboarding record (the checklist pilot) keeps rows open that no other row owns.** 2026-10-01, `app-catalog-felhom.eu/onboarding/wger.md`: **2.5** no backup → remove → restore → read back of wger exists — the box has no per-app backup press outside an Update (R-648) and wger has no newer step to carry one; **3.7** changing the password and adding a family member not measured, and the template has no `add_people` text; **6.3** no forced-fail undo for wger; **8.2** the app page not read on 9202 this session; **9.1** the runtime volume-persistence gate not re-run (last CLEAN 2026-08-02). The other open rows have their own: 1.5 (R-755), 1.7/2.8 (R-762), 3.4 (R-763), 7.1 (R-764). wger is exempt from the onboarding gate (published before the checklist), so nothing blocks; this row is what keeps the record honest. **Needs:** the five measured on 9202 — 2.5 and 6.3 ride wger's next ladder step (the update's backing-up phase is the per-app backup). `audits/new-app-checklist-2026-10-01/` | **READY — rank P3-LOW; owner: CC (catalog)** **Re-ranked 2026-10-03: P3→P4: record-keeping for a hidden app; nothing blocks.** | — | — | CC |
| **R-786** | Process & tooling | P4 | **[P3-LOW] SparkyFitness's onboarding record has six open rows** (`app-catalog-felhom.eu/onboarding/sparkyfitness.md`): 0.5 runtime internet (food search providers), 0.7 the phone app's sign-in route through traefik, 1.6 the env names the server reads, 1.7 the entrypoint read, 5.4 a second memory watch at another limit, 8.3 no logo/screenshots on felhom.eu (404). Everything else measured this session (bench + 9202). **Needs:** each row measured, or n/a with a reason. | **READY — rank P3-LOW; owner: CC (catalog)** **Re-ranked 2026-10-03: P3→P4: onboarding record completeness; no household meets it directly.** | — | — | CC |
| **R-807** | Process & tooling | P4 | **[P3-LOW] 13 apps stay UNDETERMINED because their seeds write only to the database, so their upload / media / cache / redis volumes stay empty.** MEASURED 2026-10-02 (`audits/persistence-sweep-2026-10-02/A/sweep/TABLE.md`): claper, crafty-controller, dawarich (redis), docmost, gramps-web, immich (ML cache), outline (+redis), sparkyfitness, tandoor, vikunja, wger, wishlist, zipline — plus plex (no seed route: a plex.tv claim token) and wanderer (no fixture; unhealthy under the gate). None is BROKEN: nothing was written outside a preserved folder. **Needs:** per app, a seed that uploads one file (or the volume named n/a with a reason: a redis cache, an ML model cache). | **READY — rank P3-LOW; owner: CC** **Re-ranked 2026-10-03: P3→P4: test coverage; nothing was found broken.** | — | — | CC |
@@ -379,6 +387,7 @@ stopping line that lies.
| **R-1174** | Process & tooling | P4 | **The status gate becomes a refusal on 2026-10-27.** `scripts/status_view_gate.py` (2026-10-20) checks root `STATUS.md` on every push: at most 50 lines and 6,000 characters outside the decide table, one „Updated" paragraph of at most 3 sentences with no „Earlier" chain, English outside quotes, every cited R-n an open row, no decided, closed or done row in the decide table, the P1 row under „What is broken" or „decide", and every open row whose Owner names the operator under „decide" or „do". Until `SWITCH_DATE` (2026-10-27, one constant in the gate) a conviction prints a WARNING and exits 0; from that date it exits 1. INCONCLUSIVE (no sections, no register) exits 2 at once. Decoys: `scripts/test_status_view_gate.py` (39 cases; each check red-proved by removing it, the date red-proved on both sides), run by `test_gate_decoys.py` and `script_tests_gate.py`. | WATCHING — filed 2026-10-20 | the date | On or after 2026-10-27: see one real refusal (exit 1 on a page that breaks a check — a hand run on a copy is enough), write it here, clear the due check, close | CC |
| **R-1236** | Process & tooling | P3 | **Gitea (the code and the registry) is OOM-killed at its 1 GiB limit — 4 restarts in 17 days, the last at 06:41:10 UTC on 2026-10-23, six seconds after the global floor moved three boxes to a new controller image.** Read 2026-10-23 (`kubectl get pod`: `lastState.terminated.reason OOMKilled`, exit 137; kernel: „git invoked oom-killer”; limit `memory: 1Gi`, request 256Mi; 620 Mi in use at rest). During a restart a box update, an agent package fetch, a CI clone or a push fails. Not changed: DooPlex's configuration is the operator's. | OPEN | the operator's yes (a DooPlex change) | Operator: raise the limit (e.g. 2 GiB; DooPlex has the RAM) — CC's pick; or keep it and accept a restart in release hours | operator |
| **R-1264** | Process & tooling | P4 | **Skills tooling (review round 2, DOC-B U7/S22):** the grandfathered skill has no size cap — felhom-build-deploy is 240 lines while R-394 recorded 179 (`scripts/check_skills.py:45-47,98-101`); a NEW skill folder (`skills/felhom-web-design`) is not live until `install_skills.py` runs again (not run: no DooPlex change in this unattended run). | OPEN | — | cap the grandfathered entry at its current size; run install_skills.py in an attended session | CC |
+| **R-1277** | Process & tooling | P4 | **The catalog's box fixtures drifted from the apps they test** — fixed only in the sweep's copy (`audits/catalog-sweep-2026-10-24/tools/upgrade_fixtures_box.py`, marked SWEEP COPY): OpenGist 1.15 signs up at `/-/register`; Calibre-Web's admin is the generated ADMIN_USER; Mealie's after_install replaces the factory password (the seed raced it); Papra 26.6 needs an Origin header; Rallly 4.15 closed password sign-up (no fixture possible by password); Vaultwarden 1.37.4 answers 404 on `POST /identity/accounts/register` (the fixture was written on 1.36; the admin invite works, the invited sign-up has no route — the newer clients' register/finish flow);the read-back through a family gate needs a fresh cookie after the setup gate opens (Grimmory stayed inconclusive). New fixtures for Homebox, Immich, Komga, Jellyfin, Ghost, Radarr, Sonarr in `tools/sweep_fixtures.py`; `box_walk.py` gained a `sweep` target. | OPEN | — | Port them into `app-catalog-felhom.eu/scripts/` with the bench tests | CC |