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:
+305
-9
@@ -6,8 +6,25 @@ teilweise gegen zwei echte physische Mikrotik-Testgeräte verifiziert
|
||||
kritischer Parser-Bug gefunden und gefixt, siehe unten). Danach noch
|
||||
mehrere Nutzer-Wünsche umgesetzt: Tooltips, wählbarer Backup-Ordner,
|
||||
Schnell-Backup im Verbinden-Tab, "Werkseinstellungen wiederherstellen",
|
||||
eigenes App-Icon. Release-Build liegt unter
|
||||
`/Applications/RouterOS Assistant.app`.
|
||||
eigenes App-Icon.
|
||||
|
||||
Neu in dieser Session: Einrichten-Wizard hat jetzt einen Einfach/Experte-
|
||||
Modusschalter (M9), und ein komplett neuer "Experte"-Tab (M10) gibt
|
||||
Formularzugriff auf einen großen, aber bewusst kuratierten Ausschnitt von
|
||||
RouterOS (Firewall/NAT/Mangle/Raw/Adress-Listen mit vollen Tooltips,
|
||||
plus Interfaces/IP/VPN/WLAN/Queues/System/Werkzeuge, plus ein "eigener
|
||||
Menüpfad"-Feld für alles, was nicht kuratiert ist). Live gegen den
|
||||
hEX-Testrouter (RouterOS 7.24.2) verifiziert — erst per direktem SSH,
|
||||
dann zusätzlich vom Nutzer selbst in der laufenden App (VLAN anlegen,
|
||||
DHCP-Server mit Adress-Pool zuweisen, löschen) — dabei **sieben** echte
|
||||
Bugs gefunden und gefixt (Bug 7–13 unten, nach jedem Fund Release neu
|
||||
gebaut und deployt). **Bug 10 ist der wichtigste Fund dieser Session:**
|
||||
RouterOS' SSH-CLI gibt bei fehlgeschlagenen Befehlen trotzdem Exit-Code 0
|
||||
zurück — betraf `apply()` app-weit, nicht nur den Experte-Tab (siehe
|
||||
unten). Release-Build unter `/Applications/RouterOS Assistant.app` ist
|
||||
auf aktuellem Arbeitsstand (alle M9/M10-Änderungen + alle Bugfixes
|
||||
deployt und vom Nutzer bestätigt) — **noch nicht committed** (siehe
|
||||
`git status`), letzter Commit ist weiterhin `97fc216`.
|
||||
|
||||
## Ziel
|
||||
|
||||
@@ -57,25 +74,29 @@ RouterOSAssistant/
|
||||
App/RouterOSAssistantApp.swift — 3 Tabs, teilen sich EINE ConnectionService-Instanz
|
||||
Core/
|
||||
Models/
|
||||
RouterOSCommand.swift — eine Änderung, zwei Operationen (.add/.set), zwei Renderer (CLI-Zeile / REST-JSON)
|
||||
RouterOSCommand.swift — eine Änderung, drei Operationen (.add/.set/.remove), zwei Renderer (CLI-Zeile / REST-JSON)
|
||||
WanConfig.swift, LanDhcpConfig.swift, VlanEntry.swift, WifiNetworkConfig.swift, FirewallConfig.swift — bauen je RouterOSCommand-Listen
|
||||
DhcpServerCommandBuilder.swift — geteilte "Adresse+Pool+Server+Netzwerk"-Logik (LAN + VLAN)
|
||||
RouterOSModels.swift — Credentials, DeviceInfo, Interface, RouterOSError
|
||||
RouterOSMenuItem.swift — generisches Item (id + [String:String] fields) für JEDEN RouterOS-Menüpfad (M10)
|
||||
RouterOSSchema.swift — RouterOSFieldSchema/RouterOSMenuSchema/RouterOSMenuCategory: kuratiertes Formular-Schema fürs Experte-Tool (M10)
|
||||
RouterOSSchemaCatalog.swift — die eigentliche Menü-Liste: Firewall-Familie voll kuratiert, Rest teils kuratiert/teils generisch (M10)
|
||||
Networking/
|
||||
RouterOSTransport.swift — Protocol: connect/fetchDeviceInfo/fetchInterfaces/fetchFirewallRuleCounts/apply/disconnect
|
||||
RestTransport.swift — REST-API (RouterOS ≥7.1), Zertifikats-TOFU, .set via GET+PATCH (findItemID)
|
||||
SSHTransport.swift — SSH-Fallback via Citadel, CLI-Text-Parsing, resetToFactoryDefaults(), eigene Hostkey-TOFU
|
||||
RouterOSCliParser.swift — parst `/system resource print` und `/interface print terse`
|
||||
RouterOSTransport.swift — Protocol: connect/fetchDeviceInfo/fetchInterfaces/fetchFirewallRuleCounts/fetchMenuItems/apply/disconnect
|
||||
RestTransport.swift — REST-API (RouterOS ≥7.1), Zertifikats-TOFU, .set via GET+PATCH (findItemID), .remove via GET+DELETE, fetchMenuItems (Array- oder Singleton-Objekt)
|
||||
SSHTransport.swift — SSH-Fallback via Citadel, CLI-Text-Parsing, resetToFactoryDefaults(), eigene Hostkey-TOFU, fetchMenuItems (generisch, inkl. Singleton-Fallback)
|
||||
RouterOSCliParser.swift — parst `/system resource print`, `/interface print terse`, und generisch jeden Menüpfad (parseGenericItems/parseSingletonItem, M10)
|
||||
CertificateTrustStore.swift / CertificateFingerprint.swift — TOFU für REST-Zertifikate
|
||||
SSHHostKeyTrustStore.swift / SSHHostKeyFingerprint.swift — TOFU für SSH-Hostkeys (M7)
|
||||
Services/
|
||||
ConnectionService.swift — zentraler App-State: REST-zuerst-SSH-Fallback, hält credentials/interfaces/deviceInfo
|
||||
ConnectionService.swift — zentraler App-State: REST-zuerst-SSH-Fallback, hält credentials/interfaces/deviceInfo, plus generisches fetchMenuItems
|
||||
BackupService.swift — Config-Export (`/export terse`) über eigene SSH-Verbindung, wählbarer Zielordner
|
||||
FactoryResetService.swift — /system reset-configuration über eigene SSH-Verbindung ("Gefahrenzone")
|
||||
KeychainService.swift — Passwort-Speicherung
|
||||
Features/
|
||||
Wizard/Steps/Connect/ — Verbinden-Tab (inkl. Schnell-Backup-Button nach erfolgreicher Verbindung)
|
||||
Wizard/Steps/Setup/ — Einrichten-Tab: Wan → Lan → Vlan → Wifi → Firewall → Review/Apply
|
||||
Wizard/Steps/Setup/ — Einrichten-Tab: Mode → Wan → Lan → (Vlan nur Experte) → Wifi → Firewall → Review/Apply
|
||||
Expert/ — Experte-Tab (M10): ExpertView (Kategorie-/Menüliste + "eigener Pfad"), ExpertViewModel, ExpertMenuDetailView (Item-Liste + Add/Edit-Sheet)
|
||||
Backup/ — Sicherungen-Tab (Ordner wählen, Gefahrenzone: Werkseinstellungen wiederherstellen)
|
||||
Resources/Assets.xcassets/AppIcon.appiconset/ — App-Icon "Signal Router" (16px–1024px)
|
||||
RouterOSAssistantTests/ — reine Unit-Tests (Command-Builder, CLI-Parser, Fallback-Logik via Mock-Transport)
|
||||
@@ -139,11 +160,112 @@ erreichen (siehe Bug 1 unten).
|
||||
Auswahllisten gefiltert. Regressionstest mit echten `\r\n`-getrennten
|
||||
hEX-Daten in `RouterOSCliParserTests`.
|
||||
|
||||
7. **`/ip service`: Feld heißt `available-from`, nicht `address`** — beim
|
||||
Kuratieren des Experte-Schemas geraten statt geprüft. Live gegen den
|
||||
hEX bestätigt: `/ip service print` zeigt tatsächlich `available-from=`;
|
||||
ein `set ... address=...` hätte den Zugriffsfilter stillschweigend
|
||||
nicht gesetzt. Schema korrigiert (`RouterOSSchemaCatalog.swift`).
|
||||
8. **RouterOS 7.24.2 zeigt `.id` gar nicht in `print terse`, und
|
||||
Singleton-Menüs verweigern `terse` komplett** — Annahme beim Bau des
|
||||
generischen Experte-Motors (M10) war, `.id=*N` sei Teil jeder
|
||||
`print terse`-Zeile (wie bei REST-JSON). Live-Test zeigte: RouterOS
|
||||
7.24.2 liefert dort gar kein `.id`-Feld; Menüs mit genau einem Eintrag
|
||||
statt einer Liste (`/ip dns`, `/system identity`, `/system clock`,
|
||||
`/system ntp client`, `/tool e-mail`) lehnen `terse` sogar komplett ab
|
||||
(`"bad parameter terse"`). Fix: `:put [<Menüpfad> find]` liefert die
|
||||
echten internen IDs (z.B. `*C;*1;*2`) — live bestätigt, dass die
|
||||
Reihenfolge exakt der von `print terse` entspricht, damit per Position
|
||||
zuordenbar. Für Singleton-Menüs neuer `RouterOSMenuSchema.isSingleton`-
|
||||
Schalter: Fetch fällt auf normales `print` (Doppelpunkt-Format,
|
||||
`parseSingletonItem`) zurück, `.set` läuft ohne `[find ...]` direkt
|
||||
(`matchField: ""` als Sentinel in `RouterOSCommand`/beiden Transports).
|
||||
Beides live gegen `/system identity` durchgespielt (Name testweise
|
||||
geändert, Fehlertext exakt geprüft, zurückgesetzt).
|
||||
9. **Cross-Referenz-Felder (z.B. DHCP-Server → Adress-Pool) waren reiner
|
||||
Freitext** — Nutzer meldete: "kann den vorher angelegten Adress-Pool
|
||||
nicht in der Auswahl sehen". Betraf jedes Feld, das den Namen eines
|
||||
Eintrags aus einem *anderen* Menü referenziert (DHCP-Server→Pool,
|
||||
PPP-Benutzer→Profil, Scheduler→Skript, Firewall-Filter→Adress-Liste,
|
||||
WireGuard-Peer→Interface) — alle als `.text` statt als Auswahl gebaut.
|
||||
Fix: neuer Feldtyp `RouterOSFieldSchema.Kind.menuItemPick(menuPath:
|
||||
restPath:valueField:)`, lädt beim Öffnen eines Menüs live die
|
||||
existierenden Namen aus dem referenzierten Menü
|
||||
(`ExpertViewModel.loadCrossReferenceOptions`) und zeigt sie als Picker.
|
||||
Auf alle fünf betroffenen Felder angewendet.
|
||||
10. **Kritisch, app-weit: RouterOS' SSH-CLI gibt bei fehlgeschlagenen
|
||||
Befehlen Exit-Code 0 zurück** — Nutzer meldete: DHCP-Server-Anlage
|
||||
zeigte keine Fehlermeldung, wurde aber auch nicht angelegt. Live
|
||||
reproduziert: `/ip dhcp-server add ...` auf einem Interface mit
|
||||
bereits bestehendem Server lieferte `"failure: server or relay with
|
||||
such interface already exists"` **und Exit-Status 0**; ein ungültiger
|
||||
`action=`-Wert lieferte `"syntax error (...)"`, ebenfalls Exit-Status
|
||||
0 (per `expect`-Skript mit `catch wait result` geprüft). `SSHTransport.
|
||||
apply()` warf bisher nur bei einem von Citadel gemeldeten
|
||||
Nicht-Null-Exit-Code — also nie. **Betraf jeden `.apply()`-Aufruf über
|
||||
SSH app-weit**, nicht nur den Experte-Tab: der komplette Einrichten-
|
||||
Wizard (WAN/LAN/VLAN/Firewall) lief bei jedem SSH-Schreibvorgang mit
|
||||
demselben blinden Fleck, seit M3. Fix: `apply()` behandelt jede
|
||||
nicht-leere Ausgabe eines add/set/remove-Befehls als Fehler — laut
|
||||
allen in dieser Session live getesteten Befehlsfamilien (15+) sind
|
||||
erfolgreiche mutierende Befehle immer still. Nach dem Fix live end-to-
|
||||
end bestätigt: komplette Kette VLAN→IP-Adresse→Pool→DHCP-Server→
|
||||
DHCP-Netzwerk auf einem freien Interface angelegt, lief fehlerfrei
|
||||
durch, danach vollständig wieder entfernt.
|
||||
11. **Bool-Felder im Experte-Schema als `"true"/"false"` statt `"yes"/"no"`
|
||||
geschrieben** — Nutzer meldete nach Bug-10-Fix: VLAN-Anlage zeigte
|
||||
jetzt `"Unerwartete Antwort vom Router: syntax error (line 1 column
|
||||
30)"`. Live reproduziert mit der exakt von der App erzeugten
|
||||
Befehlszeile (`disabled=false`) — identischer Fehler; mit
|
||||
`disabled=no` lief es durch. RouterOS' CLI akzeptiert nur `yes`/`no`
|
||||
für Bool-Parameter, nicht `true`/`false`. Betraf praktisch jedes
|
||||
kuratierte Schema (23× `"false"`, 4× `"true"` als `defaultValue`).
|
||||
Fix zweigleisig: `ExpertViewModel.pendingCommand` normalisiert jeden
|
||||
`.bool`-Feldwert vor dem Senden auf `yes`/`no` (Schutz unabhängig von
|
||||
der Quelle), zusätzlich Katalog-Strings selbst bereinigt. Live erneut
|
||||
end-to-end bestätigt (VLAN→IP→Pool→DHCP-Server mit `disabled=no`).
|
||||
12. **Lösch-Buttons fehlten komplett im Experte-Tab** — Nutzer: "mir
|
||||
fehlen komplett die Löschen-Buttons". Ursache: `.swipeActions(...)`
|
||||
ist eine iOS/iPadOS-Wischgeste ohne Entsprechung auf macOS-Listen —
|
||||
dort erscheint schlicht nichts, unabhängig vom Code. Fix: sichtbarer
|
||||
Papierkorb-Icon-Button je Zeile statt Wisch-Geste (nur bei
|
||||
Nicht-Singleton-Menüs, wo Löschen überhaupt Sinn ergibt). Lösch-Pfad
|
||||
(ID-Ermittlung + `remove [find .id=...]`) live gegen das vom Nutzer
|
||||
selbst angelegte VLAN nachvollzogen, funktioniert.
|
||||
13. **Interface-Auswahl (`.interfacePick`) war einmalig beim Verbinden
|
||||
eingefroren** — Nutzer legte ein VLAN an, danach fehlte es in der
|
||||
Interface-Auswahl beim Anlegen eines DHCP-Servers. Ursache:
|
||||
`.interfacePick` las aus `ConnectionService.interfaces`, nur einmal
|
||||
bei `finishConnecting()` befüllt, nie danach aktualisiert — anders als
|
||||
die neueren `.menuItemPick`-Felder (Pool/Profil/Skript), die bei
|
||||
jedem Menü-Öffnen frisch laden. Fix: neues
|
||||
`ExpertViewModel.liveInterfaceNames`, per `/interface print terse` bei
|
||||
jedem `reloadItems()` aktualisiert; `availableInterfaces`-Parameter-
|
||||
Durchreichung (`ExpertView`→`ExpertMenuDetailView`→
|
||||
`ExpertItemEditView`) komplett entfernt, da überflüssig. Danach vom
|
||||
Nutzer selbst in der App bestätigt: neu angelegtes VLAN erscheint
|
||||
sofort in der DHCP-Server-Interface-Auswahl.
|
||||
|
||||
**Lehren:** Citadel/NIOSSH-Fehler immer mit `String(describing:)` loggen,
|
||||
nie `.localizedDescription`. Jede View, die ein ObservableObject aus einem
|
||||
ViewModel liest, muss es selbst separat als `@ObservedObject` halten.
|
||||
Zeilen-Splitting bei SSH-Ausgaben grundsätzlich mit `\.isNewline` statt
|
||||
festem `"\n"`, da sich das je nach Gerät/Version unterscheiden kann.
|
||||
Bei generischem RouterOS-Tooling (M10) nichts über CLI-Ausgabeformate
|
||||
annehmen, was nicht live geprüft ist — `.id`-Verhalten und `terse`-Support
|
||||
unterscheiden sich zwischen Menütypen und RouterOS-Versionen. **RouterOS'
|
||||
SSH-Exit-Code ist kein verlässliches Erfolgssignal** — Ausgabetext ist die
|
||||
einzige verlässliche Fehlerquelle über diesen Transport (Bug 10); REST
|
||||
ist davon nicht betroffen (prüft HTTP-Statuscodes korrekt). RouterOS'
|
||||
CLI will `yes`/`no` für Bools, nie `true`/`false` (Bug 11) — an einer
|
||||
einzigen Stelle normalisieren (`pendingCommand`) statt an jedem
|
||||
Schema-Eintrag hoffen, es richtig geschrieben zu haben. SwiftUI-
|
||||
Interaktionsmuster nicht plattform-blind übernehmen — `.swipeActions`
|
||||
sieht in der Doku harmlos aus, ist aber faktisch iOS/iPadOS-only (Bug 12).
|
||||
Jeder Zustand, der sich während der Nutzung ändern kann (Interface-Liste
|
||||
nach Anlegen eines VLANs), gehört live nachgeladen, nicht einmalig beim
|
||||
Verbinden gecacht (Bug 13) — dasselbe Prinzip wie `crossReferenceOptions`
|
||||
für Pool/Profil/Skript, nur nicht von Anfang an konsequent auf alle
|
||||
Auswahllisten angewendet.
|
||||
|
||||
## `xcodebuild test` hängt — Gatekeeper, kein Code-Bug
|
||||
|
||||
@@ -162,6 +284,15 @@ wiederholen.
|
||||
|
||||
## Bekannte Einschränkungen (bewusst, nicht vergessen)
|
||||
|
||||
- **Backup-Wiederherstellung fehlt komplett** — Nutzer wies explizit
|
||||
darauf hin (2026-09-14): `BackupService` kann Backups nur erzeugen
|
||||
(`createBackup`) und auflisten (`listBackups`), es gibt **keine**
|
||||
Funktion, ein gespeichertes `.rsc`-Backup zurück auf den Router zu
|
||||
spielen. Einzige verwandte Funktion ist "Werkseinstellungen
|
||||
wiederherstellen" (`FactoryResetService`, Gefahrenzone im
|
||||
Sicherungen-Tab) — das ist RouterOS' eigener Werksreset, kein Zurück-
|
||||
spielen einer konkreten Sicherung. Noch nicht umgesetzt, für später
|
||||
vorgemerkt (siehe Nächste Schritte).
|
||||
- **REST-Pfad ungetestet für Schreibvorgänge** — auf beiden bisherigen
|
||||
Testgeräten war `www-ssl` (Port 443) aus, jeder Schreibtest lief über
|
||||
SSH. Der REST-`apply()`-Pfad (`POST`/`PATCH`, `findItemID` für `.set`)
|
||||
@@ -187,6 +318,20 @@ wiederholen.
|
||||
- ~~SSH-Hostkey-TOFU ungetestet~~ — **bestätigt gegen echte Hardware**:
|
||||
erste Verbindung zeigte den "Unbekannter SSH-Schlüssel"-Dialog, nach
|
||||
Bestätigen + Trennen + erneutem Verbinden lief es ohne Rückfrage durch.
|
||||
- **Experte-Tool (M10): mehrere kuratierte Bereiche noch nicht gegen
|
||||
Hardware bestätigt** — WLAN (Legacy- und neuer wifiwave2-Treiber:
|
||||
Testgerät hat keinen WLAN-Chip), Bonding und PPPoE-Client (beide riskant
|
||||
für die eigene Erreichbarkeit/brauchen echte ISP-Zugangsdaten) nur gegen
|
||||
RouterOS-Dokumentation kuratiert, nicht live geprüft. `/ip address`,
|
||||
`/ip dhcp-client`, `/ip dns`, `/ip service` nur lesend geprüft (Feldnamen
|
||||
bestätigt), keine Schreibtests — Risiko, sich selbst auszusperren
|
||||
(SSH/REST-Dienst) bzw. die WAN-Verbindung zu kappen.
|
||||
- **Experte-Tool: einige RouterOS-Bereiche bewusst nur generisch, nicht
|
||||
kuratiert** — Hotspot, Logging (beide mehrteilig, kein flaches Schema),
|
||||
CAPsMAN, L2TP-/OpenVPN-Server, OSPF/BGP-Routing. Grund: keine verifizierte
|
||||
Quelle für die genauen Feldnamen, lieber generischer Schlüssel/Wert-
|
||||
Zugriff als geratene Felder (siehe Bug 7 oben, warum das eine berechtigte
|
||||
Sorge ist).
|
||||
|
||||
## M8: Mehrere LAN-Interfaces + Netzwerk-Isolation
|
||||
|
||||
@@ -210,6 +355,114 @@ Netzwerk gegen nicht-isoliertes, gegenseitige Isolation, keine Isolation).
|
||||
**Noch nicht gegen echte Hardware getestet** — bräuchte zwei getrennte
|
||||
Testnetze am selben Router, um die Drop-Regeln praktisch zu bestätigen.
|
||||
|
||||
## M9: Einfach/Experte-Modus im Einrichten-Wizard
|
||||
|
||||
Nutzerwunsch: zwei Modi statt einem Wizard-Durchlauf für alle. Neuer
|
||||
erster Schritt `SetupStep.mode` (`ModeStepView`, Segmented Picker).
|
||||
|
||||
- **Einfach**: WAN → LAN (nur ein Netzwerk, kein Hinzufügen/Entfernen,
|
||||
kein Isolations-Toggle) → WLAN → Firewall (Grundschutz fest an, kein
|
||||
Toggle) → Review. VLAN-Schritt wird komplett übersprungen.
|
||||
- **Experte**: unveränderter voller Flow (Multi-LAN, VLAN, Isolation,
|
||||
Firewall-Toggle) — das, was vorher der einzige Wizard-Pfad war.
|
||||
|
||||
Beim Umschalten auf Einfach werden evtl. im Expertenmodus gesetzte Werte
|
||||
zurückgesetzt (`SetupViewModel.applySimpleModeConstraints`). Navigation
|
||||
(`goNext`/`goBack`) von linearem `SetupStep.rawValue+1` auf expliziten
|
||||
`switch` umgebaut (nötig wegen bedingtem VLAN-Skip). Nur gegen Unit-Tests
|
||||
+ Compile/Test-Build verifiziert, **nicht gegen echte Hardware** (der
|
||||
Live-Test dieser Session lief komplett über direktes SSH, nicht über die
|
||||
App-UI).
|
||||
|
||||
## M10: Experte-Tab — generischer RouterOS-Konfigurationszugriff
|
||||
|
||||
Nutzerwunsch: "Zugriff auf alle Funktionen, was RouterOS bietet ...
|
||||
alles was du findest, der komplette Umfang". RouterOS hat 300+ Menüs
|
||||
(siehe `/console inspect` / CLI-Referenz) — statt für jedes einzelne ein
|
||||
Swift-Modell zu bauen (unrealistisch), zweistufige Architektur:
|
||||
|
||||
1. **Generischer Motor** (deckt technisch jeden Menüpfad ab):
|
||||
`RouterOSMenuItem` + `RouterOSCliParser.parseGenericItems`/
|
||||
`parseSingletonItem`, `RouterOSCommand.remove` (neu, neben add/set),
|
||||
`ConnectionService.fetchMenuItems` + Transport-Implementierungen.
|
||||
Im UI: freies "eigener Menüpfad"-Eingabefeld — jeder RouterOS-Pfad ist
|
||||
erreichbar, auch ohne kuratiertes Schema, dann als rohes
|
||||
Schlüssel/Wert-Formular.
|
||||
2. **Kuratierte Schemas** (`RouterOSSchemaCatalog`) mit echten
|
||||
Formularfeldern, Tooltips, Erklärtext und Warnhinweisen: die komplette
|
||||
Firewall-Familie (Filter/NAT/Mangle/Raw/Adress-Listen — der explizit
|
||||
genannte Schwerpunkt), dazu Interfaces (Bridge, VLAN, WireGuard+Peers,
|
||||
PPPoE-Client, Bonding), IP (Adressen, Pools, DHCP-Server+Netzwerk,
|
||||
DHCP-Client, DNS, Verwaltungsdienste, Routen), VPN (PPP-Secret/Profile),
|
||||
WLAN (Legacy + neuer wifiwave2-Treiber + Sicherheitsprofile), Queues
|
||||
(Simple/Tree), System (Identity/Clock/NTP/Scheduler/Skripte/Nutzer),
|
||||
Werkzeuge (Netwatch/E-Mail). Bewusst nicht kuratiert (siehe oben):
|
||||
Hotspot, Logging, CAPsMAN, L2TP-/OVPN-Server, OSPF/BGP.
|
||||
|
||||
**Live gegen den hEX-Testrouter verifiziert** (Add→Print→Set→Remove-
|
||||
Zyklus je Familie, Router danach nachweislich unverändert — Config-Export
|
||||
vorher/nachher byte-identisch bis auf Zeitstempel): Firewall
|
||||
Filter/NAT/Mangle/Raw/Adress-Listen, VLAN, WireGuard+Peers, IP-Pool,
|
||||
DHCP-Server+Netzwerk, statische Route, PPP-Secret/Profile, Queue Simple,
|
||||
Scheduler+Skript, Netwatch, sowie der neue Singleton-Pfad
|
||||
(`/system identity`). Dabei zwei Bugs gefunden und gefixt, siehe Bug 7/8
|
||||
oben. **Nicht** gegen Hardware getestet: WLAN (kein Chip im Testgerät),
|
||||
Bonding, PPPoE-Client (beide riskant/brauchen echte Zugangsdaten),
|
||||
Schreibzugriff auf `/ip address`/`/ip dhcp-client`/`/ip dns`/
|
||||
`/ip service` (nur lesend geprüft, Risiko Selbstaussperrung/WAN-Ausfall).
|
||||
|
||||
**Nachtrag (Nutzer-Feedback-Runde, gleiche Session):** Nutzer meldete zwei
|
||||
reale Probleme beim gedanklichen/App-Testen des DHCP-Server-Formulars —
|
||||
Bug 9 (Adress-Pool-Feld ohne Auswahl) und Bug 10 (fehlgeschlagenes Anlegen
|
||||
ohne jede Fehlermeldung). Beide gefunden und gefixt (siehe oben). Bug 10s
|
||||
Fix wurde erneut end-to-end live bestätigt: komplette Kette
|
||||
VLAN → IP-Adresse → Pool → DHCP-Server → DHCP-Netzwerk auf einem freien
|
||||
Interface (statt des zuvor kollidierenden `ether5`) angelegt, kein
|
||||
Fehlertext (weil tatsächlich erfolgreich), anschließend vollständig
|
||||
wieder entfernt.
|
||||
|
||||
**Zweiter Nachtrag — jetzt tatsächlich durch die App-UI getestet (Nutzer
|
||||
selbst, gleiche Session):** Nutzer legte VLAN + DHCP-Server über den
|
||||
Experte-Tab live an, fand dabei drei weitere reale Bugs (11: yes/no,
|
||||
12: fehlende Lösch-Buttons, 13: eingefrorene Interface-Auswahl, siehe
|
||||
oben) — alle gefunden, gefixt, nach jedem Fix Release neu gebaut und
|
||||
deployt, vom Nutzer direkt in der App erneut getestet. Damit ist die
|
||||
SwiftUI-Oberfläche des Experte-Tabs (VLAN anlegen, einem DHCP-Server
|
||||
zuweisen, Adress-Pool wählen, löschen) **erstmals tatsächlich manuell
|
||||
durchgeklickt und vom Nutzer als funktionierend bestätigt** — nicht mehr
|
||||
nur die zugrundeliegende RouterOS-Syntax per SSH. Bestätigt: RouterOS
|
||||
erlaubt nur einen DHCP-Server pro Interface — der Versuch, ihn direkt auf
|
||||
`ether5` zu setzen, scheiterte zurecht (dort hängt bereits `dhcp5` aus
|
||||
einer früheren Session), auf dem VLAN-Interface funktioniert es.
|
||||
|
||||
**Dritter Nachtrag — Sicherheits-Angleichung ans übrige App-Verhalten:**
|
||||
Nutzer fragte, ob Experte-Tab-Änderungen sofort geschrieben werden oder
|
||||
eine Bestätigung braucht — Antwort war "sofort, kein eigener
|
||||
Bestätigungs-Button" (nur Löschen hatte einen Dialog). Das wich vom
|
||||
Einrichten-Wizard ab (Übersicht + Pflicht-Backup vor "Jetzt anwenden").
|
||||
Auf Wunsch angeglichen:
|
||||
- **Bestätigungsdialog vor Anlegen/Ändern**: "Anlegen"/"Speichern" öffnet
|
||||
jetzt zuerst einen `.confirmationDialog` mit dem exakten Befehl, erst
|
||||
ein zweiter Klick führt ihn aus (`ExpertMenuDetailView`).
|
||||
- **Auto-Backup einmal pro Verbindung**: `ConnectionService.
|
||||
hasExpertToolBackedUpThisSession` (zurückgesetzt bei `disconnect()`),
|
||||
`ExpertViewModel.ensureSessionBackup()` zieht vor dem allerersten
|
||||
Schreibvorgang im Experte-Tab automatisch ein Backup (wie der Wizard),
|
||||
aber nur einmal pro Sitzung, nicht vor jeder einzelnen Änderung (ein
|
||||
Experte-Tab-Durchgang sind oft viele kleine Edits hintereinander).
|
||||
|
||||
**Vierter Nachtrag — Dauer-Editor:** Nutzer fragte, in welcher Einheit
|
||||
die DHCP-Server-Lease-Zeit angegeben wird. Live geprüft: RouterOS-
|
||||
Zeitwerte sind Zahl+Einheit (`s`/`m`/`h`/`d`/`w`, kombinierbar wie
|
||||
`1d12h30m`), eine bare Zahl gilt als Sekunden (bestätigt: `90` → intern
|
||||
`1m30s`). Nutzerwunsch danach: "ein sinnvoll gestaltetes Auswahlfenster
|
||||
... ein Tooltip wäre hilfreich" statt nur Tooltip-Text. Neuer Feldtyp
|
||||
`RouterOSFieldSchema.Kind.duration` + `DurationFieldEditor` (vier
|
||||
Stepper: Tage/Std/Min/Sek, parst bestehende Werte beim Öffnen, schreibt
|
||||
beim Ändern die RouterOS-Suffix-Form zurück) — angewendet auf DHCP-Server
|
||||
"Lease-Zeit" und Adress-Listen "Ablaufzeit". Nutzer bestätigte danach:
|
||||
"funktioniert".
|
||||
|
||||
## Stand der Milestones
|
||||
|
||||
- ✅ M1–M4: Projektgerüst, Connect, Backup, WAN/LAN/DHCP, VLAN — gegen
|
||||
@@ -232,6 +485,22 @@ Testnetze am selben Router, um die Drop-Regeln praktisch zu bestätigen.
|
||||
- 🔶 M8: Mehrere LAN-Interfaces mit eigenem DHCP + Netzwerk-Isolation
|
||||
(eigene Firewall-Regeln pro LAN/VLAN) — gebaut, nur Unit-Test-verifiziert,
|
||||
noch nicht gegen echte Hardware getestet.
|
||||
- 🔶 M9: Einfach/Experte-Modus im Einrichten-Wizard — gebaut, Compile/
|
||||
Unit-Test-verifiziert. UI (Modusumschalter selbst) noch nicht manuell
|
||||
durchgeklickt — nur M10s Experte-Tab wurde das (siehe M10).
|
||||
- ✅ M10: Experte-Tab (generischer RouterOS-Zugriff + kuratierte Firewall-
|
||||
und weitere Schemas) — Kern-Logik **live gegen Hardware verifiziert**,
|
||||
UI (VLAN anlegen/löschen, DHCP-Server mit Adress-Pool zuweisen) **vom
|
||||
Nutzer selbst in der laufenden App bestätigt funktionierend** — sieben
|
||||
reale Bugs dabei gefunden und gefixt (Bug 7–13), danach zusätzlich
|
||||
Bestätigungsdialog vor Anlegen/Ändern + einmaliges Auto-Backup pro
|
||||
Sitzung (Angleichung an den Wizard) sowie ein Dauer-Editor (Tage/Std/
|
||||
Min/Sek statt Freitext) für Lease-/Ablaufzeit-Felder ergänzt, alles vom
|
||||
Nutzer bestätigt. Weiterhin ungetestet: WLAN (kein Chip im Testgerät),
|
||||
Bonding, PPPoE-Client (beide riskant/brauchen echte Zugangsdaten),
|
||||
Schreibzugriff auf `/ip address`/`/ip dhcp-client`/`/ip dns`/
|
||||
`/ip service` (Risiko Selbstaussperrung/
|
||||
WAN-Ausfall).
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
@@ -247,6 +516,33 @@ Testnetze am selben Router, um die Drop-Regeln praktisch zu bestätigen.
|
||||
isoliert, anwenden, per `/ip firewall filter print` kontrollieren, dass
|
||||
die Drop-Regeln greifen und der Rest (Internetzugriff, nicht-isolierte
|
||||
Netzwerke) unangetastet bleibt.
|
||||
5. M9 UI (Einfach/Experte-Modusumschalter im Einrichten-Tab selbst) noch
|
||||
manuell durchklicken — M10s Experte-Tab wurde bereits vom Nutzer
|
||||
bestätigt (siehe oben), der Moduswechsel im Wizard noch nicht.
|
||||
6. M10: WLAN-Schemas (an Gerät mit WLAN-Chip), Bonding, PPPoE-Client
|
||||
(mit echten oder Test-ISP-Zugangsdaten) noch gegen Hardware verifizieren.
|
||||
7. `dhcp5`/`pool5` auf `ether5` sind Test-Überbleibsel aus einer früheren
|
||||
Session — mit dem Nutzer klären, ob die noch gebraucht werden oder
|
||||
aufgeräumt werden können (aktuell blockieren sie `ether5` für einen
|
||||
neuen direkt-auf-dem-Port angelegten DHCP-Server).
|
||||
8. **Nicht anrühren:** `test-vlan` (VLAN-ID 20, ether5), `testpool`
|
||||
(192.168.90.10-250) und `testdhcp` (DHCP-Server auf `test-vlan`) sind
|
||||
**echte, vom Nutzer selbst über die App angelegte Konfiguration** aus
|
||||
dieser Session, keine Test-Artefakte zum Aufräumen.
|
||||
9. Optional, kleinere Politur: den neuen Dauer-Editor
|
||||
(`RouterOSFieldSchema.Kind.duration`) auch auf weitere Zeitwert-Felder
|
||||
anwenden, die bisher nur Text mit Beispiel-Tooltip sind — WireGuard-
|
||||
Peer "Keepalive", Scheduler "Intervall", Netwatch "Prüf-Intervall".
|
||||
10. **Backup-Wiederherstellung bauen** — vom Nutzer explizit gewünscht,
|
||||
noch nicht begonnen. Vermutlich: `BackupService` um eine
|
||||
`restoreBackup(_:for:)`-Funktion erweitern, die den Inhalt eines
|
||||
gewählten `.rsc`-Backups über SSH auf den Router einspielt (RouterOS
|
||||
kann `.rsc`-Skripte per `/import file-name=...` ausführen, dazu muss
|
||||
die Datei vorher aufs Gerät hochgeladen werden — Weg noch nicht
|
||||
verifiziert, vor dem Bauen live prüfen statt zu raten), plus ein
|
||||
"Wiederherstellen"-Button pro Eintrag im Sicherungen-Tab
|
||||
(`BackupListView`) mit Bestätigungsdialog (ähnlich der bestehenden
|
||||
Werksreset-Gefahrenzone).
|
||||
|
||||
Kein Gitea-Remote vorhanden — falls der Nutzer später eine Gitea-Instanz
|
||||
aufsetzt (z.B. selbst gehostet auf der vorhandenen OMV-NAS, siehe
|
||||
|
||||
Reference in New Issue
Block a user