# NetDiag — Diagnose-App (Android) Mobile Netzwerk-Diagnose-App. Erfasst vor Ort beim Kunden (Handy am WLAN oder USB-C→RJ45-Adapter) Geräte, Ports und Messungen und hängt die Protokolle ans Dolibarr-Modul `netdiag` an Kunde und Auftrag. ## Stack SvelteKit 2 · Svelte 5 · Tailwind 4 · Vite 7 · Capacitor 6 · SQLite-Offline ## Entwicklung (Browser) ```bash npm install npm run dev # http://localhost:5175 ``` Im Browser liefert ein **Mock** (`src/lib/scanner.ts`) Beispiel-Scandaten — die Oberfläche lässt sich ohne Gerät entwickeln. API-Aufrufe gehen über den Vite-Proxy an den Dolibarr-Testserver (`192.168.155.11`, siehe `vite.config.ts`). ## Android-Build ```bash npm run build npx cap add android # einmalig # android/ liegt komplett im Repo — cap sync kopiert nur die Web-Assets npx cap sync android npx cap open android ``` Release-APK über CI: Commit mit `[apk]` in der Message → Forgejo baut und lädt die APK in die Package Registry (`netdiag-apk`). Siehe `.forgejo/workflows/build.yml`. ## Architektur ``` src/lib/ api.ts JSON-API-Client (JWT, 401-Refresh, Timeout) auth.svelte.ts Anmelde-Status db.ts Offline-Speicher (SQLite nativ / localStorage Browser) sync.svelte.ts Sync-Queue -> Dolibarr (idempotent über clientUuid) scanner.ts Brücke zum nativen Plugin (+ Browser-Mock) protocols.ts Protokoll-Operationen (addMeasurement, upsertDevice, …) messfelder.ts Beschriftung der Ergebnisfelder — Gegenstück zur Whitelist im Dolibarr-Modul (siehe „Neues Tool") toolparams.ts Gedächtnis der zuletzt benutzten Werkzeug-Parameter stresstest.ts Auswertung des Dauertests (überlebt App-Wechsel) monitor.ts Auswertung der Geräte-Überwachung -> Verfügbarkeit wifi/ Kanalgraph-Geometrie, Kanalempfehlung, Bewertung, Demodaten overlay.svelte.ts Overlay-Stapel für den Hardware-Zurück-Knopf toast.svelte.ts kurze Rückmeldungen backButton.svelte.ts Hardware-Back (Single-Instance, KB #480/#549) updater.ts APK-Auto-Update-Prüfung (KB #363). Das Token geht als Authorization-Header mit, nicht in der Adresse. tools/ erweiterbare Tool-Plattform index.ts Registry — neues Tool hier eintragen netzwerk/ IP-Scan, Port, Ping, IP-Konflikt, SNMP, Traceroute, Stress internet/ Durchsatz-Test telefonie/ SIP-Erreichbarkeit über OPTIONS (sipcheck.ts) samt Bewertung in sip-bewertung.ts. Jede Statuszeile beweist eine antwortende Instanz — 401 heißt „erreichbar, will Zugangsdaten", nicht „tot". RTP-Sprachqualität bewusst NICHT: ohne aufgebautes Gespräch nicht ehrlich messbar. src/routes/ login/ auftraege/ kunden/ einstellungen/ protokoll/[id]/ Hauptseite mit Werkzeugen, Geräten, Messungen protokoll/[id]/stresstest/ monitor/ iptest/ wifi/ wifikanal/ Werkzeuge mit Live-Anzeige — eigene Seite statt Dialog, weil sie über Minuten/Stunden laufen android/ natives Android-Projekt inkl. Kotlin-Plugin (einzige Quelle) native-plugin/ nur noch Anleitung/Hinweise zum Plugin tools/ Prüfwerkzeuge ohne Gerät (siehe unten) ``` ## Prüfwerkzeuge (`tools/`, laufen ohne Handy) ```bash node tools/render-chart.mjs # rendert die echten Diagramm-Komponenten # nach .render/*.svg — ansehen, nicht annehmen node tools/pruefe-monitor.mjs # rechnet die Verfügbarkeits-Auswertung gegen # konstruierte Fälle mit Handwerten durch node tools/pruefe-kette.mjs # Internet-Kette: Fehlerglied, Anmeldeseite node tools/pruefe-dns.mjs # DNS: NXDOMAIN ist KEIN Ausfall node tools/pruefe-geraetediff.mjs # Geräte-Vergleich, alle Fälle OHNE MAC node tools/pruefe-geraeteaktionen.mjs # Sortierung nach Gerätetyp node tools/pruefe-serveradresse.mjs # http:// bei https-App abweisen node tools/pruefe-sip.mjs # SIP: 401/405 sind ERREICHBAR, kein Ausfall node tools/test-recommend.mjs # Kanalempfehlung ``` **Warum es diese Prüfer gibt:** Der Browser-Mock liefert bei Netzwerkwerkzeugen grundsätzlich den guten Fall — er gibt sogar jedem Gerät eine MAC-Adresse, die beim Kunden nie ankommt. Wer im Mock klickt, prüft den Mock. Deshalb liegt die Bewertungslogik jeweils in einer Datei **ohne Laufzeit-Import** (`*-bewertung.ts`, `geraete-diff.ts`, `serveradresse.ts`), die Node dank Type-Stripping direkt laden kann. Jeder dieser sechs Prüfer hat mindestens einen echten Fehler gefunden (Muster und Bilanz: KB #1091). `render-chart.mjs` gibt es, weil die erste Fassung der WLAN-Diagramme unbemerkt unlesbar in den Einsatz ging: der Emulator hat keine WLAN-Hardware, also war nie ein gefülltes Diagramm zu sehen. SVGs mit `rsvg-convert x.svg -o x.png` in ein ansehbares Bild wandeln. ## Neues Tool hinzufügen 1. Datei unter `src/lib/tools//.ts` anlegen, `Tool` implementieren. 2. In `src/lib/tools/index.ts` importieren und in `TOOLS` eintragen. 3. `quickRun: true` setzen, **wenn** das Werkzeug ohne Eingabe sinnvoll startet (kurzer Tap startet dann sofort, langes Halten öffnet die Optionen). Ausdrücklich je Werkzeug entscheiden — es gibt kein `required` an den Parametern, die Pflicht steht allein im `run()`-Rumpf. `portscan.ports` hat keinen Vorgabewert und ist trotzdem optional, `iperf.host` hat ebenfalls keinen und ist Pflicht. 4. **Jeden neuen Ergebnis-Schlüssel in BEIDE Feldtabellen eintragen:** - `src/lib/messfelder.ts` (App-Anzeige) - `netdiagKundenfelder()` in `dolibarr-modul/netdiag/lib/netdiag.lib.php` — das ist eine **harte Whitelist**: was dort fehlt, verschwindet im Kunden-PDF spurlos, übrig bleibt die nackte Ampel. Ebenso den Klarnamen des Werkzeugs in `netdiagToolName()`, sonst steht beim Kunden „[netzwerk] meintool". > Punkt 4 ist der Schritt, der hier schon **zweimal** vergessen bzw. geraten > wurde. Beim ersten Mal wurde die Whitelist gegen selbst erfundene Testdaten > gebaut, beim zweiten Mal stand `'typ'` darin statt des real gelieferten > `'type'` — im Abnahmebeleg für eine Netzwerkdose fehlte dadurch die Angabe, > ob per LAN oder WLAN gemessen wurde. **Feldnamen immer aus dem erzeugenden > Code ablesen**, nie aus dem Kopf. (KB #1084) Sync und Datenbank brauchen keinen Eingriff — das Ergebnis ist generisches JSON. Braucht das Tool eine neue native Messroutine: Methode im Kotlin-Plugin, Eintrag im Interface `NetDiagScannerPlugin` **und** ein Zweig im Browser-Mock (beides in `src/lib/scanner.ts`) — ohne Mock lässt sich nichts ohne Gerät prüfen, und ein Mock, der nur den Gutfall zeigt, bestätigt genau die Annahme, die im Feld nicht gilt (KB #1086). ## Anmeldung Die App hängt am zentralen Auth-Modul **awlauth** (7. AWL-App). Das Token kommt aus `auth.php` und geht bei jeder Anfrage als `Authorization: Bearer` mit — auch beim APK-Download und beim PDF-Abruf. **Nie in der Adresse:** ein Token in der URL steht in jedem Zugriffs- und Proxy-Log und gilt sieben Tage für die gesamte Kunden-API. (Einzige, befristete Ausnahme: `update.php?download=1` für App-Fassungen im Feld — siehe ChangeLog des Moduls 1.3.0.) ### Fingerabdruck statt Passwort Einschaltbar unter Einstellungen → Konto. Was dabei passiert: 1. Das Sitzungs-Token wird mit einem AES-256/GCM-Schlüssel aus dem **Android-Keystore** verschlüsselt (`setUserAuthenticationRequired`), Chiffrat und IV liegen in `shared_prefs/netdiag_biometrie.xml`. 2. Die **Klartextfassung wird entfernt** (`Preferences.remove('token')`). Genau das ist der Sicherheitsgewinn: vorher stand das Token offen in `CapacitorStorage.xml` und war auf einem entsperrten Gerät ohne Weiteres lesbar. 3. Beim nächsten Start zeigt die Login-Maske „Mit Fingerabdruck anmelden". Der Finger entschlüsselt das Token; es bleibt danach nur im Arbeitsspeicher. Kein zweiter Faktor — der Finger **ersetzt** das Passwort (Vorgabe von Eddy). Die Gültigkeit bestimmt weiterhin `AWLAUTH_TTL`, und „Gerät abmelden" in der awlauth-Geräteliste wirkt unverändert: hinterlegt ist dasselbe Token. Wird es serverseitig ungültig (401 **mit** Token), räumt die App die Hinterlegung selbst weg. Ein 401 **ohne** Token ist dagegen nur „noch nicht angemeldet" und lässt sie stehen — diese Unterscheidung ist nicht theoretisch: ohne sie löschte der erste Startaufruf die gerade eingerichtete Anmeldung wieder. Wird dem Gerät ein weiterer Fingerabdruck hinzugefügt, macht Android den Schlüssel ungültig (`setInvalidatedByBiometricEnrollment`) — die App sagt das im Klartext und verlangt einmal das Passwort. Gewollt: sonst könnte jemand mit dem entsperrten Gerät einfach seinen eigenen Finger anlernen. WebAuthn wie in den PWAs geht hier nicht — im Capacitor-WebView ist es nicht verlässlich verfügbar (KB #855). ## Bedienung 1. **Anmelden** (Dolibarr-Zugang; auf dem Gerät zusätzlich Server-URL). 2. **Aufträge** — aktive direkt sichtbar, abgeschlossene per Checkbox, Suche. Alternativ über **Kunden** suchen. 3. Auftrag/Kunde antippen → Diagnose-Protokoll öffnet sich. 4. **Werkzeuge** ausführen (IP-Scan füllt die Geräteliste, je Gerät weitere Tools). Bei den meisten Karten steht „Tippen startet · Halten für Optionen": kurzer Tap startet sofort mit den zuletzt benutzten Werten, langes Halten öffnet den Parameterdialog. Nach der Messung springt die Ansicht zum frischen Ergebnis. 5. **Abschließen & synchronisieren** — Protokoll geht ans Dolibarr, PDF landet im ECM. Offline bleibt es lokal und synct automatisch bei Verbindung. Selten gebrauchte Aktionen (Protokoll löschen) liegen hinter den drei Punkten in der Kopfzeile — bewusst nicht neben dem grünen Abschließen-Knopf. ## Ohne Gerät prüfen - **Browser** (`npm run dev`): Mock-Scanner liefert Beispieldaten. - **WLAN-Demomodus** (Einstellungen → WLAN-Demodaten): 18 erfundene Netze mit allen Grenzfällen — Mesh, Co-Channel, 40 MHz im 2,4-GHz-Band, DFS, 160 MHz, Bandrand. Nötig, weil der Emulator keine WLAN-Hardware hat und jeder Scan null Netze liefert. Gespeicherte Momentaufnahmen werden als Demo gekennzeichnet. - **Diagramme**: `tools/render-chart.mjs` (siehe oben).