Commit Graph

14 Commits

Author SHA1 Message Date
Debian
f378771dca feat(dashboard): SSL card expired/expiring split + HAProxy frontend labels
Expired certs now show a red error alert ("renew immediately") instead
of being silently folded into the orange "expiring soon" warning.
HAProxy frontend technical names (public_http, public_https, mgmt_https)
now display as human-readable labels (HTTP In, HTTPS In, Management).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 18:51:59 +02:00
Debian
7f4606ba16 feat(dashboard): show HAProxy check_status code on DOWN servers
When a backend server is DOWN, the HAProxy card now shows the check_status
code (L4CON, L4TOUT, L7STS, L6CON, …) as a volcano-colored tag next to
the DOWN badge. Hovering shows a plain-English explanation of the failure
reason so operators can diagnose without leaving the dashboard. v1.1.116.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:08:34 +02:00
Debian
7c86656c36 feat(dashboard): resolve eg_backend_<id> → friendly name in HAProxy card
The HAProxy stats card now shows the configured backend name (e.g.
"My Backend/web1") instead of the internal HAProxy name
("eg_backend_1/web1"). Also surfaces the socket error message when
HAProxy is unreachable (⚠ HAProxy socket: <error>) instead of the
generic "no backends" empty state — operators immediately see whether
the box is unconfigured or the socket is down. v1.1.114.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 07:59:53 +02:00
Debian
326f79cf00 feat(dashboard): WG server tunnels show peer summary instead of per-peer rows
Server tunnels with many peers previously flooded the WG card. Now
server mode shows "X/Y peers online · ▼rx ▲tx" (3-min handshake
threshold) while client tunnels retain full per-peer detail.
Adds i18n keys dashboard.wgCard.peersOnline (EN/DE). v1.1.111.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 20:01:49 +02:00
Debian
757b58f607 feat(ux): Hostname in Sidebar + CPU-Anzahl neben Load Average
- Sidebar: Hostname unter der Versionsnummer (aus /system/health);
  10px, gedimmt — beim Verwalten mehrerer Boxen sofort erkennbar
- /system/resources: neues Feld num_cpus (via runtime.NumCPU)
- Dashboard Resources-Card: Load-Average-Label zeigt "(N CPU)" —
  1.80 auf 1 CPU ist saturiert, auf 4 CPUs ist es harmlos

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:49:15 +02:00
Debian
6e52dc0620 fix(ui): fehlende onError-Handler + i18n in Backends/Domains/Dashboard
- Backends: create + del Mutations bekommen onError; 'Backup'-Tag → t()
- Domains: create + del Mutations bekommen onError
- Dashboard: LicenseChip-Texte ('License OK', 'Trial') in t() überführt;
  useTranslation() direkt in der Komponente verwendet
- en/de: dashboard.licenseOk/licenseTrial/licenseTrialDays ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:42:37 +02:00
Debian
c9caf35596 feat(dashboard): HAProxy Listener-Stats + i18n-Relativzeit
- haproxy_stats.go: FRONTEND-Rows aus show-stat CSV auslesen und als
  frontends[] zurückgeben (Name, Sessions, MaxSess, Bytes, ReqTot/Rate)
- Dashboard: Listener-Sektion über Backend-Liste; query jetzt unified
  haproxyStats mit backends/frontends alias für Abwärtskompatibilität
- common.relTime.*-Keys (en+de) eingeführt; relativeTime/relativeFromIso
  in Dashboard + relTime in WireGuard Servers/Clients auf t-Parameter
  umgestellt statt hardcodierter Strings
- CertExpiry in Cluster-Seite nutzt jetzt certDaysRemaining/certExpiredDaysAgo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:09:53 +02:00
Debian
e18037375f fix(i18n): relative-time strings vollständig lokalisiert
relativeTime() in Dashboard, relTime() in WireGuard Clients+Servers und
CertExpiry() im Cluster-Page haben bisher hardcodiertes Deutsch
(„vor 5s", „abgelaufen vor X Tagen") gerendert, unabhängig von der
gewählten UI-Sprache.

