Commit Graph

88 Commits

Author SHA1 Message Date
Debian
5ace250879 feat(cluster): FQDN-First Token-Flow — Node vor dem Join vorregistrieren
Cluster-Seite: Schritt 2 fragt jetzt den FQDN des neuen Knotens bevor
der Token generiert wird. Der Knoten wird sofort in ha_nodes (status=pending)
eingetragen. Nach Token-Generierung wird direkt die Setup-Wizard-URL des
neuen Knotens angezeigt (https://<fqdn>:3443/setup).

Backend: POST /cluster/join-tokens nimmt jetzt node_fqdn entgegen,
pre-registriert via preRegisterByFQDN(). Die IP wird beim issue-cert
nachgetragen (preRegisterJoiner).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:29:58 +02:00
Debian
afe2c951b9 feat(setup): Cluster-Join komplett in GUI — kein CLI mehr nötig
POST /setup/join-cluster macht alles was bisher edgeguard-ctl cluster-join
tat: CSR generieren, Certs vom Primary holen, schreiben, auto-registrieren,
Setup als Cluster-Node markieren.

Setup-Wizard Node-Modus fragt jetzt direkt Primary-FQDN + Join-Token ab.
Nach Submit: Erfolgsmeldung + einziger verbleibender Schritt (systemctl restart).

Neue interne Bibliothek: internal/services/clusterjoin — wird von Handler
und CLI (edgeguard-ctl cluster-join) gleichermaßen genutzt, keine Duplizierung.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:08:49 +02:00
Debian
7e5a7a83c0 feat(setup): Cluster-Node-Modus im Setup-Wizard + Install-Script-Port-Fix
Setup-Wizard zeigt jetzt beim ersten Aufruf eine Modusauswahl:
- "Neuinstallation" → bisheriger Flow (Admin-Account + FQDN + ACME)
- "Cluster-Knoten beitreten" → nur FQDN + ACME, kein Admin-Account;
  nach dem Submit werden die cluster-join-Befehle direkt angezeigt

Backend: NodeRequest + Store.CompleteAsNode() + POST /setup/complete-node
State: is_cluster_node Flag; login via PG-Replikation vom Primary

Install-Script: Setup-URL zeigt jetzt korrekt :3443/setup statt /setup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 16:07:19 +02:00
Debian
33f6fef009 feat(cluster): Seite komplett neu — Blank-Page-Fix + Node-Join-Wizard
Seite war komplett leer wenn die Cluster-API einen Fehler zurückgab
(if(!data) return null). Jetzt: sichtbarer Error-Banner mit Retry,
keine leere Seite mehr.

Neuer 4-Schritt-Wizard "Zweiten Node hinzufügen" immer sichtbar:
  1. Installer-Oneliner (copyable)
  2. Join-Token generieren (Button → POST /cluster/join-tokens)
  3. cluster-join-Befehl inkl. Token inline auf der Seite (kein Modal)
  4. systemctl restart edgeguard-api

Token + CA-Fingerprint + Befehl erscheinen direkt in Schritt 3
nach Token-Generierung — kein separates Modal mehr nötig.
common.retry i18n-Key ergänzt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 15:17:12 +02:00
Debian
31d3485a2f feat(dns): Validierung für DNS-Settings — upstream IPs, ACL-CIDRs, TTL-Kreuzcheck
Backend: validateSettings() prüft vor dem Reload-Trigger ob upstream_forwards
gültige IPs (inkl. @port), access_acl gültige IPs/CIDRs und listen_addresses
gültige IPs sind; cache_max_ttl ≥ cache_min_ttl.
Frontend: Pattern-Validatoren auf upstream_forwards + access_acl; TTL-
Kreuzvalidierung mit dependencies.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 12:52:28 +02:00
Debian
7dd76d4b58 fix(backends): Backend-Löschen verweigern wenn Routing-Regeln darauf zeigen (v1.1.142)
- Service: Pre-Check auf routing_rules.backend_id → ErrInUse vor DELETE
- Handler: ErrInUse → HTTP 409 Conflict statt 500 (response.Conflict helper)
- UI: Delete-Button deaktiviert + Tooltip "Von N Regeln verwendet" wenn Referenzen existieren

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 07:15:16 +02:00
Debian
40414d472b fix(routing+backends): Pfad-Präfix-Validierung + Warnung bei leerem Backend-Pool (v1.1.141)
- RoutingRules: path_prefix Pattern-Validator (muss mit / beginnen) + destroyOnHidden
- Backends: Alert-Banner wenn aktives Backend 0 Server hat (→ HAProxy 503)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 21:25:55 +02:00
Debian
9dee904169 fix(backends): Adress-Validierung für Backend-Server + Quick-Backend (v1.1.140)
Pattern-Validator lehnt offensichtlich ungültige Adressen (Sonderzeichen,
Leerzeichen) schon im Frontend ab, bevor sie HAProxy-Config-Generierung
zerstören können. Gilt für Backend-Server-Modal und Domain-Quick-Backend.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 21:13:24 +02:00
Debian
d89569017d feat(firewall): Regel duplizieren + CIDR-Validierung (v1.1.139)
- Duplicate-Button (CopyOutlined): klont Regel mit priority+1, disabled=true, Name "(copy)"
- CIDR-Felder: Pattern-Validator für IPv4/IPv6-CIDR-Notation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 20:36:25 +02:00
Debian
dc2c1b7471 fix(settings): Bestätigungsdialog vor Service-Restart + status-dot CSS (v1.1.138)
- Popconfirm vor jedem Restart-Button — kein versehentlicher Neustart mehr
- status-dot inline styles → .status-dot.online/.offline CSS-Klassen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:14:44 +02:00
Debian
2a9310e947 fix(firewall): NAT-Regeln nach Priorität sortieren + Port-Range-Validierung (v1.1.137)
- dataSource: data→sortedNAT — Up/Down-Pfeile zeigten auf falschen Nachbarn
- Form.Item dependencies: dportEnd/targetPortEnd validiert ≥ Start-Port
- Modal destroyOnHidden: Formular-State nach Schließen zurückgesetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 16:51:07 +02:00
Debian
76b5a4586c feat(firewall): Enterprise-UI-Redesign — KPI-Strip, Zone-Badges, Filter-Bar (v1.1.136)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 16:39:57 +02:00
Debian
2a76a6599b fix(license): Rejection-Reason anzeigen + Placeholder NETC- korrigieren
Wenn der License-Server valid:false zurückgibt, wird payload.reason
jetzt als roter Alert angezeigt — bisher war der Grund nicht sichtbar
und der Operator sah nur "Abgelaufen" ohne Erklärung.

Formular-Placeholder NMG-XXXX → NETC-XXXX (mail-gateway copy-paste).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 15:06:48 +02:00
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
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
4406f9ac5b feat(scheduler): WireGuard-Client-Tunnel-Down-Alert + dedupe-Korrekturen — v1.1.110
- runWGClientTunnelCheck() prüft alle aktiven Client-Tunnels (mode='client')
  alle 5 Min; feuert Error-Alert wenn kein Handshake seit >5 Min oder
  noch nie (12h dedupe pro Tunnel-Name)
- Dedupe-Angaben in alerts.scopeDesc korrigiert: war "1h" für mem/conntrack/ntp,
  tatsächlich 12h (shared alertDedupe) — beide Sprachen bereinigt
- wg.tunnel.down-Trigger in beiden i18n-Dateien dokumentiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 19:16:03 +02:00
Debian
feae18772c feat(scheduler): NTP-Sync-Alert — warnt wenn chrony keine Zeitquelle hat — v1.1.109
- runNTPSyncCheck() läuft alle 10 Minuten: ruft chronyc tracking auf,
  prüft ob Stratum 0 / ≥16 oder Reference ID 00000000 — feuert
  Warning mit Fix-Hints (1h dedupe)
- Initial-Check absichtlich NICHT beim Boot, da chrony nach dem Start
  einige Sekunden zur ersten Synchronisation braucht
- ntp.unsync-Trigger in beiden i18n-Dateien dokumentiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 17:40:16 +02:00
Debian
b9dfab6664 feat(scheduler): Conntrack-Alert — silent-drop Warnung bevor Tabelle voll läuft — v1.1.108
- runConntrackCheck() liest /proc/sys/net/netfilter/nf_conntrack_count +
  nf_conntrack_max, feuert Warning bei ≥80% und Critical bei ≥90%
  (2-Min-Takt, 1h dedupe pro Severity-Key)
- Bei 100% Auslastung dropped nftables alle neuen Verbindungen lautlos;
  der Alert kommt damit rechtzeitig bevor das passiert
- conntrack.high-Trigger in beiden i18n-Dateien dokumentiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 06:21:16 +02:00
Debian
ac6c580318 feat(scheduler+ntp): Memory-Alerts + NTP-Status freq/rms — v1.1.107
- Scheduler: runMemoryCheck() liest /proc/meminfo, feuert Warning bei ≥85% und Critical bei ≥95% RAM-Auslastung (5-Min-Intervall, 1h dedupe pro Severity-Key)
- NTP-Status-Karte: freq_ppm (±ppm mit Warnung bei >100) und rms_offset_ms werden jetzt angezeigt — Felder waren im Backend schon vorhanden, aber nie gerendert
- Alerts scopeDesc: mem.high-Trigger in beiden i18n-Dateien dokumentiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 05:54:57 +02:00
Debian
99b4225e64 feat(alerts): backend.down trigger — HAProxy socket check every 2 min, 12h dedupe
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 17:30:49 +02:00
Debian
711c4c7eb1 feat(fwd-proxy): Squid cache stats card — GET /forward-proxy/stats + squidclient mgr:counters
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 16:47:31 +02:00
Debian
f6615fd27d feat(dns): Resolver stats tab + NAT rule move buttons
- GET /dns/stats via unbound-control stats_noreset: total queries,
  cache hits/miss, hit-rate progress bar, recursive replies, prefetch,
  rate-limited, unwanted, RRset/msg cache memory
- DNS page: new "Resolver stats" tab with 30s auto-refresh
- NAT rules: ↑↓ move buttons (same pattern as firewall rules 1.1.102)

v1.1.103

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 13:20:07 +02:00
Debian
844f9ddc83 feat(firewall): Move-up/down buttons for rule priority reordering
Adds ↑↓ icon buttons in the firewall rules table. Clicking swaps
the rule's priority value with its sorted neighbor via two sequential
PUTs. First rule's ↑ and last rule's ↓ are disabled. Viewer role
cannot reorder.

v1.1.102

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 12:07:10 +02:00
Debian
4629679ba9 feat(ntp): Live peer status tab (chronyc sources)
Adds GET /ntp/sources endpoint (runs chronyc sources, parses tabular
output) and a new "Peer status" tab in the NTP page showing all
configured peers with mode, state badge, stratum, poll interval,
reach register, last-rx and offset/error sample.

v1.1.101

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 11:57:04 +02:00
Debian
57b9cd89b2 feat(settings): Copy + Download buttons for config preview
v1.1.100

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:48:45 +02:00
Debian
c99b0cef4c feat(system): health-Endpoint liefert jetzt hostname + OS + kernel
- /system/health gibt zusätzlich hostname, os (PRETTY_NAME aus
  /etc/os-release) und kernel (/proc/version, ohne Build-Details) zurück
- Settings-Seite: SystemHealth-Interface erweitert, System-Info-Card
  zeigt Hostname, Betriebssystem und Kernel-Version an (conditional,
  nur wenn vorhanden)
- Nützlich beim Verwalten mehrerer Boxen — ohne SSH sofort sehen
  welches System gerade geöffnet ist

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:43:56 +02:00
Debian
73619c17f8 fix(system): render-configs rendert jetzt ALLE Dienste, nicht nur HAProxy
- SystemHandler.ExtraReloaders: neues Feld für nftables, wireguard,
  squid, unbound, chrony Reloader
- WithAllReloaders(): Wire-Methode; main.go bindet alle Reloader nach
  Initialisierung ein
- RenderConfigs: läuft alle Reloader durch, sammelt Fehler, antwortet
  mit {ok, rendered[], errors{}} — partiell OK wird als warning gemeldet
- UI: Settings-Button-Label "Re-render all configs"; partial-error
  Toast zeigt welche Dienste fehlschlugen
- Timeout: 30s statt 10s (alle Dienste brauchen mehr Zeit)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 22:29:00 +02:00
Debian
8d7a43bc8c feat(wireguard): selektiver .conf-Import — Auswahl einzelner Interfaces per Modal
- GET /wireguard/importable listet alle .conf-Dateien in /etc/wireguard/
  mit already_in-Flag (bereits in DB)
- POST /wireguard/import nimmt optionale Names-Liste; ohne Namen → alles
- edgeguard-ctl wg-import [iface…] importiert nur die genannten Interfaces
- UI: Checkbox-Modal mit "Alle neuen auswählen" + Einzelauswahl;
  bereits importierte Interfaces disabled + grüner Tag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 22:09:37 +02:00
Debian
ac068bc9dd feat(dns+ntp): DNS-Cache-Flush + NTP-Force-Sync — operative Aktionen (1.1.94)
Backend: POST /dns/flush-cache (unbound-control flush_zone .)
         POST /ntp/force-sync  (chronyc makestep)
Beide werden im Audit-Log festgehalten.
UI: Schaltflächen in DNS-Settings und NTP-Settings neben Save,
    mit Tooltip-Beschreibung + i18n (de+en).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:52:20 +02:00
Debian
2d027b3044 fix(rbac): Viewer-Rolle in Detail-Pages + ActionButtons — Edit ebenfalls sperren
- ActionButtons: Edit-Button wird für Viewer wie Delete gesperrt (Tooltip zeigt Reason)
- Domains/Detail: isViewer-Flag an alle Sub-Panels weitergegeben; Save-, TLS-Cert-,
  Routing-Rules- und Headers-Buttons für Viewer disabled
- Backends/Detail: Save-Button + ServerPanel Add-Button für Viewer disabled
- i18n: domains.backendUp/backendDown Keys (waren noch hardkodiert)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:10:29 +02:00
Debian
1aaca2c056 fix(i18n): WireGuard QR/.conf Buttons + Backend 'Upgrade gestartet' → Englisch
- Servers.tsx: 'QR' und '.conf' Button-Labels in t() überführt (wg.peer.qr/conf)
- system.go: hardkodierter deutscher API-Response-String 'Upgrade gestartet'
  → 'upgrade started' (API-Responses sollen immer Englisch sein)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:55:36 +02:00
Debian
49e3e39ea6 fix(i18n): RemoteTargets S3/SFTP-Labels + NTP-Interface-Labels vollständig lokalisieren
RemoteTargets: alle 20+ hardkodierten Form-Labels und deutschen Hilfetexte
(S3: Endpoint/Region/Bucket/AccessKey/SecretKey/PathPrefix/HTTPS;
 SFTP: Host/Port/Username/Password/PrivateKey/RemoteDir/HostKeyFp)
sind jetzt in t()-Aufrufen mit remotes.s3.*/remotes.sftp.*-Keys.

NTP: Listen-Address-Dropdown-Labels (alle IPv4/IPv6-Interfaces, Loopback)
verwenden jetzt dns.settings.allIPv4/allIPv6/loopback (identisch zu DNS-Settings).
NTP-Pool-Adresse-Placeholder → t('ntp.pool.addressPlaceholder').

en/de: alle neuen Keys ergänzt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:52:13 +02:00
Debian
f6852256b1 fix(i18n): fehlendes Komma in de/common.json nach users.you
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:48:03 +02:00
Debian
bb14d2ac6c fix(i18n): hardkodierte Strings in Cluster/Users/Backups/Alerts bereinigen
- Cluster: statusTag() bekommt t-Parameter; Status-Labels (online/offline/
  joining/leaving/unknown) → cluster.status.* Keys
- Users: 'You'-Tag → t('users.you') / de: 'Ich'
- Backups: 'OK'-Status-Tag → t('backups.okTag')
- Alerts: Kanal-Kind-Labels + alle SMTP-Formular-Labels in t() überführt
- en/de: cluster.status.*, users.you, backups.okTag, alerts.smtp.*,
  alerts.kindWebhook/kindEmail ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:47:28 +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
ca1ee64829 fix(firewall): fehlende onError-Handler + i18n in Rules + NATRules
- 6 Mutations (create/update/del je Rules + NATRules) bekommen onError-Handler
- Deutsche Placeholder-Texte → t() überführt
- Action-Labels (accept/drop/reject) und Kind-Labels (any/object/group/cidr)
  in t() überführt statt hardkodiert anzeigen
- CIDR-Label-Hardkodierung in Rules-Formular behoben
- en/de: fw.rule.actions.*, fw.rule.kinds.*, fw.rule.namePlaceholder,
  fw.nat.namePlaceholder ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:40:08 +02:00
Debian
519522b8ee fix(i18n): hardkodierte Strings in DNS/RoutingRules/Settings/Backends bereinigen
- DNS Settings: Loopback/allIPv4/allIPv6 Interface-Labels in t() überführt
- RoutingRules: UP/DOWN-Tags + fehlende onError-Handler in create/update
- Settings: t-Variable-Shadowing in top_tables-Map behoben (t → tbl)
- Backends: 'Live'-Spaltenheader → t('backends.server.live')
- common.up/down + dns.settings.allIPv4/allIPv6/loopback in en+de ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:30:43 +02:00
Debian
e37e472960 fix(i18n): License-Status-Tags + letzte hardkodierte Strings entfernt
- statusTag() akzeptiert jetzt t als Parameter — Aktiv/Trial/
  Abgelaufen/Ungültig gehen durch license.tag* Keys
- en+de common.json: license.tagActive/tagTrial/tagExpired/tagInvalid

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:20:03 +02:00
Debian
f33c1bfe4f fix(i18n): ForwardProxy ACL-Labels + Diagnostics-Output vollständig übersetzt
- ForwardProxy: ACL_TYPE_KEYS-Array + t('fwd.aclTypes.*') statt
  hartkodierter gemischter DE/EN-Labels; action-Select und
  value-Placeholder ebenso via t()
- Diagnostics: '(kein Output)' → t('diag.noOutput') — war einzige
  sichtbare deutsche Konstante außerhalb t()
- en/de common.json: fwd.aclTypes.*, fwd.actions.*, fwd.valuePlaceholder,
  diag.noOutput hinzugefügt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:16:08 +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
386972366b feat(rbac): Viewer-Rolle durchsetzen — alle Mutations nur für Admins
- middleware.go: RequireAdminForMutations() blockiert POST/PUT/DELETE
  für Nicht-Admins (GET/HEAD passieren immer durch)
- main.go: Middleware in den authed-Gruppe eingehängt — wirkt für
  alle ~30 Resource-Handler gleichzeitig
- api/client.ts: 403 → AntD-Notification "Nur Lesezugriff" statt
  stiller Fehler
- Header: "Nur lesen"-Badge + Tooltip wenn role=viewer
- i18n de+en: viewerBadge + viewerHint

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 16:57:17 +02:00
Debian
4e01b4569c feat(ipv6): IPv6-Support für HAProxy + Settings-Toggle
- setup.State.IPv6Enabled + Store.SetIPv6Enabled()
- GET/POST /system/ipv6 im SystemHandler; HAProxy-Reload on save
- HAProxy-Template: bind [::]:80, [::]:443, quic6@:443, [::]:3443
  werden nur emittiert wenn IPv6Enabled=true
- haproxy.View.IPv6Enabled aus SetupStore befüllt
- Settings-UI: neues IPv6-Card (zwischen Auto-Update und Passwort)
- i18n de+en ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 16:48:26 +02:00
Debian
a490576420 feat(users): Multi-User-Management — DB-backed Login-Accounts + UI
- internal/services/users: Repo mit CRUD, bcrypt (cost 12), Upsert für
  setup-store-Admin-Migration, RecordLogin
- internal/handlers/users: GET/POST/PUT /users, POST /users/:id/password,
  DELETE /users/:id; Schutz gegen Selbst-Löschung
- auth.go Login: DB-Nutzer first, Fallback auf setup-store-Admin;
  bei erfolgreichem Fallback wird der Admin per Upsert in die DB
  migriert (kein manueller Eingriff nötig)
- management-ui: /users-Seite mit Tabelle, Anlegen-, Bearbeiten-,
  Passwort-setzen- und Löschen-Modals; "You"-Badge für eigenen Account
- Sidebar + Route + i18n (de/en) ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 10:22:27 +02:00
Debian
8293783fe6 feat(backends+domains): HTTP-Protokoll-Flags — force_http1 + disable_h3
Backend: force_http1 (bool, default false) — zwingt HAProxy auf der
Backend-Verbindung zu HTTP/1.1 statt h2,http/1.1 zu verhandeln.
Nötig für Legacy-Apps die kein h2 sprechen.

Domain: disable_h3 (bool, default false) — unterdrückt Alt-Svc-
Response-Header für diese Domain. Browser erhalten keinen h3/QUIC-
Hinweis und bleiben auf h2/http1.1.

Migration 0027, Model+Service+HAProxy-Template+UI+i18n.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 07:18:48 +02:00
Debian
bc5d81d966 feat(wg): Push-Routes (Client-Routes) für WireGuard-Server-Interfaces
Neues Feld 'client_routes' auf wireguard_interfaces: der Operator
trägt dort kommagetrennte Netzwerke ein (z. B. 10.0.10.0/24 für ein
LAN hinter der Box). Der Peer-Config-Download fügt diese automatisch
als zusätzliche AllowedIPs in den [Peer]-Block der Client-Config ein.

Bisher wurde nur das Server-Tunnel-Subnetz (ifc.address_cidr) als
AllowedIPs exportiert — Peers konnten so keine anderen Netze über
den Tunnel erreichen ohne die Config manuell anzupassen.

Migration: 0026_wg_client_routes.sql

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 13:09:51 +02:00
Debian
1f0d05019e fix(wg+fw): Startup-nftables-Render + /32-Hinweis bei Peer-AllowedIPs
Zwei unabhängige Fixes für das WireGuard peer-to-peer Problem:

1. Startup-nftables-Render: edgeguard-api rendert beim Start die
   nftables-Konfiguration neu. Damit werden Template-Änderungen aus
   einem Update (z.B. 1.1.51 WG-forward-Rule) sofort aktiv, ohne
   dass der Operator manuell eine Firewall-Mutation triggern müsste.

2. UI-Hint: Peer-AllowedIPs-Feld erklärt explizit warum /32 nötig
   ist und was /24 kaputtmacht (Server routet ganzen Subnet-Block zu
   einem Peer → andere Peers nicht mehr erreichbar).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 12:34:12 +02:00
Debian
711e9446e6 feat(domains): Domain-Detailseite + Response-Headers-Panel
Statt aller 15+ Felder in einem Modal gibt es jetzt eine eigene Seite
unter /domains/:id. Der Create-Flow bleibt im Modal (Name, Backend, Active,
HTTP→HTTPS), ein Hinweistext führt nach dem Speichern auf die Detailseite
weiter.

Die Detailseite enthält links das vollständige Settings-Formular (HSTS,
Rate-Limit, Maintenance, Max-Body, Notes, WWW-Redirect) und rechts das
HeadersPanel zum Verwalten custom HTTP-Response-Header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:04:41 +02:00
Debian
f4d178cb38 feat(firewall): nftables hit-counter pro Regel + Live-Hits-Spalte in der UI
- ruleset.nft.tpl: operator-rules bekommen `counter <action> comment "egid:<id>"`
  → nft zählt Packets + Bytes per Regel ab dem letzten Ruleset-Apply
- handlers/firewall_counters.go: GET /firewall/counters parst
  `sudo nft list table inet edgeguard` per Regex, liefert [{rule_id,packets,bytes}]
- handlers/firewall_counters_test.go: unit-tests für parseNFTCounters
- Firewall/Rules.tsx: neue "Hits"-Spalte (Packet-Count, Tooltip mit Bytes),
  10s-Polling via TanStack Query ['fw','counters']
- i18n de+en: fw.rule.hits

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 08:42:31 +02:00