Files
edgeguard-native/CLAUDE.md
Debian 7611572062 refactor(cluster): promote auf Logical-Replication umgestellt + internal/proxy-Stub entfernt — v1.2.99
Code-Altlasten aus dem Architektur-Audit bereinigt:
- internal/proxy: leerer .gitkeep-Stub (geplanter Write-Proxy nie implementiert) entfernt — keine Go-Referenzen.
- promote.go: war reines Physical-Replication-Failover (standby.signal + pg_ctlcluster promote + pg_is_in_recovery) und damit auf dem Logical-Setup TOT (ein Subscriber hat kein standby.signal / ist nie in recovery → Abbruch bei Schritt 1). Neu Logical-aware: Idempotenz-Check (schon Publisher ohne Subscription → fertig) → Subscription lösen (DISABLE+slot_name=NONE+DROP, hängt nicht am toten Publisher) → setupReplicationPrimary (Publisher werden) → ha_nodes.pg_role=primary → keepalived MASTER. Toter KeyDB-Update (cluster:pg-primary-url, wurde nie gelesen) entfernt.
- setupReplicationPrimary + dropSubscriptionIfExists aus cluster-init-replication/cluster-setup-standby extrahiert (DRY, bewährte SQL wiederverwendet). WICHTIG: setupReplicationPrimary stellt jetzt sicher dass wal_level=logical AKTIV ist — PG-RESTART falls nötig (reload reicht für wal_level/max_wal_senders nicht; Secondary hat wal_level=replica). Idempotent: Restart nur wenn wal_level != logical.
- Doku (CLAUDE.md + architecture.md) auf den bereinigten Stand gezogen.
Hinweis: echtes Cross-Node-Failover ist nur im Drill testbar; Build/vet/Tests grün, Bausteine sind die bereits produktiv genutzten SQL-Primitive.

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

11 KiB

⚠️ GOLDENE REGEL — NIEMALS RATEN. IMMER LESEN.

Nicht verhandelbar. Keine Ausnahmen.

Vor jeder Entscheidung über Feldwerte, API-Shapes, Dateinamen, Funktions-Signaturen, Konfigurationsparameter oder Architektur-Details: erst Original lesen, dann arbeiten.

  • Referenz-Backend (Go-Patterns, Migrations, Cluster, Packaging) → ac_search_code(project_id=6) oder direkt /var/www/mail-gateway
  • Referenz-UI/Bootstrap (React/AntD, i18n, Design-System, Install-Onliner) → ac_search_code(project_id=5) oder direkt /var/www/netcell-webpanel
  • Alter Docker-Stack (nur für Feature-Scope-Referenz!) → ac_search_code(project_id=3) oder /var/www/proxy-lb-waf
  • Im Zweifel → Rückfrage statt Annahme.

EdgeGuard Native (eg)

Native Neufassung des Docker-basierten EdgeGuard-Stacks. Kein Docker — alle Dienste nativ unter systemd. Zielplattform: Debian 13 (Trixie), amd64 + arm64. Auslieferung als signiertes .deb.

Hinweis: Mehrere ursprüngliche v1-Nicht-Ziele (WAF, IDS/IPS, DHCP, RADIUS) sind inzwischen umgesetzt — siehe „Feature-Stand" weiter unten.


Repository & Server

  • Gitea: https://git.netcell-it.de/projekte/edgeguard-native
  • SSH-Clone: ssh://git@git.netcell-it.de:1922/projekte/edgeguard-native.git
  • Lokal (Dev): /var/www/edgeguard-native · ssh linux@89.163.205.87
  • Architect Center: Projekt ID 8
  • Git-Server: git.netcell-it.de · SSH Port 1922 · git push origin main

MCP-Tools (Architect Center)

project_id: 8 · Session: $ARCHITECT_SESSION · MCP-Server: architect

Beim Session-Start (PFLICHT)

ac_recall(query="<aktuelle Aufgabe>", project_id=8, session_name="$(printenv ARCHITECT_SESSION)")
ac_search_code(query="<Stichworte>", project_id=8, session_name="$(printenv ARCHITECT_SESSION)", limit=6)

Alle Tools