Neu: gemeinsame i18n-Keys common.relTime.{Xs,Xm,Xh,Xd,never} in EN+DE,
sowie cluster.{certDaysRemaining,certExpiredDaysAgo}. Alle Helper-
Funktionen nehmen jetzt t() als Parameter und sind damit sprachunabhängig.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:02:27 +02:00
Debian
99982ef9d1 feat(ui): Quick-Toggles, Config-Preview, Dashboard-Alerts, Domain-Detail-Health
Quick-Toggle-Switches (kein Modal nötig) für: Backends, Backend-Server,
DNS-Zonen, DNS-Records, Domains (active), Firewall-Rules, NAT-Rules,
Forward-Proxy ACLs, Routing-Rules.

Dashboard: Alert-Banner für komplett ausgefallene Backends (HAProxy-Stats)
und Domains im Maintenance-Mode.

Domain-Detail: HAProxy-Live-Health-Badge (15s Polling), TLS-Cert
ausstellen/erneuern direkt aus dem Detail, Routing-Rules-Panel inline.

Config-Preview (Settings): alle 4 Generatoren (haproxy, nftables, squid,
unbound) rendern via RenderToString ohne Disk-Write — GET /system/config-preview.

ActionButtons: Viewer-Rolle blendet Delete aus (RBAC-Ergänzung).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 08:55:22 +02:00
Debian
9a05e8bca8 feat(haproxy): req_tot + req_rate in Stats-API; Backend-Detail + Dashboard nutzen sie
GET /haproxy/stats liefert jetzt req_tot (kumulierte Requests seit
HAProxy-Start) und req_rate (Requests/s im letzten Messfenster).
Backend-Detail zeigt in der Live-Spalte 'N sess · X/s' wenn Traffic
fließt; Dashboard-HAProxy-Card zeigt req/s ebenfalls an.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 23:03:54 +02:00
Debian
35b7308ce2 feat: umfangreiches UI+API-Polish (v1.1.36–1.1.42)
Backend:
- Audit-Log: Search-Endpoint mit ILIKE-Filter (actor/action/subject/date)
- NTP: /ntp/status via chronyc tracking (Stratum, Offset, Quelle)
- System: /service-restart mit Allowlist (haproxy/squid/unbound/chrony/scheduler)
- Domain-Response-Headers + Rate-Limit (Migration 0024)
- Join-Tokens (Migration 0025), Cluster-mTLS, Aggregator-Fan-Out
- apt-Service für Update-Banner (apt-get update + Versionsprüfung)
- Backup-Retry mit exponential backoff (retry_apt 3×)
- publish.sh fail-fast + cleanup-old.sh (max 10 Versionen)

Frontend:
- Audit-Log-Page (/audit) mit Filter + Pagination
- ErrorBoundary an React-Root + Vite build-target festgenagelt (iOS 15+)
- Storage-Schema-Stamp: auto-wipe bei Versions-Mismatch (blank-page-Fix)
- EmptyState-Komponente überall ausgerollt
- SSL: Aggregate-Karte (total/expiring/expired/errors)
- Backups: Aggregate-Karte (letzter Backup/Größe/Fehlschläge 24h) + Backup-Now
- NTP: Sync-Status-Karte (chronyc tracking live)
- Domains: Backend-UP/DOWN-Chip aus HAProxy-Stats
- Backends: HAProxy-Status-Spalte (UP/DEGRADED/DOWN)
- Settings: Service-Neustart-Karte (haproxy/squid/unbound/chrony/scheduler)
- Settings: Upgrade-Status-Card, Wartungsmodus, Auto-Update, Retention
- Dashboard: Recent-Alerts, Cluster-Health, License-Chip, Onboarding-Hint
- System-Regeln im Firewall als eigener Tab

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 16:18:41 +02:00
Debian
4a34629023 feat(audit): Live-Stream im Dashboard via WebSocket
Recent-Activity-Karte zeigt neue audit_log-Events jetzt sofort statt
in 15s-Polls.

internal/services/audit/audit.go:
  - Repo bekommt Subscribe()-Methode mit fan-out-channel (Buffer 32,
    non-blocking-send — langsame Clients droppen Events statt die
    Pipeline zu blockieren).
  - Log() macht jetzt INSERT … RETURNING id, created_at und broadcastet
    den fertigen Entry an alle Subscribers. Broadcast nur nach
    erfolgreichem INSERT — failed inserts erscheinen nicht.

