diff --git a/app/Livewire/Help/Index.php b/app/Livewire/Help/Index.php index 04ae037..ef6cad0 100644 --- a/app/Livewire/Help/Index.php +++ b/app/Livewire/Help/Index.php @@ -3,6 +3,7 @@ namespace App\Livewire\Help; use Livewire\Attributes\Layout; +use Livewire\Attributes\Url; use Livewire\Component; /** @@ -15,12 +16,16 @@ class Index extends Component { /** Help topics in display order. */ private const TOPICS = [ - 'overview', 'domain-tls', 'security', 'updates', + 'overview', 'domain-tls', 'security', 'updates', 'commands', 'servers', 'sessions', 'email', 'audit', 'recovery', ]; + #[Url] public string $topic = 'overview'; + // mount() handles the test/parameter-injection path (Livewire::test($class, ['topic' => …])). + // Browser deep links populate $topic via the #[Url] attribute above and bypass mount on + // hydration. Both paths are validated by the render() clamp below. public function mount(?string $topic = null): void { if ($topic !== null) { @@ -41,6 +46,7 @@ class Index extends Component 'domain-tls' => __('help.topic_domain_tls'), 'security' => __('help.topic_security'), 'updates' => __('help.topic_updates'), + 'commands' => __('help.topic_commands'), 'servers' => __('help.topic_servers'), 'sessions' => __('help.topic_sessions'), 'email' => __('help.topic_email'), diff --git a/lang/de/help.php b/lang/de/help.php index e0c7ba2..e4656a6 100644 --- a/lang/de/help.php +++ b/lang/de/help.php @@ -10,6 +10,7 @@ return [ 'topic_domain_tls' => 'Domain, TLS & Reverse-Proxy', 'topic_security' => 'Sicherheit & 2FA', 'topic_updates' => 'Updates & Versionen', + 'topic_commands' => 'Befehle / CLI', 'topic_servers' => 'Server & SSH', 'topic_sessions' => 'Sitzungen & Benutzer', 'topic_email' => 'E-Mail (SMTP)', diff --git a/lang/en/help.php b/lang/en/help.php index 2616940..78cd4a2 100644 --- a/lang/en/help.php +++ b/lang/en/help.php @@ -10,6 +10,7 @@ return [ 'topic_domain_tls' => 'Domain, TLS & reverse proxy', 'topic_security' => 'Security & 2FA', 'topic_updates' => 'Updates & versions', + 'topic_commands' => 'Commands / CLI', 'topic_servers' => 'Servers & SSH', 'topic_sessions' => 'Sessions & users', 'topic_email' => 'Email (SMTP)', diff --git a/resources/views/livewire/help/content/de/commands.blade.php b/resources/views/livewire/help/content/de/commands.blade.php new file mode 100644 index 0000000..1429237 --- /dev/null +++ b/resources/views/livewire/help/content/de/commands.blade.php @@ -0,0 +1,56 @@ +@php + $h = 'font-display text-base font-semibold text-ink'; + $p = 'text-sm leading-relaxed text-ink-2'; + $code = 'rounded bg-inset px-1.5 py-0.5 font-mono text-[12px] text-accent-text'; + $cmd = 'block w-full overflow-x-auto rounded-md border border-line bg-void px-3 py-2 font-mono text-[12px] text-accent-text'; + $real = 'mt-1 font-mono text-[11px] leading-relaxed text-ink-3'; +@endphp + +
+

Befehle / CLI

+

Auf dem Host richtet der Installer den Befehl clusev ein. Er kapselt die langen Docker-Kommandos — du musst dir weder Compose-Datei noch Container-Namen merken. Per SSH einloggen und von überall clusev <befehl> tippen. clusev help zeigt die Übersicht.

+
+ +
+
+
sudo clusev update
+

Holt die neueste Version, baut das Image neu (inkl. CSS/JS) und wendet Datenbank-Migrationen an. Braucht root (sudo). Secrets und die konfigurierte Domain bleiben erhalten; das Panel ist ein bis zwei Minuten kurz nicht erreichbar.

+

→ führt update.sh aus (git pull + Image-Rebuild + migrate)

+
+ +
+
clusev reset-admin
+

Setzt den Admin-Zugang zurück: entfernt den zweiten Faktor (2FA), sodass beim nächsten Login ein neues Passwort gesetzt werden kann. Letzter Ausweg, wenn Passwort und 2FA verloren sind (siehe Konto-Wiederherstellung).

+

docker compose exec app php artisan clusev:reset-admin

+
+ +
+
clusev restart
+

