| .claude | ||
| backend | ||
| data/state | ||
| frontend | ||
| .gitignore | ||
| CLAUDE.md | ||
| README.md | ||
Router Discovery und Version-Detection und Management
NodeJS/VueJS-System zur Discovery, Inventarisierung und Verwaltung von Juniper MX204-,
Ubiquiti-Edge- (BIRD2) und Mikrotik-Routern per SSH. Siehe .claude/promts/ für die
vollständige Spezifikation und den fortlaufenden Entscheidungsverlauf jeder Ausbaustufe.
Struktur
backend/ Express-API (TypeScript), Prisma/MariaDB, SSH-Vendor-Adapter, Discovery-Engine
→ backend/README.md: vollständige API-Referenz, Umgebungsvariablen, Credential-Profile
frontend/ Vue 3 + Vite WebUI (TypeScript, PrimeVue)
data/state/ Pretty-printed JSON State-Snapshots pro Router (Hash-Dedup, wird von der API befüllt)
Funktionsumfang
Discovery & Inventar
- Host manuell hinzufügen oder automatisch per Deep-Dive entdecken: rekursive
Nachbarschaftserkennung über BGP-/OSPF-Neighbors sowie bei Mikrotik zusätzlich über
MNDP/CDP/LLDP (
/ip neighbor print), mit konfigurierbarer Max-Tiefe. - Discovery-Queue mit Status-Tracking (wartet auf Scan, Scan aktiv, fehlende Zugangsdaten, SSH nicht erreichbar, außerhalb des eigenen IP-Bereichs, ignoriert, fertig) — nur Einträge, die noch Aufmerksamkeit brauchen, bleiben sichtbar.
- Einheitliche Vendor-Abstraktion für Juniper (JunOS
| display json), Ubiquiti Edge (BIRD2 überbirdcl) und Mikrotik (RouterOS 6 & 7) — Identify, Interfaces, IP-Adressen, BGP-/OSPF-Nachbarn laufen über ein gemeinsames Interface. - Dashboard zeigt nur Router, mit denen bereits erfolgreich Kontakt bestand (aktuelles Inventar); alles, was noch onboarded wird, bleibt in der Discovery-Queue.
Zugangsdaten & Sicherheit
- Zugangsdaten liegen ausschließlich in Vaultwarden/Bitwarden — die Datenbank speichert nur eine Referenz-ID, nie ein Passwort. Details: backend/README.md → Credential-Profile anlegen.
OWN_IP_RANGESverhindert, dass beim Deep-Dive automatisch Zugangsdaten an Upstream-/Peering-Partner-IPs oder untergeschobene Geräte gesendet werden (siehe unten).- Optionaler SSH-Jump-Host als automatischer Fallback, wenn ein Router direkt nicht
erreichbar ist (
SSH_UNREACHABLE) — inkl. sauberer Unterscheidung zwischen "Verbindung nicht möglich" und "Zugangsdaten falsch/fehlen".
Zustands- & Änderungsverfolgung
- State-Diff-Viewer: pretty-printed JSON-Snapshot pro Sync, nur bei tatsächlicher inhaltlicher Änderung neu geschrieben, mit farbiger Diff-Ansicht im WebUI.
- BGP-/OSPF-Flap-Historie: jede Zustandsänderung (nicht nur der aktuelle Stand) wird protokolliert und als Zeitleiste dargestellt.
- Topologie-Grafik: der betrachtete Router in der Mitte, seine Nachbarn nach West/Ost mit Hyperlink, pro Verbindung inkl. lokalem Interface, lokaler/entfernter IP und (bei BGP) beiden AS-Nummern.
- Interface-Geschwindigkeit wird bei jedem Sync als Zeitreihe erfasst (Datenerfassung fertig, Darstellung im WebUI noch offen — siehe Backlog).
Betrieb
- Täglicher Auto-Sync aller bekannten Router in einem konfigurierbaren Nacht-Zeitfenster, pro Router zu einem zufälligen Zeitpunkt darin, um die Last zu verteilen.
- Job-Aktivitätsanzeige mit Inline-Übersicht aller laufenden/wartenden Sync- und Deep-Dive-Jobs.
- Alle Sync-/Deep-Dive-Aktionen laufen asynchron über eine einzelne sequentielle Queue (nie mehrere SSH-Sessions gleichzeitig gegen dieselbe Flotte) und melden ihren Fortschritt an das Frontend.
Noch offen (siehe .claude/promts/002-phase1-planning.md für die ursprüngliche
Backlog-Liste): Gruppen-Befehlsausführung, zeitgesteuerte Firmware-Update-Queue,
IP-Service-Toggling (Mikrotik), Massen-Rotation von Passwörtern/SSH-Keys, WebUI für die
bereits erfasste Interface-Geschwindigkeits-Zeitreihe.
Voraussetzungen (Bare Metal)
- Node.js 20 LTS
- MariaDB 10.11+ (eigene Datenbank + Benutzer anlegen)
- Bitwarden CLI (
bw) installiert und imPATH, gegen eine Vaultwarden/Bitwarden-Instanz mit Organization-API-Key
Setup
# Backend
cd backend
cp .env.example .env # DATABASE_URL, BW_*, STATE_DIR anpassen
npm install
npm run prisma:migrate # legt Schema in MariaDB an
npm run dev # startet die API auf PORT (Standard 3000)
# Frontend (separates Terminal)
cd frontend
cp .env.example .env # HOST/PORT/API_PROXY_TARGET bei Bedarf anpassen
npm install
npm run dev # Vite Dev-Server, proxyt /api auf localhost:3000
HOST/PORT sind in beiden .env-Dateien konfigurierbar (Backend:
backend/README.md#umgebungsvariablen,
Frontend: frontend/.env.example) - leer/unbelegt
entspricht jeweils dem bisherigen Standardverhalten (Backend auf allen Interfaces,
Frontend-Dev-Server nur auf localhost).
Für den Produktivbetrieb: npm run build in beiden Verzeichnissen, dann als Dienst
betreiben — fertige systemd-Units und OpenRC-Init-Skripte liegen bei
(backend/systemd bzw. backend/openrc,
frontend/systemd bzw. frontend/openrc),
Installationsanleitung jeweils im zugehörigen README
(backend/README.md#produktivbetrieb-systemd--openrc,
frontend/README.md#produktivbetrieb-systemd--openrc).
Alternativ für das Frontend: dist/ per vorhandenem Webserver (nginx o. Ä.)
ausliefern und /api auf den Backend-Prozess reverse-proxyen, statt den
mitgelieferten Vite-Preview-Dienst zu nutzen.
Vollständige Liste aller Umgebungsvariablen und Details zur nicht-interaktiven Migrations-Vorgehensweise: backend/README.md.
Credential-Profile anlegen
Bevor Hosts gescannt werden können, braucht es mindestens ein CredentialProfile pro
Vendor. Die vollständige Anleitung — inkl. wie man den passenden Vault-Eintrag
vorbereitet und dessen ID gezielt (ohne den ganzen Vault zu dumpen) über die bw-CLI
ermittelt — steht in
backend/README.md → Credential-Profile anlegen.
Eigene IP-Bereiche (OWN_IP_RANGES)
Deep-Dive verbindet sich automatisch zu neu entdeckten BGP-/OSPF-Neighbor-IPs und probiert dabei hinterlegte Credentials - das darf niemals gegen Upstream-/Peering-Partner-IPs oder ein untergeschobenes Gerät auf einer ehemals bekannten IP passieren. OWN_IP_RANGES in backend/.env legt daher fest, welche CIDR-Bereiche (IPv4 und/oder IPv6, kommagetrennt) als "eigenes Netz" gelten. Nur Neighbor-IPs innerhalb dieser Bereiche werden automatisch gescannt; alles außerhalb wird als Router mit Status OUT_OF_SCOPE sichtbar gemacht (für die Topologie), aber nie kontaktiert. Ist OWN_IP_RANGES leer, ist das Verhalten fail-safe: es wird nichts automatisch gescannt, bis der Wert gesetzt ist.