72 Commits
Author SHA1 Message Date
KayandClaude Sonnet 5 adb3a661ab Doku: README/Manual an Bug-37-Fix angepasst
M7-Status in README aktualisiert (REST-Schreibpfad + Hostkey-Trust
jetzt live verifiziert). Manual.md korrigiert: seit Bug 37 kann bei
REST-Verbindungen zusätzlich zum Zertifikat auch der SSH-Host-Schlüssel
zur Bestätigung erscheinen, nicht mehr nur eines von beiden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 16:28:10 +02:00
KayandClaude Sonnet 5 3034d8b874 Bug 37: SSH-Hostkey-Trust bei REST-Verbindungen proaktiv etablieren
Dedizierte SSH-Dienste (BackupService u.a.) sind der erste echte
SSH-Kontakt zu einem per REST verbundenen Router und trafen dort auf
einen unbestätigten Hostkey ohne Trust-UI (nur ReviewApplyView/
ExpertMenuDetailView-Fehlertext, kein Bestätigungsweg). Fix: nach
jedem erfolgreichen REST-Connect prüft ConnectionService den
SSH-Hostkey einmalig im Hintergrund und zeigt bei Bedarf denselben
Trust-Dialog wie der SSH-Fallback, ohne die aktive REST-Verbindung neu
aufzubauen. Live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 16:23:33 +02:00
KayandClaude Sonnet 5 9de9311bee M26+M27: Seriennummer bei Bekannte Router, Schlüsselbund-Trennung, terse-Fallback verallgemeinert
M26: SavedRouter bekommt ein optionales serialNumber-Feld. Zwei
physisch verschiedene Router mit identischem Host+Benutzername
(Werks-Adresse) blieben bisher ein gemeinsamer "Bekannte Router"-
Eintrag; recordSuccessfulConnection matcht jetzt zusätzlich nach
Seriennummer, mit sauberer Migration bestehender Einträge ohne
Seriennummer. Drei neue Tests.

M27, beim Live-Test von M26 gefunden:
- Passwort-Anzeige-Button (Augen-Symbol) im Verbinden-Tab
- Bug 35: KeychainService speicherte Passwörter nur nach
  "username@host" — beide Router teilten sich denselben
  Schlüsselbund-Eintrag trotz getrennter SavedRouter-Einträge. Fix:
  optionaler serialNumber-Parameter qualifiziert den Account-Key,
  mit Fallback auf den alten Key für bereits gespeicherte Passwörter.
- Bug 36: neuer Router zeigte keine Routerboard-Infos/Seriennummer —
  derselbe Root Cause wie der zuvor gemeldete "Jetzt prüfen"-Fehler:
  /system routerboard und /system package update scheitern auf diesem
  Router mit "expected end of command" statt dem bisher einzig
  abgefangenen "bad parameter terse". SSHTransport.fetchMenuItems
  erkennt jetzt beide Formulierungen.

Alles live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 14:02:27 +02:00
KayandClaude Sonnet 5 8a5df3338a M25: Einrichten-Wizard-Politur + SSH-Trust-Persistenz endlich verifiziert
- WAN-Schritt: fehlenden "Zurück"-Button ergänzt (beide Modi)
- "Abbrechen"/"Jetzt sichern" prominent gemacht (wie "Neu scannen")
- LAN-/VLAN-Schritt: Adressfelder starten leer, nur Format-Beispiel im
  Feld sichtbar statt vorbelegter Werte. VlanStepView bekam dafür eine
  Validierungssperre auf "Weiter" (fehlte bisher, war ok solange
  Defaults immer gültig waren). Zwei Tests entsprechend angepasst.
- SSH-Host-Key-Trust aus M24 hatte sich entgegen der Live-Bestätigung
  nie tatsächlich persistiert (defaults read zeigte leeren Schlüssel,
  Ursache ungeklärt) — betraf BackupServices dedizierte SSH-Verbindung
  beim ersten Experte-Tab-Schreibversuch pro Sitzung. Erneut über den
  bestehenden Trust-Dialog bestätigt, diesmal per defaults read
  verifiziert statt nur der UI-Bestätigung vertraut.

Alles live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 12:41:47 +02:00
KayandClaude Sonnet 5 086393d379 Manual.md: drei fehlende, bereits live bestätigte Features ergänzt
Vollständiger Review (DE+EN) auf Nutzerwunsch. Gefunden und ergänzt:
REST-Zertifikat-Dialog (bisher nur SSH-Host-Schlüssel dokumentiert,
obwohl REST seit M22 der bevorzugte Pfad ist), "Abbrechen"-Button im
Einrichten-Wizard, einklappbare Kategorien im Experte-Tab (M23). Dazu
Icon-Farbbedeutung beim LAN-Scanner-Traffic-Monitor ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 11:54:11 +02:00
KayandClaude Sonnet 5 69c4a03024 LAN-Scanner: veraltete Rechtsklick-Hinweise durch Aktionen-Button ersetzt
Der Aktionen-Button (M24) ersetzte den Rechtsklick im Code, aber ein
App-eigener Warnhinweis (Feste-IP-Bestätigung) und README.md/Manual.md
(DE+EN) verwiesen weiterhin auf Rechtsklick. Gefunden durch Nutzer-
Hinweis nach Prüfung auf Gitea.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 11:51:42 +02:00
KayandClaude Sonnet 5 4cc30a2016 M24: LAN-Scanner Aktionen-Button, Traffic-Monitor+Sparkline, ARP-Fix
- Rechtsklick-Kontextmenü ersetzt durch sichtbaren "Aktionen"-Button
  je Geräte-Zeile (bisher nicht diskoverbar)
- Live-Traffic pro Port (↓/↑, wiederverwendet InterfaceTrafficMonitor)
  plus kleines Sparkline-Liniendiagramm der letzten 10 Sekunden
  (Swift Charts, neuer TrafficSample-Typ)
- Bug 34: ARP-Tabelle kann mehrere Zeilen für dieselbe MAC halten
  (reachable + stale/failed) — Auflösung bevorzugte bisher blind die
  zuletzt gesehene Zeile statt die erreichbare. Zwei Regressionstests.
- Nebenbefund: dedizierte SSH-Dienste (Backup/NetworkTools/Traffic/
  Update/FactoryReset) haben keinen eigenen Bestätigungspfad für einen
  neuen SSH-Host-Key, scheitern still solange REST verbindet — als
  offener Punkt dokumentiert.

