Commit Graph

4 Commits (b9b0f62d781257bfe15f2eefef36feba94c72c62)

Author SHA1 Message Date
boban b9b0f62d78 feat(ssh): wire real fleet data over SSH (FleetService + live poller)
Replace the page mock data with real reads from the target host via the
phpseclib SSH layer. New FleetService parses raw command output into the exact
shapes the Livewire pages already consume; all parsing forces LC_ALL=C and reads
/proc to stay locale-independent.

- app/Services/FleetService.php: metrics (cpu via two /proc/stat samples, mem via
  /proc/meminfo, disk via df), full snapshot (identity/specs incl. virt+disk_gb,
  volumes, interfaces from ip+/proc/net/dev, sshd/fail2ban/ufw hardening, authorized
  keys), systemd units + journal, and an ls-based directory listing. One compound
  command per read; connect/parse failures bubble up.
- clusev:poll-metrics command replaces the mock emitter in the dev supervisor:
  polls every credentialed server, persists cpu/mem/disk/status, broadcasts
  MetricsTicked(server) — unreachable boxes flagged offline, loop never dies.
- Pages wired with graceful failure (offline state, never a 500):
  Dashboard (live cached metrics + notable units), Services (real units+journal),
  Files (real listing + dir navigation via open/go/up), Server-Details (live
  snapshot persisted onto the row + offline banner).
- WithFleetContext prefers a credentialed, non-offline server as the default.
- dualChart filters ticks by server name so the chart tracks the active host.

Verified live against a real Debian 13 box: metrics/services(91)/journal(25)/
files(navigable)/snapshot(5 ifaces, real hardening, real key) all parse correctly.
Credentials are stored encrypted in the vault — never in source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 21:34:13 +02:00
boban 218806727c feat(r5): wire-elements/modal confirmations for destructive actions
Add a generic ConfirmAction modal (LivewireUI\Modal\ModalComponent). On confirm
it persists exactly one AuditEvent and re-dispatches a page event so the origin
applies its own state change — domain-agnostic and reused everywhere (R5).

Wired the destructive actions, each writing an audit row:
- Services: start/stop/restart -> confirm + audit; service state reflects result
- Files: delete -> confirm + audit; entry removed
- Server-Details: revoke SSH key (new per-row trash button) -> confirm + audit
  (carries server_id)

Supporting changes:
- Publish + restyle the modal container for the dark theme (void backdrop +
  surface panel + shadow-pop instead of the package's gray/white defaults)
- Toaster island in the app layout that catches the `notify` browser event
- Add alert/power/rotate/trash icons to x-icon

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 15:05:50 +02:00
boban 5fce2dd757 feat: v1 pages — servers (index + details), services, files, audit + SSH layer
Five full-page Livewire routes (R1/R2) on the component kit + seeded models,
German UI, responsive, tokens-only:
- /servers: fleet overview (status KPIs, live search, rows linking by uuid).
- /servers/{uuid}: details — resource rings, specs, volumes, network interfaces,
  security hardening checklist, SSH keys (mock until the SSH layer).
- /services: systemd units (enabled/status, start/stop/restart placeholders per R5)
  + journalctl tail.
- /files: SFTP file browser (breadcrumb, perms/size/modified, actions).
- /audit: real AuditEvent log with live filter + empty state.

SSH layer (app/Support/Ssh): SshClient (exec), Sftp, CredentialVault (decrypts the
encrypted vault) — phpseclib3, validated, ready for a target server.

Verified: all pages HTTP 200, no errors; 5/5 screenshot-checked on-brand.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 06:33:59 +02:00
boban 53f7309c0b feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb
Working dev stack on :80 (Freigabe step 5: app boots, page renders, Vite HMR runs):
- Multi-stage Dockerfile (php8.3-fpm + nginx + supervisor + node). Dev runs
  php-fpm + nginx + vite in ONE app container; prod target bakes vendor + assets.
- docker-compose.yml (dev, bind-mount) + docker-compose.prod.yml (GHCR image).
  Env-driven ports/UID (APP_PORT, VITE_PORT, REVERB_HOST_PORT, DB_PORT,
  HOST_UID/HOST_GID) — nothing hardcoded. MariaDB only on 127.0.0.1:3306.
- Laravel 13, Livewire 3.8 (class-based, no Volt), wire-elements/modal 2,
  phpseclib 3, laravel/reverb 1. composer platform pinned to php 8.3.
- Tailwind v4 @theme tokens ("Tactical Terminal") in app.css; Vite remote HMR
  (host 0.0.0.0, hmr.host 10.10.90.136).
- Dashboard as a full-page Livewire route (/) in layouts/app; §5 folder skeleton.
- Docs: rules.md R1-R11 (incl. R11 UUID-in-URLs) + CLAUDE.md updated for
  Laravel 13, clusev/ root, port 80, vite-in-app, env-driven config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 00:31:50 +02:00