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
This commit is contained in:
Kay
2026-09-14 00:03:50 +02:00
co-authored by Claude Sonnet 5
parent 97fc216b0c
commit c9ecd3a0a9
21 changed files with 2252 additions and 32 deletions
+222
View File
@@ -231,3 +231,225 @@ TOFU (M7) ist fertig und live bestätigt. Offene Punkte: Firewall-Regeln
mit korrektem WAN-Port nach dem Werksreset noch nicht erneut kontrolliert,
WLAN-`.set`-Pfad weiterhin ohne Testgerät mit echtem WLAN-Chip, Rest von
M7 (Fehlerzustände/Politur, REST-Schreibtest mit aktivem `www-ssl`).
## M8 (separate Session, hier nachträglich kurz notiert)
Nutzer, neuer Tag: Frage, ob mehrere Router-Interfaces in einem
Konfigurationsvorgang mit je eigenem DHCP-Server (und optional VLAN)
einrichtbar sind. Antwort ja → als M8 gebaut:
`SetupViewModel.lanConfigs: [LanDhcpConfig]` (mehrere LAN-Netzwerke statt
einem) plus Isolations-Toggle pro LAN-/VLAN-Eintrag, der bei aktivem
Firewall-Grundschutz paarweise Forward-Drop-Regeln erzeugt
(`FirewallConfig.NetworkSegment`). Kompiliert, Release gebaut und nach
`/Applications` deployt, `HANDOFF.md` + eine `mikrotik-setup.md`-
Referenzdatei (RB750Gr3-Szenarien: gemeinsame Bridge, komplett getrennte
Netze, Port aus Bridge lösen) gespeichert. Nur Unit-Test-verifiziert,
nicht gegen Hardware.
## Session 2026-09-13: Einfach/Experte-Modus + Experte-Tab
- "wir machen zwischendurch mal was anderes. ich brauche einen einfachen
Modus und einen Experten-Modus" — einfacher Modus: nur Grundeinrichtung
(kein VLAN, kein Mehrfach-DHCP, keine Port-Trennung), Experte: voller
Zugriff. Rückfrage per AskUserQuestion zum genauen Schnitt (WAN+LAN vs.
+WLAN/Firewall) — Nutzer wählte "WAN+LAN+WLAN+Firewall, Firewall fest
an". Als M9 gebaut: neuer erster Wizard-Schritt `ModeStepView`,
`SetupStep.goNext/goBack` von linearem `rawValue+1` auf expliziten
`switch` umgebaut (VLAN-Schritt wird im Einfach-Modus übersprungen),
Isolations-Toggle/Mehrfach-LAN im LAN-Schritt nur im Experte-Modus
sichtbar. Build+Tests grün.
- "wir machen weiter bei Expert. hier wird es umfangreich. [...] Ich
brauche nun Zugriff/Einstellungsmöglichkeit auf alle Funktionen, was
RouterOS bietet (Isolation, Firewalling, NAT alles was der Router
kann). Wir wollen hier ein echtes Experten-Tool bauen." — vor dem Bauen
per WebSearch/WebFetch in die offizielle RouterOS-Dokumentation
(manual.mikrotik.com, help.mikrotik.com) eingelesen: Firewall-Struktur
(Filter/NAT/Mangle/Raw-Chains, Adress-Listen, Connection-Tracking,
Layer7), volle CLI-Menübaum-Übersicht (300+ Top-Level-Menüs).
- Versuch, den Umfang mit einer AskUserQuestion einzugrenzen (nur
Firewall/NAT vs. zusätzlich VPN/Routing vs. wirklich alles) — **vom
Nutzer abgelehnt**: "alles was du findest,, der komplette Umfang des
RouterOS soll eingestellt werden könnn." Als Feedback-Memory
gespeichert: bei bereits klar geäußertem vollem Scope nicht nochmal
nachfragen, sondern eine Architektur bauen, die diesen Scope praktisch
abdeckt.
- Architekturentscheidung (da 300+ Menüs unmöglich einzeln von Hand
modelliert werden können): zweistufig. (1) Generischer Motor —
`RouterOSMenuItem`, `RouterOSCliParser.parseGenericItems`, neue
`RouterOSCommand.remove`-Operation, `ConnectionService.fetchMenuItems`
+ Transport-Implementierungen, dazu ein freies "eigener Menüpfad"-Feld
im UI — deckt technisch jeden Pfad ab, auch unkuratierte, als rohes
Schlüssel/Wert-Formular. (2) Kuratierte Schemas
(`RouterOSSchemaCatalog`) mit echten Formularfeldern, Tooltips,
Erklärtext und Warnhinweisen — komplette Firewall-Familie
(Filter/NAT/Mangle/Raw/Adress-Listen) sofort voll kuratiert, weitere
Bereiche (Interfaces/IP/VPN/WLAN/Queues/System/Werkzeuge) zunächst nur
generisch gelistet. Neuer "Experte"-Tab (`ExpertView`/
`ExpertViewModel`/`ExpertMenuDetailView`) in die App eingehängt. Build
+ alle Tests grün.
- "machen wir mit (a) weiter" (mehr Kategorien kuratieren statt sofort
Live-Test) — Interfaces (Bridge, Bridge-Port, VLAN, WireGuard+Peers,
PPPoE-Client, Bonding), IP (Adressen, Pools, DHCP-Server+Netzwerk,
DHCP-Client, DNS, Verwaltungsdienste, Routen), VPN (PPP-Secret/Profil),
WLAN (Legacy + neuer wifiwave2-Treiber + Sicherheitsprofile — Feldnamen
für den neuen Treiber vorab per WebSearch aus der offiziellen
Dokumentation verifiziert, nicht geraten), Queues (Simple/Tree), System
(Identity/Clock/NTP/Scheduler/Skripte/Nutzer), Werkzeuge (Netwatch/
E-Mail) kuratiert. OSPF/BGP und der neue WLAN-Treiber-Feldnamen-Versuch
per WebFetch gegenrecherchiert, aber für Routing keine ausreichend
verifizierte Quelle gefunden → bewusst generisch belassen statt
geraten. Build+Tests grün.
- "machen wir einen Livetest" → Zugangsdaten erhalten, Testansatz erklärt
(direktes SSH statt UI-Automatisierung, da kein Tool für native-macOS-
UI-Steuerung verfügbar ist). `sshpass` fehlte, `expect`-Skript als
Ersatz gebaut. Alter SSH-Host-Key in `known_hosts` stimmte nicht mehr
(Router war zwischenzeitlich zurückgesetzt worden) — alten Eintrag
entfernt, dabei eine unabhängig kaputte Zeile in `known_hosts`
mitgefunden und bereinigt.
- Vor jeder Änderung Config-Backup (`/export terse`) gezogen. Systematisch
jede kuratierte Menü-Familie einmal komplett durchgespielt (anlegen →
mit `print` prüfen → wieder entfernen): Firewall Filter/NAT/Mangle/Raw/
Adress-Listen, VLAN, WireGuard+Peer, IP-Pool, DHCP-Server+Netzwerk,
Route, PPP-Secret/Profil, Queue Simple, Scheduler+Skript, Netwatch —
alle Feldnamen bestätigt.
- **Zwei echte Bugs gefunden:** (1) `/ip service`s Zugriffsfilter-Feld
heißt `available-from`, nicht wie im Schema angenommen `address`. (2)
RouterOS 7.24.2 zeigt `.id` gar nicht in `print terse`-Ausgaben (anders
als angenommen), und Menüs mit nur einem Eintrag statt einer Liste
(`/ip dns`, `/system identity`, `/system clock`, `/system ntp client`,
`/tool e-mail`) lehnen `terse` komplett ab. Live herausgefunden, dass
`:put [<Pfad> find]` die echten internen IDs in exakt der Reihenfolge
von `print terse` liefert (per Stichprobe kreuzgeprüft) — als Fix
genutzt, plus neuer `RouterOSMenuSchema.isSingleton`-Schalter mit
eigenem Fetch-/Set-Pfad für die Ein-Eintrag-Menüs. Fix live gegen
`/system identity` bestätigt (Name testweise geändert, zurückgesetzt).
- Nach dem Test: `/export terse` erneut gezogen und gegen das
Ausgangs-Backup verglichen — bis auf den Zeitstempel-Kommentar
byte-identisch, alle Testeinträge sauber entfernt.
- "alles nochmal speichern (Handoff, Chatlog, Memory)" → dieser Eintrag,
`HANDOFF.md` (M9/M10-Abschnitte, Bug 7/8, aktualisierte
Einschränkungen/Nächste-Schritte) und Memory aktualisiert.
## Nachtrag: erster Release-Deploy + Nutzer testet selbst in der App
- "baue Release neu und deploye nach /Applications" → Release gebaut,
altes `/Applications/RouterOS Assistant.app` ersetzt.
- Nutzer meldete direkt danach: "wenn ich einen DHCP Server neu anlege,
kann ich den vorher angelegten Adress-Pool nicht in der Auswahl sehen."
→ Bug 9 gefunden: Cross-Referenz-Felder (DHCP-Server→Pool, PPP-Secret→
Profil, Scheduler→Skript, Filter→Adress-Liste, WireGuard-Peer→
Interface) waren reiner Freitext statt Auswahl. Neuer Feldtyp
`RouterOSFieldSchema.Kind.menuItemPick` gebaut, lädt beim Öffnen eines
Menüs live die Namen aus dem referenzierten Menü. Build+Tests grün,
Nutzer bestätigte "ja bitte" → Release neu gebaut+deployt.
- Nutzer: "die auswahl funktioniert jetzt, aber der DHCP-Server wird nicht
angelegt." → Frage nach Fehlermeldung: keine. Live reproduziert: exakt
derselbe `/ip dhcp-server add`-Befehl über direktes SSH lieferte
`"failure: server or relay with such interface already exists"` **mit
Exit-Status 0** (per `expect`-Skript + `catch wait result` geprüft,
zusätzlich mit einem zweiten Fehlerfall — ungültiger `action=`-Wert,
`"syntax error"` — bestätigt). Bug 10 gefunden: `SSHTransport.apply()`
erkannte Fehler nur am Exit-Code, der bei RouterOS' SSH-CLI aber nie
ungleich 0 wird. Betraf `apply()` app-weit, nicht nur den Experte-Tab.
Fix: jede nicht-leere Ausgabe eines add/set/remove-Befehls gilt jetzt
als Fehler (laut allen 15+ live getesteten Befehlsfamilien sind
erfolgreiche mutierende Befehle immer still). Nutzer wollte zusätzlich
einen echten Test: VLAN mit eigenem DHCP-Server auf einem freien
Interface komplett neu durchgespielt (VLAN→IP→Pool→DHCP-Server→
Netzwerk), lief fehlerfrei, danach entfernt. Release neu gebaut+deployt.
## Nachtrag: Nutzer testet erstmals selbst in der App-UI
- "leg jetzt VLAN mit eigenem DHCP-Server an, aber mir fehlen komplett die
'löschen-Buttons'" — zwei Anliegen. Live-Test des DHCP-Server-Flows mit
`disabled=no` bestätigte den Bug-10-Fix nochmal. Für die Lösch-Buttons:
Ursache war `.swipeActions` — eine iOS/iPadOS-Wischgeste ohne
Entsprechung auf macOS-Listen (Bug 12). Fix: sichtbarer
Papierkorb-Icon-Button je Zeile. Release neu gebaut+deployt.
- Nutzer probierte danach selbst: "klappt, leg jetzt VLAN mit eigenem
DHCP-Server an, aber ..." — parallel wieder ein Live-Test von mir
(VLAN→IP→Pool→DHCP-Server mit `disabled=no`, lief durch, aufgeräumt).
- "es erscheint keine Fehlermeldung" beim VLAN-Anlegen selbst (nach dem
Bug-10-Fix, vor dem nächsten) → Nutzer beschrieb genauen Ablauf
(Experte-Tab, VLAN-Interfaces, Name TEST-VLAN, ID 20, ether5,
`"Unerwartete Antwort vom Router: syntax error (line 1 column 30)"`).
Live mit der exakt gleichen generierten Befehlszeile reproduziert:
`disabled=false` → derselbe Fehler; `disabled=no` → Erfolg. Bug 11:
RouterOS-CLI akzeptiert nur `yes`/`no`, nie `true`/`false` — Schema-
Defaults waren aber durchgängig als `"true"/"false"` geschrieben (23×
falsch). Fix in `ExpertViewModel.pendingCommand` (normalisiert jeden
Bool-Wert vor dem Senden) plus Katalog-Strings bereinigt. Release neu
gebaut+deployt — Nutzer bestätigte: "klappt".
- Nutzer testete darauf selbst weiter in der App: VLAN anlegen/zuweisen/
löschen funktionierte. Beim DHCP-Server-Zuweisen auf `ether5` kam
`"failure: server or relay with such interface already exists"`
kein neuer Bug, sondern derselbe bereits bekannte Fall (ether5 hatte
bereits `dhcp5` aus einer früheren Session). Nutzer wählte "Weg 1":
DHCP-Server aufs VLAN statt auf `ether5` — meldete dann: "TEST-VLAN
steht nicht in der Auswahl". Bug 13 gefunden: `.interfacePick` las aus
`ConnectionService.interfaces`, einmalig beim Verbinden befüllt, nie
danach aktualisiert — anders als die neueren `.menuItemPick`-Felder.
Fix: neues `ExpertViewModel.liveInterfaceNames`, lädt bei jedem
Menü-Öffnen frisch via `/interface print terse`; die stale
`availableInterfaces`-Parameter-Durchreichung komplett entfernt.
Release neu gebaut+deployt.
- Nutzer: "super, das hat funktioniert." — VLAN erschien direkt in der
DHCP-Server-Interface-Auswahl, ohne erneutes Verbinden.
- "alles nochmal speichern" → dieser Eintrag, `HANDOFF.md` (Bug 1113,
aktualisierte M10-Zusammenfassung, Milestones, Nächste-Schritte) und
Memory aktualisiert.
## Nachtrag: Sicherheits-Angleichung + Dauer-Editor
- "die änderungen, welche ich im expert-Modus mache, werden diese sofort
geschrieben, oder ist eine Bestätigung erforderlich? wenn eine
bestätigung erforderlich, vermisse ich den Button dafür." → Antwort:
sofort, kein Bestätigungsschritt für Anlegen/Ändern (nur Löschen hatte
einen Dialog) — wich vom Wizard ab (Übersicht + Pflicht-Backup vor
"Jetzt anwenden"). Nutzer: "ja, beides einbauen." → Bestätigungsdialog
vor Anlegen/Ändern ergänzt (zeigt den exakten Befehl), plus
`ConnectionService.hasExpertToolBackedUpThisSession` +
`ExpertViewModel.ensureSessionBackup()`: automatisches Backup vor dem
ersten Schreibvorgang je Verbindung, nicht vor jeder einzelnen Änderung.
Build+Tests grün, Release neu gebaut+deployt.
- "in welche zeit (sekunden, Minuten oder Stunden wird die Lease-Zeit
angegeben? das war beim anlegen des DHCP-Server nicht deutlich." — live
geprüft statt geraten: RouterOS-Zeitwerte sind Zahl+Einheit
(s/m/h/d/w, kombinierbar wie `1d12h30m`), eine reine Zahl gilt als
Sekunden (`90` → intern `1m30s`). Tooltip entsprechend präzisiert,
Build+Tests grün.
- "kannst du mir dazu ein sinnvoll gestaltetes Auswahlfenster erzeugen?
ein Tooltip wäre sehr hilfreich" → neuer Feldtyp
`RouterOSFieldSchema.Kind.duration` + `DurationFieldEditor` (vier
Stepper: Tage/Std/Min/Sek, parst bestehende Werte per Regex/Bare-Zahl
beim Öffnen, schreibt die RouterOS-Suffix-Form zurück), angewendet auf
DHCP-Server "Lease-Zeit" und Adress-Listen "Ablaufzeit". Build+Tests
grün, Release neu gebaut+deployt.
- Nutzer: "ok, funktioniert, alles nochmal speichern (Handoff, Chatlog,
Memory) und dann schluß für heute, danke für die coole session." →
dieser Eintrag, `HANDOFF.md` (dritter/vierter Nachtrag, Milestones,
Nächste-Schritte inkl. Hinweis: `test-vlan`/`testpool`/`testdhcp` sind
echte Nutzer-Konfiguration, kein Test-Überbleibsel) und Memory
aktualisiert. Sitzung beendet.
## Stand am Ende dieser Session (2026-09-14)
M9 (Einfach/Experte-Modus) und M10 (Experte-Tab: generischer Motor +
kuratierte Firewall/Interfaces/IP/VPN/WLAN/Queues/System/Werkzeuge-
Schemas) gebaut und **live in der App vom Nutzer selbst bestätigt**
(VLAN anlegen, DHCP-Server mit Adress-Pool zuweisen, löschen) — nicht mehr
nur per SSH nachgestellt wie im ersten Test-Durchgang. Dabei sieben reale
Bugs gefunden und gefixt (Bug 713), jeder Fund mit einem Release-Rebuild
+ Deploy gefolgt. Bug 10 (RouterOS-SSH-Exit-Code immer 0, Fehler wurden
app-weit verschluckt) ist der wichtigste Fund der Session. Danach zwei
Nutzerwünsche ergänzt: Bestätigungsdialog + Auto-Backup vor dem ersten
Experte-Tab-Schreibvorgang (Angleichung an den Wizard), und ein
Dauer-Editor (Tage/Std/Min/Sek) für Lease-/Ablaufzeit-Felder statt
Freitext. Release-Build unter `/Applications/RouterOS Assistant.app` ist
auf aktuellem Stand, noch nicht committed. Offen: M9s Modusumschalter
selbst noch nicht manuell durchgeklickt, WLAN/Bonding/PPPoE-Client-Schemas
ungetestet (kein WLAN-Chip / riskant), einige IP-Schreibpfade nur lesend
geprüft, `dhcp5`/`pool5` auf `ether5` als Test-Überbleibsel noch zu
klären, Dauer-Editor könnte auf weitere Zeitfelder ausgeweitet werden,
plus alle bereits vorher offenen Punkte (M7-Rest, M8-Hardware-Test,
Firewall-WAN-Port-Recheck).