clusev/docs/superpowers/specs/2026-06-19-help-page-design.md

8.6 KiB

Hilfe-Seite (In-Panel-Dokumentation) — Design

Goal: Eine eigene, bilinguale Hilfe-Seite im Panel, die alle Einstellungen und Abläufe erklärt — inklusive einer generischen Schritt-für-Schritt-Anleitung, wie man Clusev hinter einem externen Reverse-Proxy ("Proxy Manager") betreibt.

Architecture: Eine neue Full-Page-Livewire-Komponente unter /help mit linker Themen-Navigation (wie die Einstellungen). Kurze Chrome-Strings (Nav-Labels, Seitentitel) liegen in lang/{de,en}/help.php; der lange Fließtext liegt als Blade-Partials pro Sprache und wird nach aktiver Locale eingebunden. Keine neuen Tabellen, kein State außer dem gewählten Thema.

Tech Stack: Laravel 13, Livewire 3 (class-based), Tailwind v4 @theme-Tokens, bestehende Blade-Komponenten (x-panel, x-icon, …).


1. Platzierung & Navigation

  • Komponente: App\Livewire\Help\Index (Ordnerkarte R6), View resources/views/livewire/help/index.blade.php.
  • Route: Route::get('/help', Help\Index::class)->name('help') in der onboarded-Gruppe von routes/web.php (gleiche Middleware-Gruppe wie Settings/System; hinter Auth + EnsureSecurityOnboarded).
  • Sidebar: neuer Eintrag „Hilfe" unten (nach „Version"), Icon z. B. help-circle (Lucide, inline via x-icon). Label lokalisiert (__('shell.nav_help')).
  • Command-Palette: Eintrag in resources/views/components/command-palette.blade.php ($nav) + Chord g h in CMDK_GO (analog zu den bestehenden g <key>).
  • Layout: layouts.app.
  • Route-Pfad englisch (R13), sichtbares Label deutsch/englisch (R9/R16).

2. Aufbau der Seite

  • Öffentliche Property public string $topic = 'overview'; — der gewählte Themenschlüssel.
  • mount() akzeptiert optional ein ?topic-Query/Param, validiert gegen die bekannte Themenliste, fällt sonst auf overview zurück (kein Lockout, kein 404 für unbekannte Keys → Default).
  • Links: Themenliste (Buttons wire:click="$set('topic', '<key>')", aktives Thema hervorgehoben — gleiche Optik wie die Settings-Tabs in settings/index.blade.php).
  • Rechts: @include('livewire.help.content.'.app()->getLocale().'.'.$topic) mit Existenzprüfung; fehlt das Locale-Partial, Fallback auf de.
  • Responsive (R7): links Themen-Nav, die auf schmal über dem Inhalt als horizontale/aufklappbare Liste erscheint (gleiche Technik wie Settings-Tabs).

Themenliste (Reihenfolge)