Tool Wann verwenden
ac_recall(query, project_id=8, session_name) Session-Start — relevante Memories laden
ac_search_code(query, project_id=8, session_name, limit?) Vor JEDEM neuen Code schreiben
ac_search_code_global(query, session_name, limit?) Suche über alle Projekte hinweg
ac_remember(text, category, project_id=8, session_name) Jede neue Erkenntnis / Entscheidung
ac_create_bug(title, description?, priority?, session_name?) Bug gefunden
ac_create_feature(title, description?, priority?, session_name?) Feature-Idee
ac_create_task(title, description?, priority?, status?, project_id?) Follow-up Arbeit
ac_update_task(id, status?, priority?, title?) Task-Status ändern
ac_add_decision(title, content, category?, project_id?) Architekturentscheidung
ac_notify(message, title?, type?) Status-Update senden
ac_get_project(session_name) project_id für Session ermitteln
ac_research(query, context?) Doku / CVE / Libraries recherchieren
ac_review(code, language?, focus?) Code-Review nach Fertigstellung
ac_analyze(text, question?) Logs / Outputs analysieren

ac_remember Kategorien: decision · pattern · bugfix · convention · architecture · general


Stack

Schicht Technologie
API Go 1.26, Gin, GORM (Queries), goose (Migrations)
UI React 19, TypeScript strict, Vite, Ant Design 6, TanStack Query 5
DB PostgreSQL 16 (Distro-Paket), goose-Migrations in migrations/
State/HA PostgreSQL Logical Replication + Cluster-Agent-Heartbeat (mTLS); KeyDB Active-Active nur optional (Recommends, für Lizenz-Leader-Election/Shared-Cache)
Proxy/LB HAProxy (Distro) — TLS-Termination, L7-Routing, LB
WAF Coraza v3 + OWASP CRS, via HAProxy SPOE (edgeguard-waf-Agent)
IDS/IPS CrowdSec + crowdsec-firewall-bouncer (nftables) — managed-wenn-installiert (kein Depends)
VPN WireGuard (Kernel-Modul ab 5.6, wireguard-tools)
DNS Unbound (Distro) — Forwarder+Cache mit DNSSEC, Cluster-internes Split-Horizon
DHCP Kea (kea-dhcp4-server) — managed, default-off
AAA/RADIUS FreeRADIUS (PAP/CHAP, files-based) — managed, default-off
NTP chrony (Distro)
VIP/HA keepalived (VRRP)
FW nftables (Distro)
Forward-Proxy Squid (Distro)
Auth/SSO JWT (lokal) + 2FA/TOTP + OIDC/OAuth2 (Keycloak u. a.)
TLS certbot + webroot-Plugin
Packaging dpkg-deb (direkt, wie mail-gateway + netcell-webpanel)
Plattform Debian 13 Trixie · amd64 + arm64

Feature-Stand (Stand 2026-06)

Über den ursprünglichen v1-Scope hinaus inzwischen umgesetzt (waren mal Nicht-Ziele):

  • WAF — Coraza v3 + OWASP CRS via HAProxy SPOE (edgeguard-waf)
  • IDS/IPS — CrowdSec + crowdsec-firewall-bouncer (nftables-Bouncer); managed-wenn-installiert, kein hartes Depends
  • DHCP — Kea kea-dhcp4-server (managed, default-off)
  • RADIUS — FreeRADIUS PAP/CHAP, files-based (managed, default-off)
  • SSO — OIDC/OAuth2 (additiv, Rolle aus DB, lokaler Login bleibt)
  • 2FA — TOTP
  • IPv6 — Firewall-Regeln + NAT familienbewusst
  • HA — VIP via keepalived (VRRP), PG-Logical-Replication, bidirektionaler Cluster-Heartbeat

Damit ist die ursprüngliche v2-Roadmap (WAF, 2FA, IPv6-FW, OIDC, DHCP, RADIUS) abgearbeitet.

Nicht-Ziele (weiterhin)

  • Kein Docker — alle Dienste nativ unter systemd
  • Kein Network-IDS Suricata — Intrusion-Detection läuft über CrowdSec, nicht über Suricata-Paket-Inspektion
  • Keine Mail-Verarbeitung (eigenes Produkt: mail-gateway)
  • Keine Multi-Tenant-GuardZones
  • Keine ISO-Builds (kein EdgeGuardOS-Klon — nur APT)
  • Nur Debian 13 — kein Ubuntu, kein Debian 12, kein RHEL

Binaries & Ports

Binary Beschreibung Bindet User
edgeguard-api REST Management-API 127.0.0.1:9443 edgeguard
edgeguard-scheduler Cron-Jobs (ACME-Renew, Backup, Health) edgeguard
edgeguard-ctl CLI: initdb migrate cluster-join promote dump-config root/edgeguard

HAProxy terminiert TLS auf :443, routet per Host-Header an Backends und fällt für Management-FQDN/ACME-Webroot auf 127.0.0.1:9443 (edgeguard-api) zurück. Die Management-UI wird von edgeguard-api ausgeliefert (statisch aus /usr/share/edgeguard/ui/ oder embedded).


Build