Alles live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 11:46:01 +02:00
KayandClaude Sonnet 5 567feed93a M23: Experte-Tab-Sektionsüberschriften prominenter + einklappbar
Section-Header größer/fett mit adaptivem accentColor-Hintergrund statt
macOS' winzigem Kapitälchen-Default. Einklappbar per eigenem Chevron
(immer sichtbar, nicht macOS' Hover-only-Sidebar-Dreieck) statt
Section(isExpanded:), da SwiftUI dessen natives Disclosure-Verhalten
nicht anpassen lässt. Startet standardmäßig komplett zugeklappt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 11:03:39 +02:00
KayandClaude Sonnet 5 a0e7e53f22 M7: REST-Transport erstmals live verifiziert, vier Bugs gefunden+gefixt
Erstmaliger REST-Schreibtest gegen echte Hardware (www-ssl vorher auf
jedem Testgerät aus, Pfad lief nur gegen Mocks). Vier Bugs gefunden:

- baseURL fehlte trailing slash, relative URL-Auflösung warf "/rest"
  aus jedem Pfad (404, fiel still auf SSH zurück statt Zertifikat-
  Dialog zu zeigen)
- .add nutzte POST statt PUT (RouterOS' REST-API erwartet PUT für neue
  Einträge)
- RouterOS sendet Cache-Control: max-age=31536000 auf jede REST-
  Antwort, URLSession cachte dadurch die erste (leere) GET-Antwort für
  den Rest der App-Laufzeit
- Löschen aktualisierte die Experte-Tab-Liste nicht in-place (SwiftUI-
  Render-Problem, kein Datenfehler) — Anlegen/Bearbeiten laufen über
  ein Sheet, dessen Schließen automatisch neu rendert, Löschen über
  ein confirmationDialog ohne Remount

Anlegen/Bearbeiten (inkl. Feld-Leeren)/Löschen live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 10:51:55 +02:00
KayandClaude Sonnet 5 0237b3afbe Dauer-Editor auf Keepalive/Scheduler-Intervall/Netwatch-Intervall ausgerollt
WireGuard-Peer "Keepalive", Scheduler "Intervall" und Netwatch
"Prüf-Intervall" nutzen jetzt RouterOSFieldSchema.Kind.duration statt
Freitext. Netwatch-Default von "00:00:10" auf "10s" umgestellt, da
DurationFieldEditor.parse nur das Suffix-Format versteht, kein
HH:MM:SS. Vorher live geprüft, dass RouterOS das Suffix-Format bei
allen drei Feldern akzeptiert. Live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 10:03:35 +02:00
KayandClaude Sonnet 5 8bebef78fd HANDOFF.md: fetchMenuItems-Singleton-Fallback (Bug 20) nachgeprüft
Live an 12 Singleton-Menüs getestet — alle melden konsistent "bad
parameter terse (line 1 column N)", vom bestehenden Substring-Check
abgedeckt. Keine dritte, unbehandelte Fehlerform gefunden. Nebenbefund:
/system health ist kein Singleton, liefert echte Liste über terse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 09:41:24 +02:00
KayandClaude Sonnet 5 d3685bb8d4 HANDOFF.md: Übersicht-Interface-Highlight visuell bestätigt
Interface-Klick hebt live im Diagramm die komplette zusammenhängende
Kette hervor (inkl. zwei Hops entfernter Knoten), Pool/Adresse bleiben
bei der 1-Hop-Regel. War bisher nur per Unit-Test abgesichert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 09:39:01 +02:00
KayandClaude Sonnet 5 f34fc0587a Einrichten-Tab: "Abbrechen"-Button ergänzt
Vorher kein Weg aus dem Wizard außer schrittweise "Zurück" bis zu
Modus. Zentral als Toolbar-Button in SetupView (nicht pro Schritt
dupliziert), mit Bestätigungsdialog gegen Datenverlust, deaktiviert
während eines laufenden Apply. SetupViewModel.finish() in gemeinsame
resetToInitialState() plus benannte finish()/cancel()-Wrapper
aufgeteilt. Live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 09:34:03 +02:00
KayandClaude Sonnet 5 0b557b55e9 Firewall-NAT/Filter-Regeln beim Wizard-Apply idempotent machen
Wiederholter Wizard-Lauf gegen einen bereits konfigurierten Router hat
bisher jedes Mal dieselben NAT-/Filter-Regeln erneut angelegt (RouterOS
lehnt Duplikate hier nicht ab). SetupViewModel.apply holt jetzt einmalig
eine Live-Momentaufnahme der bestehenden Regeln und überspringt geplante
.add-Befehle mit identischem Argument-Set (ohne das rein schreibseitige
place-before). Live bestätigt: zweimaliger Wizard-Lauf, Regelanzahl
blieb beim zweiten Mal unverändert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 09:29:21 +02:00
KayandClaude Sonnet 5 e18eb2f714 HANDOFF.md: .id-Positions-Überlagerung live nachgeprüft (Bug 15)
Live-Vergleich :put [Pfad find] vs. print terse bei /ip address,
/ip route, /ip dhcp-server lease — Reihenfolge stimmte in allen drei
Fällen überein, kein erneuter Fehlgriff reproduzierbar. Entkräftet
Bug 15 nicht (RouterOS dokumentiert die Stabilität nirgends);
Timing-Race bei dynamischen Menüs (Lease-Tabelle) als Arbeitshypothese
festgehalten, echte Behebung bleibt offen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:48:47 +02:00
KayandClaude Sonnet 5 16706d5c6b M21: Zweisprachigkeit (DE/EN) auf alle fünf Tabs ausgerollt
Einrichten-Wizard (alle sieben Schritte), Übersicht, LAN-Scanner,
Sicherungen laufen jetzt über L10n.t statt fester deutscher
String-Literale — Experte- und Verbinden-Tab waren bereits vorher
umgestellt (M16/M17). Model-Layer-Strings werden am Verwendungsort
gewrappt, ViewModel-generierte Laufzeitstrings (Fehlermeldungen,
CLI-Zeilen, Log) bleiben bewusst unübersetzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:31:08 +02:00
KayandClaude Sonnet 5 04325e3bbd M20: LAN-Scanner umbenannt + Netzwerk-Tools (Ping/Traceroute/DNS/Port-Scan)
Tab "Geräte" -> "LAN-Scanner", Refresh-Button "Neu scannen" + prominenter
Stil. Neues Netzwerk-Tools-Menü: Ping/Traceroute/DNS-Auflösung über
NetworkToolsService (eigene SSH-Verbindung, wie Backup/InterfaceTraffic-
Monitor), mit Zeichen-Validierung gegen Command-Injection ueber einen
boeswilligen DHCP-Hostnamen. Port-Scan laeuft direkt von diesem Mac ueber
Network.framework (RouterOS hat kein eingebautes Portscan-Tool) - dabei
einen echten NWConnection-Bug gefunden (verweigerte Verbindung meldet sich
ueber .waiting, nicht .failed) und per Unit-Test gegen einen Loopback-Port
aufgedeckt und gefixt.

Zusaetzlich: Warnhinweis bei "Feste IP zuweisen" erklaert jetzt den
Rueckweg. DE/EN-Umschalter zeigt Landesflaggen statt Text.

92 Tests gruen. HANDOFF.md/README.md (inkl. Mermaid-Diagramm)/Manual.md/
CHATLOG.md aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 22:41:23 +02:00
KayandClaude Sonnet 5 b5933fa44b README: Mermaid-Architekturdiagramm um M17/M18 ergänzt
Dedizierte SSH-Verbindung für InterfaceTrafficMonitor, lokaler
SavedRoutersStore-Pfad (UserDefaults, kein Router-Zugriff).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 21:43:51 +02:00
KayandClaude Sonnet 5 31607b7270 M17-M19: Bekannte Router, Live-Traffic-Anzeige, Übersicht-Animation+Drag
M17: "Bekannte Router" im Verbinden-Tab (SavedRouter/SavedRoutersStore),
Standort-Freitextfeld, Scroll-Cap ab 4 Einträgen. Bugfix: Umbenennen-
TextField steckte in einem sich selbst deaktivierenden Button.

M18: Live-Traffic-Punkt an Interfaces (InterfaceTrafficMonitor, eigene
SSH-Verbindung, monitor-traffic-Polling). Dabei zwei reale CLI-Parser-Bugs
gefunden und gefixt: running/disabled-Flags werden als Buchstaben vor dem
ersten Feld codiert, nicht als key=value; monitor-traffic liefert
"50.7kbps" statt einer reinen Zahl.

M19: Übersicht-Tab — animierte Flussrichtung auf allen Verbindungslinien
(TimelineView+dashPhase), frei verschiebbare Knoten mit Live-folgenden
Linien, Zurücksetzen-Button.

Zusätzlich (noch nicht live getestet, nur Build+Unit-Tests grün):
LAN-Port-Konflikt-Prüfung im Einrichten-Assistenten mit doppelter
Sicherheitsbestätigung, "Fertig"-Button nach erfolgreichem Anwenden.

82 Tests grün. HANDOFF.md/README.md/Manual.md/CHATLOG.md aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 21:40:46 +02:00
KayandClaude Sonnet 5 9b26677dc2 Übersicht: Interface-Klick hebt transitiv alle zusammenhängenden Linien hervor
OverviewGraph.highlightedNodeIDs(startingAt:) macht für Interface-Knoten
eine BFS über alle Kanten statt nur 1-Hop-Matching, damit z.B. "DHCP-Server
-> Pool" oder "IP-Adresse -> DHCP-Netzwerk" mit sichtbar werden. Andere
Knotentypen bleiben unverändert bei 1-Hop. Logik isoliert unit-getestet
(GUI selbst nicht automatisiert klickbar). 61 Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 19:58:05 +02:00
KayandClaude Sonnet 5 ba6603ba64 HANDOFF.md: Router am 2026-09-15 erneut auf Werkseinstellungen zurückgesetzt
Alle Config-Stände aus früheren Sessions sind damit hinfällig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 16:36:10 +02:00
KayandClaude Sonnet 5 b6bb4bc289 M16: Verbinden-Tab zweisprachig (DE/EN)
ConnectView.swift auf L10n.t(...) umgestellt: Verbindungsformular, Status,
Geräte-/Routerboard-Infos, Update-/Firmware-Dialoge, Zertifikats-/SSH-
Warnungen. Dialog-Helper-Funktionen bekommen appLanguage-Parameter (liegen
außerhalb der View-Struct). Nebenbei fehlenden "Passwort"-Label-Eintrag im
Experte-Katalog nachgetragen. L10n.swift jetzt 444 Einträge, keine
Duplikate. 60 Tests grün, live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 16:18:02 +02:00
KayandClaude Sonnet 5 7af550ae85 M16 komplett: kompletter Experte-Tab zweisprachig (alle 9 Menü-Familien)
L10n.swift translations-Dictionary auf 376 Einträge erweitert: Firewall,
Interfaces, IP, Routing, VPN, WLAN, Queues, System, Werkzeuge. Zwei
Dictionary-Key-Kollisionen gefunden und behoben (Swift-Dictionary-Literale
crashen zur Laufzeit bei doppelten Schlüsseln). 60 Tests grün, live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 16:07:26 +02:00
KayandClaude Sonnet 5 0d16d05cb3 M16: Zweisprachigkeit (DE/EN) im Experte-Tab, eigener L10n-Helfer statt String Catalog
.environment(\.locale) + Localizable.xcstrings schaltete Text(LocalizedStringKey)
live nachweislich nicht um. Ersetzt durch Core/Localization/L10n.swift
(Dictionary-Lookup je AppStorage("appLanguage")), Umschalt-Button in der Toolbar.
Vollständig übersetzt: alle Tab-Namen, alle Menü-Kategorien, kompletter
Experte-Tab inkl. Firewall-Formulare. 60 Tests grün, live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 15:54:26 +02:00
KayandClaude Sonnet 5 2e507aa9ef M15 erweitert: Interfaces direkt editierbar (Übersicht + Experte-Tab)
Jedes Interface bekommt jetzt ein editTarget — VLAN-Interfaces über das
kuratierte /interface vlan-Schema (mit der eigenen .id aus /interface
vlan, nicht der generischen /interface-Liste), alle anderen Typen
(Ethernet, Bridge, WLAN, WireGuard) generisch über /interface.

Dabei live einen echten Stolperstein gefunden: für /interface gab es
bisher kein kuratiertes Schema, alle Felder landeten unbeschriftet in
"Weitere Parameter" — beim Versuch, ether5 zu ether51 umzubenennen,
wurde versehentlich default-name (RouterOS' Werksname, nie änderbar)
statt name geändert ("bad parameter default-name"). Fix: /interface
jetzt mit kuratiertem Schema (Name/Kommentar/Deaktiviert), Tooltip auf
"Name" warnt explizit vor der Verwechslung mit default-name.

Adress-Listen-Knoten bleiben bewusst weiter nicht editierbar (fassen
mehrere Einträge zusammen, bräuchten eine andere UI-Form).

Live bestätigt ("funktioniert"). 60 Unit-Tests grün. Manual.md/
HANDOFF.md aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 15:10:55 +02:00
KayandClaude Sonnet 5 bd610b0a8c Übersicht: Verbindungs-Label klarer, Verbindungszeilen anklickbar
Nutzerfrage: was bedeutet "Optionen" bei einer IP-Adresse verknüpften
DHCP-Netzwerk-Zeile? Umbenannt zu "DHCP-Optionen". Zusätzlich: die
"Verbindungen"-Zeilen im Detailpanel eines Knotens sind jetzt anklickbar
(springt zum verbundenen Element, wie bei Linien-Klicks) und zeigen
beim Hovern eine Klartext-Erklärung als Tooltip (OverviewStyle.
explanation(for:), bereits für EdgeDetailView gebaut).

59 Unit-Tests grün. Manual.md/HANDOFF.md aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 14:20:09 +02:00
KayandClaude Sonnet 5 a7272f059a Manual.md: bilingues Benutzerhandbuch für live verifizierte Funktionen
Deckt nur Funktionen ab, die live gegen echte Hardware bestätigt sind
(-Meilensteine): Verbinden, Einrichten-Wizard, Übersicht, Geräte,
Experte, Sicherungen — jeweils mit eigenem Inhaltsverzeichnis auf
Deutsch und Englisch. Absichtlich nicht enthalten: WLAN-Einrichtung,
Rest der Härtung (M5/M7, nur teilweise getestet) — siehe HANDOFF.md.

Wird künftig selbstständig bei jedem erfolgreich live getesteten
Meilenstein aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 14:08:50 +02:00
KayandClaude Sonnet 5 aebba46989 Bug 29: Übersicht-Tab aktualisierte sich nicht selbst beim Tab-Wechsel
.task lief nur einmal pro View-Lebenszeit — SwiftUI zerstört Tab-Inhalte
auf macOS beim Wechsel nicht, die View bleibt am Leben, .task feuert
also nie erneut beim Zurückwechseln. Fix: .onAppear statt .task, feuert
bei jedem Sichtbarwerden des Tabs neu — Änderungen aus dem Experte-Tab
(z.B. eine neu angelegte Route) erscheinen jetzt automatisch, ohne
manuellen "Aktualisieren"-Klick.

59 Unit-Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 14:02:48 +02:00
KayandClaude Sonnet 5 18fefc76a8 Bug 28: dynamische Routen (distance=0) nicht mehr über die Übersicht editierbar
Eine dynamische/verbundene Route (automatisch angelegt durch eine
IP-Adresse auf einem Interface) scheiterte beim Bearbeiten mit "no such
item (4)" — bestätigt per /ip route print detail: D-Flag, distance=0.
RouterOS' "dynamic"-Flag steht nicht zuverlässig in print terse
(dasselbe Problem schon bei DHCP-Leases dokumentiert), aber distance=0
ist ein verlässliches Signal, da keine echte statische Route das je
haben kann. Solche Routen bekommen jetzt kein editTarget mehr — ihre
.id ist ohnehin nicht stabil, RouterOS kann sie jederzeit neu anlegen.

59 Unit-Tests grün (neuer Test OverviewGraphTests.
testDynamicRouteHasNoEditTarget).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 13:54:11 +02:00
KayandClaude Sonnet 5 f25d02af17 Bug 27: unveränderter distance=0 einer dynamischen Route beim Set abgelehnt
Gleiche Ursache wie Bug 26, aber bei einem kuratierten statt einem
unkuratierten Feld: eine dynamische/verbundene Route hat distance=0,
RouterOS akzeptiert das nur system-intern, nicht als expliziten Eingabe-
wert für "set" — auch wenn der Wert unverändert zurückgesendet wird
("value of distance out of range (1...255)").

Fix generalisiert das "nur bei Änderung senden"-Prinzip aus Bug 26 von
unkuratierten auf ALLE Felder beim Bearbeiten eines bestehenden Items:
pendingCommand diffed jetzt gegen das ursprünglich geladene Item, statt
kuratierte Felder immer komplett neu zu senden. Deckt implizit auch das
Leeren eines Feldes ab (Bug 25), dessen Sonderfall dadurch überflüssig
wurde und entfernt ist.

Nebenbei: ExpertViewModelTests.swift lief bisher gar nicht mit, weil
nach dem Anlegen der Datei kein "xcodegen generate" lief (Xcodegen
erzeugt die Sources-Dateiliste einmalig beim Generieren). Nach erneutem
Generate 58 Unit-Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 13:42:45 +02:00
KayandClaude Sonnet 5 58c9ed5481 Bug 25/26: geleerte Felder blieben bestehen, Route-Bearbeiten scheiterte an nur-lesbarem Feld
Beide Bugs in ExpertViewModel.pendingCommand, betreffen Experte-Tab
direkt (nicht nur den neuen Übersicht-Bearbeiten-Weg):

- Bug 25: ein geleertes Textfeld (z.B. Kommentar löschen) wurde beim
  Speichern aus den Argumenten gefiltert statt explizit als "" gesendet
  — RouterOS' `set` ändert nur übergebene Parameter, ein weggelassener
  bleibt unangetastet statt geleert. Fix: Feld bleibt im Argument-Set,
  wenn es vorher einen Wert hatte; RouterOSCommand's SSH-Zeilen-Rendering
  gibt einen leeren Wert jetzt als `""` statt als nacktes `feld=` aus.
- Bug 26: eine Route bearbeiten (z.B. nur Kommentar ändern) scheiterte
  mit "bad parameter immediate-gw" — dieses von RouterOS mitgelieferte,
  nur lesbare/berechnete Feld landete unkuratiert in den freien
  "Weiteren Parametern" und wurde bei jedem Speichern blind
  mitgeschickt. Fix: ein unkuratiertes Feld wird nur noch gesendet, wenn
  sein Wert sich gegenüber dem ursprünglich geladenen Item tatsächlich
  geändert hat.

54 Unit-Tests grün (neue ExpertViewModelTests + eine Ergänzung in
RouterOSCommandBuilderTests).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 13:05:02 +02:00
KayandClaude Sonnet 5 216206b29f M15: Übersicht-Tab — Diagramm-Fixes + Direktes Bearbeiten
Diagramm-Fixes: echter Geometrie-Bug behoben (VLAN-/Bridge-Port-Kanten
laufen innerhalb derselben Spalte, eine Firewall/NAT-Kante rückwärts —
die Kurven-Berechnung nahm immer "rechts raus, links rein" an und schoss
dabei über den Canvas hinaus, links abgeschnitten). Hover-Flackern durch
Trägheit + Beschränkung auf hervorgehobene Kanten behoben. Klick-vs-
Hover-Priorität vertauscht (Klick gewinnt jetzt über Hover, vorher
verdrängte das Streifen fremder Karten beim Nachfahren einer Linie die
Auswahl). Linien-Klick zeigt jetzt volle Erklärung im rechten Panel
(EdgeDetailView) statt nur Hover-Tooltip. Ein Auto-Fit-Versuch
(GeometryReader) brach das Scroll-Verhalten und wurde wieder
zurückgezogen.

Neue Fähigkeit: ein Knoten (IP-Adresse, Pool, DHCP-Server/-Netzwerk/
-Client, Route, Firewall-Filter-/NAT-Regel, WireGuard-Peer) lässt sich
direkt über denselben Dialog wie im Experte-Tab bearbeiten und
zurückschreiben (OverviewNode.EditTarget + wiederverwendete
ExpertItemEditView). Live bestätigt: Kommentar-Änderung an einer
Firewall-Regel. 59 Unit-Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 12:50:13 +02:00
KayandClaude Sonnet 5 bf2ae58a20 Experte-Tab: ausführlichere Tooltips, Sektions-Überschrift, aktive Auswahl hervorgehoben
Alle RouterOSFieldSchema.help-Texte in RouterOSSchemaCatalog.swift
überarbeitet — jedes Adress-/Netz-/Bereichs-Feld hat jetzt ein
konkretes Beispiel (z.B. 192.168.88.1/24), vorher leere Hilfetexte
gefüllt.

Zusätzlich zwei UI-Wünsche umgesetzt: fette Überschrift (Menüname +
Kategorie) im Detailbereich, da vorher unklar war, in welcher Sektion
man sich befindet; und hellblaue Hervorhebung des aktiven Eintrags in
der linken Liste (per Zeileninhalt-Hintergrund statt
.listRowBackground, das vom macOS-Sidebar-Stil überschrieben wird).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 11:16:10 +02:00
KayandClaude Sonnet 5 fc3b2ca039 M8: Netzwerk-Isolation live verifiziert (manuell + über den Wizard)
Isolation zuerst manuell per SSH nachgebaut (ether5), danach über den
App-Wizard (Experte-Modus, ether4), um die eigentliche Abnahme-
Bedingung ("kompletter Wizard-Durchlauf") zu erfüllen. Dabei drei
App-Bugs gefunden und gefixt:

- Bug 22: neues LAN-/VLAN-Interface wurde nie der defconf-Interface-
  Liste "LAN" hinzugefügt, wodurch DNS-Anfragen an den Router selbst
  blockiert blieben (Werks-Firewall droppt Input von allem außerhalb
  dieser Liste).
- Bug 23: ein voller Wizard-Durchlauf gegen einen bereits konfigurierten
  Router brach am ersten nicht-idempotenten Add-Befehl ab
  (/ip address, /ip pool, /ip dhcp-server, /ip dhcp-server network).
- Bug 24: ein als eigenes isoliertes Netz konfiguriertes Interface
  blieb Bridge-"Slave" (Werks-Bridging), wodurch RouterOS die
  generierten Isolationsregeln selbst als ungültig verwarf.

Alle drei in DhcpServerCommandBuilder/SetupViewModel gefixt, 52 Unit-
Tests grün, Isolation+DNS+Internet am echten Gerät bestätigt. M8 auf
live verifiziert gesetzt. Nebenbei zwei veraltete Doku-Stellen zum
Gitea-Remote korrigiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 10:28:09 +02:00
KayandClaude Sonnet 5 19fa1d6ef4 README: Projektübersicht, Architektur-Diagramm, Meilensteine, Strukturverzeichnis
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 21:33:03 +02:00
KayandClaude Sonnet 5 0e8d910352 Wizard: idempotenter WAN-Apply fuer DHCP-Client/PPPoE (Bug 21)
Wizard erneut auf einem Interface durchlaufen, das schon einen
DHCP-Client hat (hier: aus einer zurueckgespielten Sicherung), scheiterte
live mit "failure: dhcp-client on that interface already exists" -
WanConfig.buildCommands() erzeugt fuer DHCP-Client/PPPoE immer .add, ohne
vorher zu pruefen, ob auf dem Interface schon einer existiert.

Fix: SetupViewModel.applyIdempotently faengt einen .add-Fehlschlag auf
/ip dhcp-client bzw. /interface pppoe-client ab und wiederholt ihn als
.set (nach "interface" gematcht) - bewusst nur fuer diese zwei Menues
mit "maximal ein Eintrag pro Interface"-Semantik, nicht generell fuer
jedes .add (z.B. /ip address erlaubt legitim mehrere Adressen pro
Interface).

Gefunden beim Versuch, M8 (Netzwerk-Isolation) live durchzutesten -
dieser Test selbst ist noch nicht abgeschlossen, naechste Session dort
weitermachen (siehe HANDOFF.md Naechste Schritte Punkt 1).

HANDOFF.md/CHATLOG.md aktualisiert: Bug 21, Sessionende-Stand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 20:43:56 +02:00
KayandClaude Sonnet 5 e72da84843 M14: Update-Check (Software+Firmware) + Karten-Design fuer Sektionen
Verbinden-Tab zeigt jetzt die volle Routerboard-Info (Modell/Revision/
Seriennummer/Firmware, aus /system routerboard) sowie einen
RouterOS-Software-Update-Check (/system package update: Kanal/
installierte/neueste Version/Status, "Jetzt pruefen"/"Update
installieren"), dazu "Firmware aktualisieren" fuer die
Routerboard-Bootloader-Firmware und "Jetzt neu starten" danach. Alle
vier Aktionen live bestaetigt, inklusive der zuvor unsicheren Frage, ob
/system routerboard upgrade's normalerweise interaktive Bestaetigung
den nicht-interaktiven SSH-Weg dieser App blockiert (tut es nicht).

Bug 20 gefunden und gefixt: fetchMenuItems' Singleton-Fallback (Bug 8)
reagierte nur auf eine geworfene Exception fuer "bad parameter terse",
aber RouterOS liefert diesen Fehler fuer /system routerboard mit
Exit-Code 0 zurueck (dasselbe Bug-10-Muster, diesmal beim Lesen statt
Schreiben) - die Routerboard-Sektion blieb dadurch leer, ohne Fehler.
Fix: zusaetzlich den Output-Text selbst pruefen, nicht nur die Exception.

Design-Durchgang: Verbinden-Detailseite/Sicherungen/Geraete liefen auf
nackter List ohne Rahmen - umgestellt auf Form+.formStyle(.grouped),
denselben nativen macOS-Karten-Look, den Wizard und Experte-Tab schon
hatten, fuer eine einheitliche App. Dark Mode auf Nachfrage gepueft und
ohne Codeaenderung bestaetigt funktionierend.

HANDOFF.md/CHATLOG.md aktualisiert: M14, Bug 20, Design-Durchgang,
Dark-Mode-Bestaetigung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 16:34:50 +02:00
KayandClaude Sonnet 5 20f8d5e0bf M13: Backup-Wiederherstellung, mit Modell-Schutz und Login-Erhalt
Letzter offener Punkt aus HANDOFF.md: gespeicherte .rsc-Backups lassen
sich jetzt wieder einspielen. Weg: Backup-Datei per SFTP auf den Router
hochladen (Citadel, die bereits eingebundene SSH-Bibliothek, hat einen
SFTP-Client), dann RouterOS' offiziell dokumentierter Restore-Weg in
einem Rutsch: /system reset-configuration no-defaults=yes
run-after-reset=<datei> (kompletter Wipe + sofortiges Wiederanwenden,
sicherer als ein Re-Import auf eine bestehende, andere Config).

Vor dem Bestätigungsdialog wird das Routermodell abgeglichen
(/system routerboard prints "model"-Feld gegen die "# model = ..."-
Kopfzeile der Sicherung) und bei Mismatch komplett blockiert, um ein
Brick-Risiko durch falsches Modell zu vermeiden - der Dialog selbst warnt
zusaetzlich prominent davor.

Ein ernster Bug live gefunden und gefixt: der erste echte Restore-Test
sperrte den Router komplett aus (RouterOS exportiert nie Passwoerter,
no-defaults=yes loescht zusaetzlich den Werks-Admin-Account), nur per
Hardware-Reset behebbar. Fix: das aktuell verwendete App-Login wird jetzt
vorne ins Restore-Skript eingefuegt, noch vor dem eigentlichen
Sicherungsinhalt, da RouterOS den Import beim ersten Fehler irgendwo im
Skript komplett abbricht. Zwei Tests fuer die Escaping-Logik ergaenzt.

Nebenbei: BackupListView mit den neuen Restore-Dialogen liess sich nicht
mehr kompilieren (SwiftUI-Typpruefung timeoutete bei der langen
Modifier-Kette) - Restore-Dialoge in eine eigene @ViewBuilder-Property
ausgelagert.

HANDOFF.md/CHATLOG.md aktualisiert: M13, Bug 18+19, "Backup-
Wiederherstellung fehlt" aus den offenen Punkten entfernt, Hinweis auf
den zweiten (ungewollten) Werksreset waehrend der Session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 15:21:05 +02:00
KayandClaude Sonnet 5 8e99ab8e41 Geräte-Tab: "Feste Zuweisung entfernen" (Rückweg zu dynamisch)
RouterOS kennt kein make-dynamic als Umkehrung von make-static (per
Recherche-Agent gegen die offizielle DHCP-Doku bestätigt: nur
check-status/make-static/send-reconfigure existieren) — der offizielle
Weg ist, die statische Lease zu entfernen; das Gerät bekommt beim
naechsten Verbindungsaufbau automatisch wieder eine dynamische Adresse,
moeglicherweise eine andere IP als zuvor.

Neuer Kontextmenü-Eintrag bei fest zugewiesenen Geräten im Geräte-Tab,
mit Bestätigungsdialog (erklärt den Ablauf) und Nachkontrolle, dass der
Lease-Eintrag wirklich entfernt wurde, bevor Erfolg gemeldet wird -
gleiche Vorsicht wie beim bestehenden "Feste IP zuweisen". Vom Nutzer
live bestätigt (fest zuweisen -> entfernen -> Kabel/WLAN neu verbinden
-> wieder dynamisch), kein neuer Bug diesmal.

HANDOFF.md/CHATLOG.md aktualisiert: "Zurück auf dynamisch" aus den
offenen Punkten entfernt, M12-Beschreibung ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 14:11:34 +02:00
KayandClaude Sonnet 5 e2b303963a M12: Geräte-Tab — LAN-Scanner mit Static-IP-Zuweisung
Neuer Tab: eine Tabelle pro physischem Ethernet/WLAN-Port mit den dort
gefundenen Geräten (Name, IP, MAC, Fest/Dynamisch/Kein-DHCP), gebaut aus
DHCP-Leases + ARP + Bridge-Host-Tabelle. Rechtsklick auf ein dynamisches
Gerät -> "Feste IP zuweisen" (RouterOS' "Make Static", per
/ip dhcp-server lease make-static), mit Bestätigungsdialog und
Session-Backup vor dem ersten Schreibvorgang (geteilter Mechanismus mit
dem Experte-Tab).

Vier reale Bugs live gefunden und gefixt (siehe HANDOFF.md Bug 14-17):

- "print terse" gibt das "dynamic"-Feld von /ip dhcp-server lease nie
  aus, in keinem Zustand -> Status kommt jetzt über RouterOS' find/get
  gegen die interne Eigenschaft, nicht aus gelesenen Feldern.
- fetchMenuItems' .id-Positionsüberlagerung ordnete für dieses Menü die
  falsche .id der falschen Zeile zu -> Erkennung und make-static-Ziel
  laufen jetzt über die MAC-Adresse statt .id.
- Ein SwiftUI-.confirmationDialog löschte sein eigenes Ziel-Objekt vor
  der Ausführung der bestätigten Aktion (Setter feuert bei jedem
  Knopfdruck, nicht nur Abbrechen) -> Dialog-Sichtbarkeit und
  Nutzlast entkoppelt, wie in BackupListView.
- Die eigene Verifikations-Abfrage (get [find ...] feld als ein
  kombinierter Befehl) war selbst eine nie verifizierte Annahme und
  lieferte falsche Negative -> ersetzt durch :foreach aus zwei einzeln
  bestätigten Bausteinen (find, get <id> feld).

RouterOSCommand bekommt einen neuen .action-Operationstyp für
RouterOS-"Menü-spezifische Befehle" jenseits von add/set/remove (aktuell
nur make-static). HANDOFF.md/CHATLOG.md mit allen vier Bugs, neuen
Milestones M11/M12 und offenen Punkten aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 13:55:46 +02:00
KayandClaude Sonnet 5 10f30a8a7f M11: Übersicht-Tab — IST-Zustand-Diagramm des Routers
Neuer Tab zeigt die komplette aktuelle Router-Konfiguration als grafisches
Diagramm: Interfaces, IP-Adressen, DHCP/Pools, Routen und Firewall/NAT in
Spalten, verbunden durch Linien, die RouterOS' eigene Referenzfelder
abbilden (VLAN->Basis-Interface, DHCP-Server->Pool, Firewall-Regel->
Interface/Adress-Liste usw.), nicht geraten. Rein lesend, kein apply().

Verbindungsarten sind farblich getrennt (8 Kategorien), Hover/Klick auf
eine Karte hebt ihre Linien hervor und blendet den Rest ab. Detail-Panel
zeigt Rohfelder + Verbindungen; Legende erklärt Spalten, Farben und listet
bewusst nicht gegraphte Bereiche (VPN, WLAN-Sicherheitsprofile, Queues,
System, Werkzeuge, Mangle/Raw), die weiterhin im Experte-Tab erreichbar
bleiben.

OverviewViewModel.buildGraph ist eine reine, nonisolated Funktion,
getestet in OverviewGraphTests (6 Fälle: IP/Interface, VLAN-Parent,
DHCP->Pool, DHCP-Netzwerk->passende IP-Adresse über RouterOS' eigenes
"network"-Feld, Route nur bei Interface-Gateway, Firewall->Interface/
Adress-Liste).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 10:05:39 +02:00
KayandClaude Sonnet 5 c9ecd3a0a9 M9/M10: Einfach/Experte-Modus + Experte-Tab (generischer RouterOS-Zugriff)
M9: Einrichten-Wizard bekommt einen Einfach/Experte-Modusschalter
(ModeStepView). Einfach überspringt VLAN, erlaubt nur ein LAN-Netzwerk
ohne Isolation, Firewall-Grundschutz fest an.

M10: neuer "Experte"-Tab mit generischem Motor (RouterOSMenuItem,
RouterOSCommand.remove, ConnectionService.fetchMenuItems, freies
"eigener Menüpfad"-Feld) plus kuratierten Formularen mit Tooltips
(RouterOSSchemaCatalog) für Firewall/NAT/Mangle/Raw/Adress-Listen,
Interfaces, IP, VPN, WLAN, Queues, System, Werkzeuge.

Live gegen einen hEX-Testrouter verifiziert (erst per SSH, dann vom
Nutzer selbst in der App), dabei 7 reale Bugs gefunden und gefixt —
der wichtigste: RouterOS' SSH-CLI gibt bei fehlgeschlagenen Befehlen
Exit-Code 0 zurück, wodurch apply() app-weit Fehler verschluckte statt
sie zu melden. Danach ergänzt: Bestätigungsdialog vor Anlegen/Ändern
+ Auto-Backup vor dem ersten Experte-Tab-Schreibvorgang je Sitzung
(Angleichung an den Wizard), sowie ein Dauer-Editor (Tage/Std/Min/Sek)
für Lease-/Ablaufzeit-Felder statt Freitext.

Details zu allen Bugs/Fixes: HANDOFF.md, CHATLOG.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EW3r6rW1xCf6UT5jNvt6rn
2026-09-14 00:03:50 +02:00
KayandClaude Sonnet 5 97fc216b0c Mikrotik-Setup-Referenz hinzugefügt (RB750Gr3, Multi-Netz-Szenarien)
CLI-Referenz für den hEX/RB750Gr3: gemeinsame LAN-Bridge vs. Port-pro-Netz,
Isolation über /interface list + in/out-interface-list statt einzelner
Paar-Regeln, Port aus bestehender Bridge herauslösen. Hintergrundmaterial
für kommende Arbeit an M8/Netzwerk-Isolation — noch nicht in der App
verarbeitet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYoWFMLHACvzzRC8u4iKF9
2026-09-13 19:57:25 +02:00
KayandClaude Sonnet 5 2697e4cff5 Handoff: M8-Stand dokumentiert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYoWFMLHACvzzRC8u4iKF9
2026-09-13 19:57:19 +02:00
KayandClaude Sonnet 5 5c8b5fd9d2 M8: Mehrere LAN-Interfaces + Netzwerk-Isolation (Firewall-Regeln pro Netzwerk)
lanConfig wird zu lanConfigs: [LanDhcpConfig] (analog zum VLAN-Listen-
Muster) — mehrere physische Interfaces mit je eigenem DHCP-Server.
Neues isolated-Feld auf LanDhcpConfig/VlanEntry: FirewallConfig erzeugt
daraus paarweise Forward-Drop-Regeln zwischen jedem isolierten Netzwerk
und allen anderen konfigurierten Netzwerken (Pair-Dedup bei gegenseitiger
Isolation). Behebt nebenbei, dass VlanStepView bisher Isolation im
Hilfetext behauptete, ohne dass eine Regel das durchsetzte.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYoWFMLHACvzzRC8u4iKF9
2026-09-13 19:57:15 +02:00
KayandClaude Sonnet 5 c1e6ec73b5 Chatlog: M7 SSH-Hostkey-TOFU-Session ergänzt (Session-Ende)
Kompletter Verlauf von Werksreset-Meldung über SSH-Hostkey-TOFU-Bau
(API-Verifikation im swift-nio-ssh-Quellcode, Fingerprint-Kreuzcheck
per ssh-keygen, Test-Isolationsbug gefunden+gefixt) bis zum fehlenden
Trennen-Button und der finalen Live-Bestätigung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-13 00:47:11 +02:00
KayandClaude Sonnet 5 570fe4999d Handoff: SSH-Hostkey-TOFU gegen echte Hardware bestätigt
Live-Test erfolgreich: erste Verbindung zeigte den Bestätigungsdialog,
nach Trennen+Neuverbinden lief es ohne Rückfrage durch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-13 00:45:38 +02:00
KayandClaude Sonnet 5 c77cd72cbd Verbinden-Tab: Trennen-Button ergänzt
ConnectionService.disconnect() existierte schon (bisher nur intern
nach Werksreset genutzt), aber ohne UI-Zugang im Verbinden-Tab selbst
-- Nutzer musste die App neu starten, um eine Verbindung sauber zu
beenden. Jetzt als Button direkt neben dem "Verbunden"-Status.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-13 00:44:18 +02:00
KayandClaude Sonnet 5 5c582a006b Handoff: SSH-Hostkey-TOFU-Stand dokumentiert
M7 als teilweise erledigt markiert (implementiert, aber noch nicht
gegen echte Hardware getestet), alte lo-Regel-Einschränkung entfernt
(durch Werksreset des Testgeräts erledigt), nächste Schritte um den
neuen TOFU-Dialog beim ersten Verbinden ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-13 00:41:43 +02:00
KayandClaude Sonnet 5 13344c265e M7: SSH-Hostkey-TOFU (ersetzt .acceptAnything())
Größte offene Härtungslücke geschlossen: SSHTransport nutzte bisher
.acceptAnything() für Host-Key-Validierung, akzeptierte also jeden
Schlüssel ohne Prüfung -- ein Man-in-the-Middle im lokalen Netz wäre
unbemerkt geblieben. Jetzt Trust-on-first-use wie beim REST-Zertifikat:

- SSHHostKeyFingerprint: SHA256 über NIOSSHPublicKey.write(to:) (die
  SSH-Wire-Format-Bytes des Schlüssels) -- exakt die Bytes, die auch
  OpenSSH für seine SHA256:-Fingerabdrücke hasht. Per Unit-Test gegen
  einen echten ssh-keygen-erzeugten Testschlüssel kreuzgeprüft
  (SHA256:Hllxv6LLoHl2XTIXGGjUYJHbPFoH2F7iMrR74C5J95g), nicht geraten.
- SSHHostKeyTrustStore: UserDefaults-Persistenz pro Host, Pendant zu
  CertificateTrustStore.
- SSHTransport conformt jetzt selbst zu NIOSSHClientServerAuthentication-
  Delegate (wie RestTransport zu URLSessionDelegate) und übergibt sich
  selbst als .custom(self) Host-Key-Validator.
- ConnectionService: neuer State .needsSSHHostKeyConfirmation, eigener
  Bestätigungs-Retry-Pfad (trustCurrentSSHHostKeyAndRetry), analog zum
  bestehenden Zertifikat-Flow.
- ConnectView: zweiter Bestätigungsdialog mit Warnhinweis, dass ein
  geänderter Fingerabdruck bei zuvor schon verbundenen Routern auf ein
  manipuliertes Netzwerk hindeuten könnte.

BackupService/FactoryResetService bekommen die TOFU-Prüfung automatisch
mit (SSHTransport-Default-Parameter, gleicher UserDefaults-Speicher),
ohne eigene Bestätigungs-UI -- in der Praxis unkritisch, da der
Verbinden-Tab das Vertrauen immer zuerst herstellt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-13 00:40:26 +02:00
KayandClaude Sonnet 5 9e6a38a5c5 Handoff + Chatlog auf aktuellen Stand gebracht (Session-Ende)
HANDOFF.md komplett überarbeitet: M5/M6-Live-Test-Ergebnisse, den
kritischen Interface-Parser-Bug (Bug 6) inkl. Ursache und Fix, neue
Zusatzfeatures (Tooltips, wählbarer Backup-Ordner, Schnell-Backup im
Verbinden-Tab, Werkseinstellungen-Reset, App-Icon), aktualisierte
Einschränkungen (Firewall-Regeln mit korrektem WAN-Port noch nicht
erneut kontrolliert, alte "lo"-Regeln evtl. noch auf dem Testgerät) und
konkrete nächste Schritte.

CHATLOG.md um die komplette Fortsetzung ergänzt: M5/M6-Bau, Live-Test
mit dem hEX-Gerät, das gemeinsame Debugging des Interface-Bugs
(PTY-Verdacht widerlegt durch Nutzer-Test, echte Ursache im Parser
gefunden), sowie alle Nutzer-Wünsche danach (Tooltips, Backup-Pfad,
Schnell-Backup, Werksreset, macOS-Deploy, App-Icon).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 21:49:50 +02:00
KayandClaude Sonnet 5 008ee653a6 App-Icon: "Signal Router"-Motiv
Eigenständiges Router-Symbol (Antennen + Gerätekörper mit Status-LEDs)
auf Türkis-Verlauf -- kein Nachbau von Mikrotiks eingetragenem Logo,
nur farblich an RouterOS angelehnt. Als SVG entworfen, per kleinem
AppKit/NSImage-Skript (kein Homebrew/librsvg nötig) in alle macOS-
Icongrößen von 16px bis 1024px gerendert.

project.yml: ASSETCATALOG_COMPILER_APPICON_NAME=AppIcon ergänzt, damit
Xcode das neue AppIcon.appiconset als App-Icon verwendet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 21:45:31 +02:00
KayandClaude Sonnet 5 a93a61c84f Werkseinstellungen wiederherstellen (Gefahrenzone im Sicherungen-Tab)
RouterOS bringt eine eigene Standardkonfiguration mit, wiederherstellbar
über /system reset-configuration no-defaults=no -- restauriert die vom
Hersteller ausgelieferte Konfiguration (nicht eine leere), RouterOS legt
dabei selbst zusätzlich ein Backup an (skip-backup=no, Standard).

FactoryResetService läuft wie BackupService immer über eine eigene
SSH-Verbindung (kein verifiziertes REST-Äquivalent, passt nicht ins
add/set-Modell von RouterOSCommand). Vor dem Zurücksetzen erstellt die
App zusätzlich selbst ein Backup (best-effort). Verbindung zum Router
bricht durch den Reboot erwartungsgemäß ab -- wird nicht als Fehler
behandelt, ConnectionService trennt sich danach selbst.

UI: rot markierte "Gefahrenzone" im Sicherungen-Tab, destruktiver
Bestätigungsdialog vor dem Ausführen, klarer Hinweistext was verloren
geht.

Außerdem .gitignore um /Backups/ und *.rsc ergänzt -- beim Testen des
wählbaren Backup-Ordners landete ein echter Router-Export im
Projektordner, gehört nicht ins Repo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 20:52:23 +02:00
KayandClaude Sonnet 5 9993f84311 Verbinden-Tab: Sicherung direkt nach dem Verbinden erstellbar
"Jetzt sichern"-Button erscheint sobald verbunden, noch bevor man in
den Einrichten-Tab wechselt -- Nutzer-Wunsch, um vor Änderungen ohne
Tab-Wechsel sichern zu können. Zeigt zusätzlich "Zuletzt gesichert: ..."
für den aktuell verbundenen Host, falls schon eine Sicherung existiert
(gefiltert auf den aktuellen Host, damit es bei mehreren Routern nicht
verwirrt). Nutzt dieselbe BackupViewModel/BackupService-Logik wie der
Sicherungen-Tab, eigene Instanz.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 20:44:47 +02:00
KayandClaude Sonnet 5 9d1aecc452 Tooltips für alle Konfigurationsfelder + wählbarer Backup-Ordner
.help(...)-Tooltips auf jedem Eingabefeld/Picker/Toggle in Connect-
sowie allen Einrichten-Schritten (WAN/LAN/VLAN/WLAN/Firewall) --
kurze Erklärung was der Wert bedeutet und welche Auswirkung er hat,
passend zum Laien-Anspruch der App.

Sicherungen-Tab: Speicherort jetzt änderbar (Ordner wählen über
nativen macOS-Dialog, Zurücksetzen auf Standard). BackupService hält
den gewählten Pfad in UserDefaults (BackupService.customDirectoryURL),
fällt ohne Auswahl weiter auf ~/Library/Application Support/... zurück.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 20:30:22 +02:00
KayandClaude Sonnet 5 c1f9940eae Fix: CLI-Parser verlor 6 von 7 Interfaces auf echtem hEX-Gerät
Kritischer Fund beim M6-Live-Test: RouterOSCliParser.parseInterfaces
splittete nur auf "\n", aber die SSH-Ausgabe eines echten hEX-Routers
trennt Zeilen anders -- alle Interface-Zeilen wurden zu EINER Zeile
zusammengefasst. Beim key=value-Parsen dieser einen Riesenzeile
überschrieb jedes Feld (name=, type=, ...) den vorherigen Wert, sodass
am Ende nur das letzte Interface im Text ("lo", Loopback) übrig blieb
-- mit den Feldwerten aller anderen Interfaces vermischt.

Folge: WAN-Schritt zeigte nur "lo" zur Auswahl, wodurch alle
WAN-Interface-Referenzen (NAT-Masquerade, ICMP-Regel, WAN-Block-Regel,
finale Anti-Spoofing-Regel) fälschlich auf "lo" statt den echten
WAN-Port zeigten. Auf diesem Testgerät blieb es folgenlos, weil RouterOS
schon eine vollständige eigene Standard-Firewall (defconf) mitbrachte,
die den echten Schutz weiterhin übernahm -- auf einem Gerät ohne
bestehende Firewall hätte das eine wirkungslose Firewall bedeutet, die
sich als aktiv ausgegeben hätte.

Fix: split(whereSeparator: \.isNewline) statt split(separator: "\n"),
robust gegen \n/\r/\r\n. Zusätzliches Sicherheitsnetz in SetupView:
Loopback-Interfaces werden aus allen WAN/LAN/VLAN-Auswahllisten
gefiltert, damit ein ähnlicher Parser-Fehler künftig nicht erneut zu
einer sinnlosen Interface-Auswahl führen kann. Regressionstest mit
realen \r\n-getrennten hEX-Daten ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 20:17:26 +02:00
KayandClaude Sonnet 5 da5133245e Handoff: M6-Stand + Gatekeeper-Testrunner-Hang dokumentiert
Neuer Abschnitt erklärt den xcodebuild-test-Hang (amfid/syspolicyd
Gatekeeper-Netzwerk-Check bei ad-hoc-signierten Binaries) als
Tooling-Eigenheit, nicht Code-Bug, und wie man ihn umgeht
(build-for-testing zum Compile-Check, echte Verifikation über Xcode).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 19:58:55 +02:00
KayandClaude Sonnet 5 772549c991 M6: Firewall-Schritt (opt-in Sicherheits-Grundschutz)
Standardmäßig aus (Toggle wie VLAN) -- höchstes Risiko aller bisherigen
Schritte, falsche Regeln können Fernzugriff kappen. Preset ist
Mikrotiks eigener Standard-Ansatz (unverändert seit Jahren in
RouterOS-Werkskonfigurationen): NAT/Masquerade auf WAN, established/
related erlauben, invalid verwerfen, unaufgeforderte WAN-Verbindungen
zu LAN-Geräten blocken (außer explizitem Port-Forward via
connection-nat-state=!dstnat).

Jede neue Regel bekommt ein place-before mit aufsteigendem Index,
damit sie vor eventuell schon vorhandenen Regeln des Routers landet --
sonst könnte eine bereits vorhandene "alles blocken"-Regel unsere
neuen Regeln wirkungslos machen. NAT und Filter sind getrennte,
unabhängig nummerierte RouterOS-Listen.

Vor dem Anwenden zeigt der Schritt die Anzahl bereits vorhandener
Filter-/NAT-Regeln (neuer fetchFirewallRuleCounts()-Aufruf in
RouterOSTransport/RestTransport/SSHTransport/ConnectionService) --
Transparenz, bevor auf einem möglicherweise schon konfigurierten
Router weitere Regeln landen. Nutzer-Entscheidung, extra Lese-Aufruf
in Kauf zu nehmen statt nur Warntext.

Build + Test-Compile (build-for-testing) sind grün. Der eigentliche
Testlauf (xcodebuild test) hängt aktuell an einem macOS-Gatekeeper-
Netzwerk-Check für ad-hoc-signierte Binaries (amfid: "adhoc signed or
signed by an unknown certificate chain", GK performScan über
syspolicyd) -- kein Code-Bug, tritt nur bei CLI-Testläufen auf, nicht
beim normalen Xcode-Cmd+R-Weg. Nutzer verifiziert M6 deshalb direkt in
Xcode.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 19:57:53 +02:00
KayandClaude Sonnet 5 ea6bc0bfed Handoff: M5 kein-WLAN-Zweig gegen echtes Gerät bestätigt
Testgerät hat keinen WLAN-Chip -- korrekt erkannt, Konfiguration lief
ohne WLAN-Befehle sauber durch. Der eigentliche SSID/Passwort-.set-Pfad
bleibt ungetestet, dafür fehlt ein Gerät mit echtem WLAN-Chip.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 18:56:00 +02:00
KayandClaude Sonnet 5 d715e21afb Handoff aktualisiert: M5-Stand, neues .set-Architekturprinzip
Reflektiert den WLAN-Schritt, die erweiterte RouterOSCommand-Operation
(.add/.set) und die noch fehlende Verifikation gegen echte
WLAN-Hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 13:42:34 +02:00
KayandClaude Sonnet 5 016f57f613 M5: WLAN-Schritt + echte set-Operation im Befehlsmodell
RouterOSCommand unterstützt jetzt neben .add auch .set (bestehenden
Eintrag ändern statt neuen anzulegen) — nötig, weil WLAN-Interfaces
schon vor jeder Konfiguration existieren. SSH löst das per CLI-eigenem
"set [find field=value] ..." inline auf; REST hat dafür keine
Entsprechung und muss den Eintrag erst per GET suchen (matchField/
matchValue), seine .id auslesen, dann PATCH auf restPath/<id> senden
(RestTransport.findItemID). Mit dem Nutzer abgestimmte Entscheidung
gegen die einfachere "WLAN nur über SSH"-Variante.

WifiNetworkConfig: pro erkanntem Legacy-Wireless-Interface
(/interface wireless, type=wlan) eine SSID/Passwort-Konfiguration,
Sicherheitsprofil (WPA2) wird zuerst angelegt, dann per set mit dem
Interface verknüpft. Geräte ohne WLAN zeigen einen Hinweistext statt
des Formulars (User-Anforderung: muss berücksichtigt werden). Geräte
mit dem neueren "wifi"-Treiber (type=wifi, wifiwave2/802.11ax) werden
erkannt, aber bewusst nicht unterstützt -- anderes Menü, eigener
Umbau nötig, dazu Hinweistext.

cliPath wurde in allen bisherigen Command-Buildern (Wan/Lan/Vlan) zu
menuPath + .add migriert, da RouterOSCommand jetzt operation-basiert
ist statt den Aktionswort im Pfad-String zu verstecken.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-12 13:41:25 +02:00
KayandClaude Sonnet 5 a240cfb4e8 Chatlog dieser Session hinzugefügt
Lesbare Nacherzählung des Gesprächsverlaufs (Planung, M1-M4, komplette
Live-Debugging-Kette gegen echtes Testgerät). Kein Rohtranskript --
das interne Session-Log liegt als ~8,7 MB JSONL vor und ist fürs Repo
nicht sinnvoll.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 22:21:16 +02:00
KayandClaude Sonnet 5 9db6031bca Handoff-Dokument: Architektur, gefixte Bugs, bekannte Einschränkungen
Fasst Stand nach M1-M4 zusammen: Aufbau, alle Live-Test-Fixes gegen
echtes Testgerät (SwiftUI-Observation, NIOSSHError/CommandFailed-
Fehlertexte, SSH-Algorithmen, Picker-Defaults), bewusste Scope-
Entscheidungen (VLAN ohne Port-Tagging) und offene Punkte für M5-M7.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 22:17:41 +02:00
KayandClaude Sonnet 5 9f2ad2c9e9 M4: VLAN-Schritt (separates virtuelles Netz)
Neuer optionaler Schritt im Einrichten-Wizard, standardmäßig
übersprungen (Toggle): legt ein VLAN-Interface auf einem gewählten
Basis-Anschluss an, mit eigenem IP-Bereich und eigenem DHCP-Server —
z.B. für Gäste/IoT. Bewusst ohne Port-Zuweisung (Access/Trunk): das
bräuchte RouterOS Bridge-VLAN-Filtering mit "set"-Operationen auf
bestehende Einträge, die unser bisheriges reines "add"-Befehlsmodell
(identisch für REST+SSH) nicht abdeckt. Wer ein VLAN auf einem
bestimmten Switch-Port braucht, muss den Trunk weiterhin manuell
einrichten. Entscheidung mit Nutzer abgestimmt.

DHCP-Befehlsbau (Adresse+Pool+Server+Netzwerk) aus dem LAN-Schritt in
DhcpServerCommandBuilder extrahiert, da jetzt zweimal identisch
gebraucht (LAN direkt, VLAN pro Eintrag).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 22:13:31 +02:00
KayandClaude Sonnet 5 582eced109 Fix: Picker-Warnungen durch ungültige WAN/LAN-Interface-Vorgaben
wanConfig/lanConfig starteten mit festen Platzhaltern ("ether1"/
"bridge"), die nicht zwangsläufig zu den tatsächlichen Interfaces des
verbundenen Geräts passen -> SwiftUI-Picker meldete ungültige
Selection. prepareDefaults() korrigiert jetzt beide (vorher nur WAN)
anhand eines allgemeinen "ist der Wert überhaupt in der Liste"-Checks
statt nur "ist es noch der Platzhalter", und läuft bereits im init
statt erst bei onAppear, damit der erste Render schon die echten
Werte zeigt.

Aufgefallen beim Live-Test gegen echtes Testgerät (Konsolenwarnung
"the selection ... is invalid and does not have an associated tag").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 21:57:36 +02:00
KayandClaude Sonnet 5 5117386a4e Fix: SSH-Befehlsfehler zeigt RouterOS-Fehlertext statt nur Exit-Code
Citadels executeCommand() verwirft die gesammelte Kommandoausgabe,
sobald der Exit-Code ungleich 0 ist -- genau der Text, den RouterOS
bei einem fehlerhaften Befehl zurückgibt (z.B. falscher Parameter,
Interface existiert nicht). Eigene Sammlung über
executeCommandStream() behält die Ausgabe bis zum Fehlschlag und
hängt sie an die Fehlermeldung an.

Aufgefallen beim ersten Schreibtest (M3 "Einrichten"-Tab) gegen
echtes Testgerät: Fehler kam nur als nutzloses
"Citadel.SSHClient.CommandFailed error 1" durch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 21:49:30 +02:00
KayandClaude Sonnet 5 abe5864ea3 Fix: SSH-Verbindung scheiterte an Key-Exchange-Aushandlung mit RouterOS
RouterOS' SSH-Server bietet typischerweise nur ältere Algorithmen an
(diffie-hellman-group14-sha1, RSA-Hostkeys), die in Citadels
Standard-Algorithmenliste fehlen -> keyExchangeNegotiationFailure beim
Verbindungstest gegen echtes Gerät. Citadels vorgefertigtes
SSHAlgorithms.all-Preset aktiviert diese Legacy-Algorithmen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 21:35:25 +02:00
KayandClaude Sonnet 5 5b7c51f62b Fix: SSH-Fehlermeldung zeigt echten NIOSSHError-Grund statt Platzhalter
NIOSSHError.localizedDescription bridged auf NSError und liefert nur
"The operation couldn't be completed. (NIOSSH.NIOSSHError error 1.)" —
der eigentliche Fehlertyp/die Diagnostik steckt in der internen
CustomStringConvertible-Beschreibung. String(describing:) statt
.localizedDescription verwenden, um den echten Grund (z.B. Algorithmus-
Aushandlung, Host-Key, Auth) sichtbar zu machen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 21:33:29 +02:00
KayandClaude Sonnet 5 6c230827be Fix: ConnectView zeigte nie Verbindungsstatus an
connectionService war nur über viewModel.connectionService erreichbar,
ein zwei Ebenen tief verschachteltes ObservableObject. SwiftUI abonniert
automatisch nur Objekte, die eine View direkt per @StateObject/
@ObservedObject hält — nicht transitiv erreichte. Dadurch blieb die
Oberfläche beim echten Verbindungstest (physisches Mikrotik-Gerät)
komplett unverändert hängen, obwohl die Verbindung im Hintergrund
korrekt lief oder fehlschlug.

Fix: ConnectView hält connectionService jetzt zusätzlich selbst als
@ObservedObject, direkt von der App-Ebene durchgereicht.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 21:29:56 +02:00
KayandClaude Sonnet 5 87f4fa188c M3: WAN + LAN/DHCP-Wizard mit Anwenden-Logik
Neuer "Einrichten"-Tab führt durch Internet-Anschluss (DHCP/statisch/
PPPoE) und Heimnetzwerk+DHCP-Server, zeigt vor dem Anwenden eine
Klartext-Übersicht (optional mit den exakten RouterOS-Befehlen) und
erstellt automatisch eine Sicherung, bevor Änderungen geschrieben
werden. Änderungen laufen über beide Transporte: CLI-Zeile für SSH,
JSON-POST für REST — beide aus einem gemeinsamen RouterOSCommand
gebaut. RouterOS-CLI-Syntax ist Standard und langjährig stabil, aber
nicht gegen ein echtes Gerät verifiziert; deshalb die Detailanzeige
im Übersichtsschritt vor dem Anwenden.

ConnectionService ist jetzt der einzige App-weite Zustand (ersetzt
SessionStore) und wird explizit an alle drei Tabs durchgereicht.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 21:07:34 +02:00
KayandClaude Sonnet 5 c4ed26b8dd M2: Backup-Service + Sicherungen-Tab
Config-Export (/export terse) über eine dedizierte SSH-Verbindung,
unabhängig vom aktiven Live-Transport (REST oder SSH) — RouterOS' REST-API
hat keinen generischen Export-Endpunkt. Lokale Sicherungen unter
~/Library/Application Support/RouterOSAssistant/Backups/. Neuer
"Sicherungen"-Tab mit manuellem "Jetzt sichern"-Button, SessionStore
teilt die Zugangsdaten der aktiven Verbindung zwischen den Tabs.

Der bestehende Connect-Schritt dient bereits als reiner Lese-Modus
(nur GET-Aufrufe) — ein zusätzlicher Dry-Run-Schalter entfällt, da es
vor M3 noch keine Schreibpfade gibt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 20:58:39 +02:00
KayandClaude Sonnet 5 63734ef7fe M1: Projektgerüst + Connect-Schritt (REST/SSH-Autodetect)
XcodeGen-basiertes SwiftUI-Projekt für den RouterOS-Interview-Assistenten.
Erster Wizard-Schritt: Verbindung zu Mikrotik-Geräten per REST-API
(RouterOS >=7.1) mit SSH-CLI-Fallback für ältere Firmware, Zertifikats-
TOFU-Bestätigung, Zugangsdaten im Keychain. Unit-Tests für CLI-Parser
und Fallback-Logik.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HReLXMbmPvtQ23p1iWiJNW
2026-09-11 20:51:26 +02:00