Startet den Stack neu (alle Container) und wendet Konfigurationsänderungen an, ohne neu zu bauen.

+

docker compose up -d

+
+ +
+
clusev logs
+

Folgt den Live-Logs des Stacks (z. B. zur Fehlersuche). Mit einem Dienstnamen dahinter — etwa clusev logs app — nur dessen Logs. Strg-C beendet.

+

docker compose logs -f

+
+ +
+
clusev ps
+

Zeigt, welche Dienste laufen (Alias: clusev status). Schneller Gesundheits-Check des Stacks.

+

docker compose ps

+
+ +
+
clusev migrate
+

Wendet ausstehende Datenbank-Migrationen an. Normalerweise erledigt das clusev update automatisch — dieser Befehl ist für den seltenen manuellen Fall.

+

docker compose exec app php artisan migrate --force

+
+ +
+
clusev artisan <...>
+

Für Fortgeschrittene: reicht ein beliebiges artisan-Kommando in den app-Container durch, etwa clusev artisan about.

+

docker compose exec app php artisan <...>

+
+
diff --git a/resources/views/livewire/help/content/de/recovery.blade.php b/resources/views/livewire/help/content/de/recovery.blade.php index 34c74ea..6f2b566 100644 --- a/resources/views/livewire/help/content/de/recovery.blade.php +++ b/resources/views/livewire/help/content/de/recovery.blade.php @@ -17,8 +17,7 @@

Komplett ausgesperrt (letzter Ausweg)

-

Passwort und 2FA verloren, kein SMTP? Vom Host wiederherstellen — per SSH auf den Server einloggen und im Projektverzeichnis ausführen:

-
cd clusev
-docker compose -f docker-compose.prod.yml exec app php artisan clusev:reset-admin
-

clusev:reset-admin entfernt den zweiten Faktor, sodass du beim nächsten Login ein neues Passwort setzen kannst.

+

Passwort und 2FA verloren, kein SMTP? Vom Host wiederherstellen — per SSH auf den Server einloggen und ausführen:

+
clusev reset-admin
+