internal/handlers/audit.go:
  - Neuer GET /api/v1/audit/live (WebSocket): sendet beim Connect die
    letzten 50 Einträge (oldest→newest), danach Live-Stream aus
    Subscribe-Channel. 30s-Ping gegen HAProxy-Tunnel-Timeout.
  - Recent (Poll-Endpoint) bleibt für Fallbacks erhalten.

UI Dashboard:
  - useAuditLive(keep=15)-Hook ersetzt das 15s-useQuery-Poll.
  - WebSocket auf wss://<host>/api/v1/audit/live; Auto-Reconnect alle
    2s nach Drop.
  - dedupe per id (Snapshot + erste live-Events können sich kurz
    überschneiden während des Subscribe-Race).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 15:39:04 +02:00
Debian
c7b98f196e feat(dashboard): Operations-Dashboard mit Live-Health/Resources/Audit/HAProxy
Vorher: Dashboard war Counts + statische Cards. Jetzt operativer
Überblick — was läuft, was klemmt, was wurde gerade geändert.

Backend (4 neue Endpoints):
* GET /api/v1/system/services — systemctl is-active für 8 services
  (edgeguard-api, scheduler, haproxy, nftables, unbound, chrony,
  squid, postgresql). Inklusive ActiveEnterTimestamp.
* GET /api/v1/system/resources — /proc/loadavg, meminfo, statfs(/),
  nf_conntrack count+max, uptime.
* GET /api/v1/audit/recent?limit=N — letzte audit_log entries.
  audit-Repo bekommt ListRecent + Entry struct.
* GET /api/v1/haproxy/stats — parsed haproxy 'show stat' CSV vom
  /run/haproxy/admin.sock (postinst addet edgeguard zu haproxy-
  group für socket-read; haproxy-group exists nach apt install).

Frontend Dashboard rewrite:
* PageHeader + KPI-Strip (6 tiles, wie zuvor) — bleibt.
* Resources-Strip: Load (1/5/15) + Mem-Progress + Disk-Progress +
  Conntrack-Progress + Uptime.
* Service-Health-Grid: 8 Karten mit StatusDot + state.
* Recent-Activity-Card (audit-log): action-Tag + actor + subject +
  relative time.
* HAProxy-Backends-Card: backend/server + UP/DOWN-Tag + sessions +
  bytes_in/out + last_change_age.
* WireGuard live (handshake-age, traffic) — bleibt aus früherem
  Stand.
* Cluster + Firewall + SSL + Routing Cards — bleiben.
* Polling 10s für services/resources/haproxy, 15s für audit.

Plus: postinst usermod -a -G haproxy edgeguard für admin.sock
read-permission.

Version 1.0.43.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:46:39 +02:00
Debian
b507d2a7d5 feat(ui): Frontend MVP — React 19 + AntD 6 + Vite + StaticFS-Wiring
Scaffold und Core-Infrastruktur 1:1 nach enconf-Pattern (netcell-
webpanel/management-ui), reduziert auf EdgeGuard-Scope (kein reseller/
customer-Roles, keine codemirror/extensions). Stack: React 19 + AntD 6
+ TS strict + Vite + TanStack-Query + zustand + react-i18next.

Layout: AppLayout (Sider+Header+Content), Sidebar (Dashboard/Domains),
Header (User-Dropdown + Logout). i18n mit de/en common.json.

Pages: Login (POST /auth/login), Setup-Wizard (POST /setup/complete),
Dashboard (Health-Polling + Statistics), Domains (volles CRUD via
TanStack-Query gegen /domains-API). UpdateBanner-Komponente
(/system/package-versions, alle 5 min poll, /system/upgrade trigger)
ist von Tag 1 wie vom User gefordert eingebaut.

API-Wiring: cmd/edgeguard-api/main.go mountUI() — gin StaticFS für
/usr/share/edgeguard/ui/ (overridebar via EDGEGUARD_UI_DIR), echte
Files werden direkt geserved, alle nicht-API-Pfade fallen via
NoRoute auf index.html für React-Router-SPA. Wenn dist/ fehlt:
HTML-Placeholder mit Build-Hinweis.

Verifiziert: bun install + npx tsc -b strict (0 errors) + bun run
build (12 chunks). End-to-end gegen /tmp/eg-api: / serviert echte
React-index.html, /domains SPA-Fallback, /api/v1/* JSON, /assets/*
direkt, /api/v1/nonexistent korrekt 404.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:16:04 +02:00