Key Label (de) Inhalt-Kurzfassung
overview Überblick / Erste Schritte Was Clusev ist, Erst-Login (admin@clusev.local / clusev, Zwangswechsel), Navigation, Bare-IP vs. Domain.
domain-tls Domain, TLS & Reverse-Proxy Drei Modi (Bare-IP, eingebautes TLS/Let's Encrypt, externer Proxy); Schritt-für-Schritt-Proxy-Anleitung; TRUSTED_PROXY_CIDR; Neustart-Boundary.
security Sicherheit & 2FA TOTP, Security-Keys (YubiKey), Backup-Codes; 2FA-Zugangspfad-Hinweis (s. u.); Passwort-Manager-Extension-Hinweis (Bitwarden/Kaspersky).
updates Updates & Versionen Auto-Check, „Jetzt aktualisieren"-Knopf, CLI sudo ./update.sh, was beim Update passiert (Build/Migrate).
servers Server & SSH Server hinzufügen, SSH-Credential-Vault, Hardening, SSH-Key-Provisioning.
sessions Sitzungen & Mehrbenutzer Aktive Sitzungen sehen/widerrufen, weitere Admins, Audit-Attribution.
email E-Mail (SMTP) SMTP für Passwort-Reset konfigurieren + Testmail.
audit Audit-Log Was protokolliert wird, Retention.
recovery Konto-Wiederherstellung Forgot-Password (E-Mail-Link / 2FA-Proof), Bare-IP-Recovery, clusev:reset-admin.

3. Inhalt zweisprachig

  • Chrome (kurz): lang/de/help.php + lang/en/help.php — Seitentitel, Eyebrow, Untertitel, die Themen-Labels (topic_overview, topic_domain_tls, …), nav_help in shell.php.
  • Lange Texte: Blade-Partials je Sprache:
    • resources/views/livewire/help/content/de/<topic>.blade.php
    • resources/views/livewire/help/content/en/<topic>.blade.php
    • Reines Markup mit Überschriften, Absätzen, Listen und Code-Blöcken (für Proxy-/CLI-Beispiele). Nur @theme-Token-Utilities (R3), keine Inline-Styles (R4), kein Emoji (R9). Native Tokens (X-Forwarded-Proto, TRUSTED_PROXY_CIDR, sudo ./update.sh) bleiben als font-mono.
  • Locale-Auflösung im View über app()->getLocale(); Fallback de, wenn das EN-Partial (noch) fehlt — so bricht nichts, falls eine Sprache nachgezogen wird.

4. Schlüssel-Inhalte (verbindlich)

4a. Proxy-Anleitung (in domain-tls) — generisch, OHNE Produktnamen

  1. Im Panel: System → Domain & TLS → Domain eintragen → TLS-Terminierung „Externer Reverse-Proxy" → speichern → Stack neu starten (Knopf).
  2. Im Proxy Manager: neuen Host/Eintrag anlegen:
    • Eingehende Domain = panel.<deine-domain>
    • Ziel/Backend = http://<Clusev-Server-IP>:80 (HTTP, nicht HTTPS)
    • Host-Header durchreichen und X-Forwarded-Proto: https setzen
    • WebSocket-Weiterleitung aktivieren (für Realtime: Pfade /app/* und /apps/*)
  3. In der .env (Clusev-Server): TRUSTED_PROXY_CIDR auf die Adresse/CIDR des Proxys setzen → korrekte Secure-Cookies + echte Besucher-IP im Audit-Log; danach sudo ./update.sh (oder Caddy-Neustart).
  4. Firewall: den HTTP-Port (80) des Clusev-Servers so absichern, dass er nur vom Proxy erreichbar ist.
  5. Hinweis: In diesem Modus stellt Clusev kein eigenes Zertifikat aus — TLS kommt vom Proxy.

4b. 2FA-Zugangspfade (in security, Querverweis in recovery)

  • Security-Key (YubiKey) funktioniert nur über die HTTPS-Domain (WebAuthn braucht einen sicheren Kontext + die Domain als rpId). Über die Domain wird die Security-Key-Anmeldung angeboten und funktioniert.
  • Über den Bare-IP-/HTTP-Recovery-Pfad (http://<Server-IP>) lässt sich nicht per Security-Key anmelden — dort muss ein Backup-Code verwendet werden.
  • TOTP / „Google Authenticator" funktioniert überall — auch über Bare-IP/HTTP. Wer TOTP nutzt, braucht für den Bare-IP-Pfad keinen Backup-Code.
  • Praxis-Empfehlung: Wer ausschließlich einen Security-Key nutzt, sollte die Backup-Codes aufbewahren (einziger Weg über den Bare-IP-Recovery-Pfad). Wer zusätzlich/alternativ TOTP hat, ist auf allen Pfaden abgedeckt.

4c. Passwort-Manager-Extensions (in security)

  • Browser-Erweiterungen wie Bitwarden/Kaspersky können die Security-Key-Registrierung abfangen („Passkey speichern"). Clusev signalisiert korrekt einen Hardware-Key (cross-platform, non-resident, hints: ['security-key']), aber Erweiterungen lassen sich seitenseitig nicht abschalten. Lösung: die Passkey-Übernahme der Erweiterung für die Seite deaktivieren, oder die Registrierung in einem Browser/Fenster ohne diese Erweiterung durchführen (z. B. privates Fenster).

5. Komponenten-Logik (klein halten)

App\Livewire\Help\Index:

  • public string $topic
  • mount(?string $topic = null): validiert gegen self::TOPICS (Liste der Keys), Default overview.
  • render(): übergibt die Themenliste (Keys + lokalisierte Labels) + den aktiven $topic; die View bindet das passende Locale-Partial ein.
  • Keine Persistenz, keine externen Aufrufe, keine Berechnungen — reine Anzeige.

6. Dateistruktur

  • Neu: app/Livewire/Help/Index.php
  • Neu: resources/views/livewire/help/index.blade.php
  • Neu: resources/views/livewire/help/content/{de,en}/{overview,domain-tls,security,updates,servers,sessions,email,audit,recovery}.blade.php (18 Partials)
  • Neu: lang/de/help.php, lang/en/help.php
  • Ändern: routes/web.php (Route), resources/views/partials/sidebar.blade.php (Nav-Eintrag), lang/{de,en}/shell.php (nav_help), resources/views/components/command-palette.blade.php + CMDK_GO (cmdk-Eintrag + g h).

7. Test & Verifizierung

  • Livewire-Test (tests/Feature/HelpPageTest.php): Default-Thema = overview; $set('topic', 'domain-tls') rendert den Proxy-Abschnitt (assertSee eines bekannten Strings, z. B. X-Forwarded-Proto); unbekannter Topic-Key fällt auf overview zurück; Seite lädt für einen eingeloggten Nutzer (HTTP 200).
  • R12 Browser (auf der Domain): /help lädt mit HTTP 200, keine Konsolenfehler, keine geleakten {{ }}/group.key-Tokens; Themenwechsel funktioniert; DE/EN-Umschalter zeigt den jeweiligen Inhalt; 375/768/1280.
  • R15 Codex über den Diff.

8. Bewusst NICHT enthalten (YAGNI)

  • Keine Volltextsuche in der Hilfe (Themen-Nav reicht).
  • Keine kontextuellen „?"-Sprungmarken aus jeder Einstellung (kann später kommen).
  • Keine aus Markdown gerenderte Doku-Engine — statische Blade-Partials genügen.
  • Keine Versionierung/Changelog der Hilfe-Inhalte (das CHANGELOG deckt das ab).