clusev reset-admin entfernt den zweiten Faktor, sodass du beim nächsten Login ein neues Passwort setzen kannst. (Dahinter läuft docker compose exec app php artisan clusev:reset-admin — siehe „Befehle / CLI".)

diff --git a/resources/views/livewire/help/content/de/updates.blade.php b/resources/views/livewire/help/content/de/updates.blade.php index 48ab3dd..87bc001 100644 --- a/resources/views/livewire/help/content/de/updates.blade.php +++ b/resources/views/livewire/help/content/de/updates.blade.php @@ -10,7 +10,7 @@

Unter Version & Releases prüft das Panel beim Öffnen automatisch, ob eine neuere Version im Kanal verfügbar ist (Vergleich mit dem neuesten getaggten Release). Ist eines verfügbar, erscheint der Knopf „Jetzt aktualisieren".

Beim Update wird das Image neu gebaut (inkl. npm run build für CSS/JS) und es werden Datenbank-Migrationen angewendet. Stil-Änderungen und Schema-Updates greifen also automatisch. Secrets und die konfigurierte Domain bleiben erhalten.

diff --git a/resources/views/livewire/help/content/en/commands.blade.php b/resources/views/livewire/help/content/en/commands.blade.php new file mode 100644 index 0000000..f6f260e --- /dev/null +++ b/resources/views/livewire/help/content/en/commands.blade.php @@ -0,0 +1,56 @@ +@php + $h = 'font-display text-base font-semibold text-ink'; + $p = 'text-sm leading-relaxed text-ink-2'; + $code = 'rounded bg-inset px-1.5 py-0.5 font-mono text-[12px] text-accent-text'; + $cmd = 'block w-full overflow-x-auto rounded-md border border-line bg-void px-3 py-2 font-mono text-[12px] text-accent-text'; + $real = 'mt-1 font-mono text-[11px] leading-relaxed text-ink-3'; +@endphp + +
+

Commands / CLI

+

The installer sets up the clusev command on the host. It wraps the long Docker invocations — you never need to remember the compose file or container names. SSH in and run clusev <command> from anywhere. clusev help prints the overview.

+
+ +
+
+
sudo clusev update
+

Pulls the latest release, rebuilds the image (including CSS/JS) and applies database migrations. Requires root (sudo). Secrets and the configured domain are preserved; the panel is briefly unreachable for a minute or two.

+

→ runs update.sh (git pull + image rebuild + migrate)

+
+ +
+
clusev reset-admin
+

Resets dashboard access: clears the second factor (2FA) so you can set a new password on the next login. Last resort when password and 2FA are both lost (see Account recovery).

+

docker compose exec app php artisan clusev:reset-admin

+
+ +
+
clusev restart
+

Restarts the stack (all containers) and applies configuration changes without rebuilding.

+

docker compose up -d

+
+ +
+
clusev logs
+

Follows the stack's live logs (handy for troubleshooting). Add a service name — e.g. clusev logs app — for just that one. Ctrl-C stops.

+

docker compose logs -f

+
+ +
+
clusev ps
+

Shows which services are running (alias: clusev status). A quick stack health check.

+

docker compose ps

+
+ +
+
clusev migrate
+

Applies pending database migrations. Normally clusev update does this for you — this is for the rare manual case.

+

docker compose exec app php artisan migrate --force

+
+ +
+
clusev artisan <...>
+

For advanced use: passes any artisan command through to the app container, e.g. clusev artisan about.

+

docker compose exec app php artisan <...>

+
+
diff --git a/resources/views/livewire/help/content/en/recovery.blade.php b/resources/views/livewire/help/content/en/recovery.blade.php index 1491d19..83439a1 100644 --- a/resources/views/livewire/help/content/en/recovery.blade.php +++ b/resources/views/livewire/help/content/en/recovery.blade.php @@ -17,8 +17,7 @@

Completely locked out (last resort)

-

Lost password and 2FA, no SMTP? Recover from the host — SSH into the server and run in the project directory:

-
cd clusev
-docker compose -f docker-compose.prod.yml exec app php artisan clusev:reset-admin
-

clusev:reset-admin clears the second factor so you can set a new password on the next login.

+

Lost password and 2FA, no SMTP? Recover from the host — SSH into the server and run:

+
clusev reset-admin
+

clusev reset-admin clears the second factor so you can set a new password on the next login. (Under the hood it runs docker compose exec app php artisan clusev:reset-admin — see "Commands / CLI".)

diff --git a/resources/views/livewire/help/content/en/updates.blade.php b/resources/views/livewire/help/content/en/updates.blade.php index 663fc39..dcc1837 100644 --- a/resources/views/livewire/help/content/en/updates.blade.php +++ b/resources/views/livewire/help/content/en/updates.blade.php @@ -10,7 +10,7 @@

Under Version & Releases the panel checks on open whether a newer release is available in the channel (compared against the newest tagged release). When one is available, the "Update now" button appears.

An update rebuilds the image (including npm run build for CSS/JS) and applies database migrations. So style changes and schema updates take effect automatically. Secrets and the configured domain are preserved.

diff --git a/tests/Feature/HelpPageTest.php b/tests/Feature/HelpPageTest.php index 36b58bd..c246c55 100644 --- a/tests/Feature/HelpPageTest.php +++ b/tests/Feature/HelpPageTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature; use App\Livewire\Help\Index; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; +use Livewire\Attributes\Url; use Livewire\Livewire; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; @@ -57,6 +58,31 @@ class HelpPageTest extends TestCase ->assertSee('TOTP'); } + public function test_topic_property_is_url_bound(): void + { + $attrs = (new \ReflectionProperty(Index::class, 'topic'))->getAttributes(Url::class); + $this->assertNotEmpty($attrs, 'Help topic must be #[Url]-bound for deep links / reload'); + } + + public function test_recovery_shows_the_short_host_command_not_the_long_compose_one(): void + { + $this->actAsAdmin(); + Livewire::test(Index::class) + ->set('topic', 'recovery') + ->assertSee('clusev reset-admin') + ->assertDontSee('docker-compose.prod.yml'); + } + + public function test_commands_topic_lists_the_cli(): void + { + $this->actAsAdmin(); + Livewire::test(Index::class) + ->set('topic', 'commands') + ->assertSee('clusev reset-admin') + ->assertSee('sudo clusev update') + ->assertDontSee('docker-compose.prod.yml'); + } + #[DataProvider('topicProvider')] public function test_each_topic_renders_its_own_partial(string $topic, string $marker): void { @@ -67,12 +93,13 @@ class HelpPageTest extends TestCase public static function topicProvider(): array { return [ - ['updates', 'update.sh'], + ['updates', 'clusev update'], ['servers', 'SSH'], ['sessions', 'Sitzung'], ['email', 'SMTP'], ['audit', 'Audit'], - ['recovery', 'clusev:reset-admin'], + ['recovery', 'clusev reset-admin'], + ['commands', 'clusev ps'], ]; } }