make build            # Host-Architektur (amd64)
make test             # go test ./...
make lint             # golangci-lint
make deb              # amd64 + arm64 .deb
make publish          # deb + Upload Gitea Package Registry
make install-local    # direkt auf Dev-Server installieren (kein .deb)

# UI
cd management-ui && bun install && bun run build

Dev-Server Quickstart

# Abhängigkeiten installieren
sudo apt-get install -y postgresql-16 haproxy wireguard-tools squid unbound nftables certbot

# API starten (ohne systemd, für Entwicklung)
go run ./cmd/edgeguard-api/

# UI Dev-Server
cd management-ui && bun run dev

Projektstruktur

/var/www/edgeguard-native/
├── cmd/
│   ├── edgeguard-api/         # Management-API (Gin, 127.0.0.1:9443)
│   ├── edgeguard-scheduler/   # Cron-Jobs
│   └── edgeguard-ctl/         # CLI
├── internal/
│   ├── database/              # pgxpool + goose-Runner; migrations/ via go:embed
│   │   └── migrations/        # SQL (goose-Format) — embedded ins Binary
│   ├── models/                # GORM-Models
│   ├── handlers/              # HTTP-Handler (REST)
│   ├── services/              # Business-Logik
│   ├── haproxy/               # Config-Generator (TLS + Routing + LB)
│   ├── squid/                 # Config-Generator
│   ├── wireguard/             # Config-Generator
│   ├── unbound/               # Config-Generator (Forwarder + Cluster-DNS)
│   ├── firewall/              # nftables-Generator
│   ├── cluster/               # Join/Promote/Peer-Discovery
│   ├── aggregator/            # Cluster-View APIs
│   └── license/               # Lizenz-Validierung
├── management-ui/             # React 19 + AntD 6 (1:1 enconf-Pattern)
├── packaging/debian/          # control, postinst, postrm, systemd-Units
├── deploy/
│   ├── systemd/               # *.service, *.target, *.timer
│   ├── haproxy/               # (Templates liegen jetzt neben Renderer in internal/<svc>/)
│   ├── squid/                 # squid.conf.tpl
│   ├── unbound/               # unbound.conf.tpl
│   └── nftables/              # ruleset.nft.tpl
├── scripts/
│   ├── apt-repo/              # build-package.sh, publish.sh
│   └── install.sh             # Bootstrap curl-Onliner
├── docs/
│   └── architecture.md        # Vollständige Architektur-Spec
├── go.mod
├── Makefile
├── CLAUDE.md                  # Diese Datei
└── agent.md                   # Agent-Factory Pipeline

Key Conventions

Go-Code

  • Migrations: goose SQL-Dateien in internal/database/migrations/, via //go:embed ins Binary — NICHT GORM AutoMigrate
  • ORM: GORM für Queries, nicht für Schema-Verwaltung
  • Config-Generierung: Template-Datei in deploy/*/, Generator in internal/*/
  • Config-Reload: systemctl reload <service> nach Config-Schreiben
  • Cluster-Primary-Ermittlung: zuverlässig über pg_publication (edgeguard_shared); Primary-URL aus setup.json PrimaryFQDN via clusterjoin.NormalizePrimaryURL. Kein Write-Proxy — Schreibzugriffe auf geteilte Tabellen erfolgen am Primary.
  • Failover: edgeguard-ctl promote ist Logical-Replication-aware (Subscription lösen → setupReplicationPrimary → Publisher werden, inkl. PG-Restart für wal_level=logical); erholte Nodes danach via cluster-setup-standby <neuer-primary> zurückhängen.

Packaging

  • dpkg-deb direkt (wie mail-gateway) — kein dh_make/debhelper/fpm
  • postinst: User anlegen → Dirs → initdb (idempotent) → migrate → systemctl
  • postrm purge: nur bei purge DB + User entfernen

UI

  • 100% enconf-Pattern (netcell-webpanel/management-ui/) — keine eigenen Design-Entscheidungen
  • import type für alle Type-Imports (verbatimModuleSyntax!)
  • AntD 6, kein Tailwind, kein Material UI

Auth

  • JWT-basiert (analog enconf), Secret in /var/lib/edgeguard/.jwt_fingerprint
  • Admin-Check: immer aus DB-User-Row, nie aus JWT-Payload

Vollständige Architektur

docs/architecture.md


Vor jeder Änderung

  1. Referenz-Pattern in mail-gateway oder netcell-webpanel lesen
  2. ac_search_code vor neuem Code — Pattern existiert meist schon
  3. make test nach Backend-Änderungen
  4. cd management-ui && npx tsc --noEmit nach Frontend-Änderungen