fix(admin): Phase 0 — Log & Restart reparieren, Status auf Wahrheit

Wurzel-Ursache: Dienst läuft als System-Dienst, Code nutzte aber
systemctl/journalctl --user → Log leer, Restart wirkungslos.

- Log-WS (admin.py): --user → System-journalctl. Erfordert voice in
  Gruppe systemd-journal (siehe DEPLOYMENT.md 2.7.1).
- Restart (admin_llm.py): --user → sudo -n systemctl restart über eng
  begrenzte sudoers-Regel; is-active ebenfalls auf System-Dienst.
- Status (app.js): irrelevante Ollama/llama.cpp-Karte + Backend-Wechsel
  entfernt; zeigt jetzt echtes aktives LLM-Modell (aus Runtime-Config);
  Neustart in eigener "Wartung"-Karte (zieht in Phase 3 nach Konfiguration).
- DEPLOYMENT.md 2.7.1: sudoers-Regel + journal-Gruppe dokumentiert.

Live verifiziert: Log lesbar, Restart ohne Passwort, /health nach 3s zurück.
Tests: 214 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-25 02:27:18 +02:00
commit f3f9151894
4 changed files with 58 additions and 90 deletions

View file

@ -369,7 +369,7 @@ async def admin_log_ws(websocket: WebSocket, key: str | None = None):
# und der Log-Tab bliebe sonst kommentarlos leer.
try:
check = await asyncio.create_subprocess_exec(
"systemctl", "--user", "is-active", "voice-assistant.service",
"systemctl", "is-active", "voice-assistant.service",
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL,
)
out, _ = await check.communicate()
@ -378,13 +378,13 @@ async def admin_log_ws(websocket: WebSocket, key: str | None = None):
"⚠ Der systemd-Dienst 'voice-assistant.service' ist nicht aktiv — "
"die laufende Instanz wurde vermutlich manuell gestartet (uvicorn --reload). "
"Live-Logs erscheinen hier nur, wenn das Gateway als Dienst läuft "
"(systemctl --user start voice-assistant.service). Manuelle Starts loggen ins Terminal."
"(sudo systemctl start voice-assistant.service). Manuelle Starts loggen ins Terminal."
)
except Exception:
pass
proc = await asyncio.create_subprocess_exec(
"journalctl", "--user", "-f", "-u", "voice-assistant.service",
"journalctl", "-f", "-u", "voice-assistant.service",
"-n", "100", "--no-pager", "-o", "short",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,