NetDiag — Netzwerk-Diagnose App (SvelteKit + Capacitor)
Find a file
Eduard Wisch 34589f12d1 Phase 2: Dauertest komplett neu — Live-Ansicht, fester Takt, Foreground-Service
Kompletter Umbau (ROADMAP_UMSETZUNG.md Phase 2). Die alte Fassung hatte vier
Probleme, die den Test praktisch wertlos machten: kein festes Intervall (ein
"Messpunkt" dauerte so lange wie das Ziel zufaellig antwortete — Prod #126:
38 Punkte in 300 s statt der ueblichen ~250-300), keine Zeitreihe (nur
Summen), kein Foreground-Service trotz gegenteiliger Doku-Behauptung, kein
Abbruchpfad. Vor allem aber: waehrend der 1-60 Minuten sah man nichts ausser
"Messung laeuft ...".

Nativ (NetDiagScannerPlugin.kt, MonitorService.kt)
  StressRun komplett neu: feste Taktung per naechstem Fixpunkt (nextTick +=
  intervalSec*1000, kein Zeitverzug ueber eine Stunde), Rohzaehler
  (sentTotal/receivedTotal/rttSum/Min/Max) + echte Zeitreihe (Liste aus
  {ts,rtt}), Ausfallsegmente werden waehrend des Laufs erkannt und
  geschlossen. Laeuft im MonitorService (Foreground, wie der Geraete-Monitor)
  — dafuer wurde der Dienst auf eine Job-Registry umgestellt (jobId -> Text),
  damit ein gleichzeitig laufender Geraete-Monitor und Dauertest sich beim
  Beenden nicht gegenseitig die Benachrichtigung wegnehmen.
  Events stressSample (live, pro Probe) und stressFinished (einmalig, Grund
  completed/stopped) + getStressStatus zur Wiederaufnahme nach Seitenwechsel.
  WICHTIG geloest: laeuft der Test natuerlich aus, waehrend niemand zuhoert
  (App im Hintergrund, andere Seite offen), bleibt der Lauf-Eintrag in
  stressRuns bestehen (wie monitorRuns) statt sofort geloescht zu werden —
  sonst waere das Ergebnis unwiederbringlich weg. Neuer Aufraeum-Call
  dismissStressRun.
  Nebenbei: der geteilte io-Scope aller Plugin-Methoden lief bisher auf einem
  gewoehnlichen Job — eine unbehandelte Exception in EINER Coroutine (z.B.
  IP-Scan mit kaputtem Host) haette strukturell alle Geschwister-Coroutinen
  mitgerissen, auch einen parallel laufenden Monitor/Dauertest. Jetzt
  SupervisorJob + CoroutineExceptionHandler.

Kritischer Bug gefunden UND gefixt (im Emulator, echter Netzausfall-Test):
  `.put("rtt", rtt as Any?)` mit Kotlin null wird von org.json.JSONObject
  behandelt wie `remove(key)` — der Schluessel verschwindet komplett statt
  als JSON null anzukommen. Die App bekam damit `undefined` statt `null` fuer
  verlorene Proben; `!== null`-Filter hielten das faelschlich fuer "erhalten".
  Ergebnis: ein per Flugmodus ausgeloester echter Ausfall zeigte live "0 %
  Verlust" und "NaN ms" bei Min/Max/Oe. Betraf NUR die Live-Anzeige — die
  gespeicherte Messung war unabhaengig davon korrekt, weil buildStressResult()
  ausschliesslich aus dem nativen Kotlin-Zustand rechnet, nie ueber die
  Pro-Probe-JSON-Bruecke. Fix: ueberall explizit JSONObject.NULL statt bloss
  `null` (betraf auch die Traceroute-Korrektur aus Phase 1). Zusaetzlich
  TS-seitig als zweite Verteidigungslinie `!= null` statt `!== null` (deckt
  sowohl null als auch undefined ab).

Neu: gemeinsame Bewertung (tools/rating.ts)
  ping.ts und der alte Dauertest bewerteten denselben Netzzustand
  unterschiedlich (ping.ts: avgMs>100 -> Rot; Dauertest: nur lossPct/maxMs).
  rateLatency() ist jetzt die einzige Stelle: Verlust, Jitter, Latenz nach
  Zielklasse (LAN/WLAN/WAN) UND eine eigene Regel "jeder Ausfall > 5 s = Rot"
  unabhaengig vom Gesamt-Verlustprozentsatz. ping.ts umgestellt, unveraendertes
  Verhalten fuer die bisherigen Schwellen (inkl. Jitter>10ms, das beim
  Portieren fast uebersehen wurde).

Neue Route statt Dialog (routes/protokoll/[id]/stresstest/)
  Wie IP-Test/WLAN/Monitor eine eigene Seite statt des blockierenden
  Werkzeug-Dialogs. Einrichtung (Ziel leer=Gateway, Dauer, Takt) mit
  Vorlaufprobe wie zuvor in stresstest.ts. Laufend: grosse Live-Zahl mit
  Ampelfarbe (rateLatency), Fortschrittsbalken mit Restzeit, Streifendiagramm
  (StressChart.svelte, live rollierendes 120s-Fenster), Zaehler
  gesendet/verloren/Ø/Min/Max, offener-Ausfall-Banner, Ereignisliste mit
  Uhrzeit ("Ausfall — wieder da nach 16 s"), Abbrechen. Abgeschlossene Laeufe
  darunter aufklappbar mit demselben Diagramm (kompletter Verlauf statt
  Fenster). stresstest.ts (Tool-Registry-Eintrag) ist jetzt nur noch
  Namens-Lookup fuer die Messungen-Liste, run() wirft bewusst einen Fehler,
  falls doch noch etwas den alten Weg aufruft.

Sicherheitsnetz gegen verpasste Events (lib/stresstest.ts)
  Ein natuerlich beendeter Test, waehrend niemand auf der Stresstest-Seite
  ist, verpasst dort das stressFinished-Event. Die Hauptprotokollseite prueft
  deshalb beim Oeffnen zusaetzlich per resumeFinishedStressSessions() nach
  (praktisch immer besucht, bevor ein Protokoll abgeschlossen wird) und
  traegt das Ergebnis nach. Bekannter Rest-Fall (dokumentiert): verlaesst der
  Techniker das Protokoll komplett ohne eine der beiden Seiten noch einmal zu
  oeffnen, bleibt der fertige Lauf bis zum naechsten Besuch liegen.

Ergebnis-Speicherung: Zeitreihe in 1-Minuten-Buckets + Ausfallsegmente +
laengster Ausfall als Measurement (tool=stresstest, sync-faehig) — Ausfaelle
werden beim Abschliessen mit dem nativen (autoritativen) Ergebnis abgeglichen,
nicht nur mit der lokal live mitgefuehrten Kopie.

Getestet im Emulator (Pixel 6 / Android 14):
- 1-Minuten-Lauf komplett bei ausgeschaltetem Display durchgelaufen
  (Foreground-Service haelt den Prozess), automatischer Abschluss + Toast
- Echter Netzausfall per Flugmodus (15s) waehrend laufendem 5-Minuten-Test:
  korrekt 23,2%/16,7% Verlust, Min/Max ohne NaN, Ereignisliste mit exakter
  Uhrzeit und Dauer — nach dem NULL-Fix verifiziert
- Abbrechen-Pfad: sofortiger Stopp, korrektes Teil-Ergebnis
- Wiederaufnahme: laufender Test nach APK-Neuinstallation (Prozess-Kill)
  korrekt als beendet erkannt
- gradle compileDebugKotlin ok, svelte-check 0 Fehler

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 00:39:36 +02:00
.forgejo/workflows android/ fest ins Repo aufgenommen — Build wie beim Adressmanager [apk] 2026-05-19 18:09:23 +02:00
android Phase 2: Dauertest komplett neu — Live-Ansicht, fester Takt, Foreground-Service 2026-08-15 00:39:36 +02:00
native-plugin Phase 0: doppelte Plugin-Quelle aufgeloest, falsche Doku-Zusagen korrigiert 2026-08-14 18:39:40 +02:00
src Phase 2: Dauertest komplett neu — Live-Ansicht, fester Takt, Foreground-Service 2026-08-15 00:39:36 +02:00
.gitignore Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
capacitor.config.ts Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
package.json Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
README.md Phase 0: doppelte Plugin-Quelle aufgeloest, falsche Doku-Zusagen korrigiert 2026-08-14 18:39:40 +02:00
svelte.config.js Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
tsconfig.json Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00
vite.config.ts Initiales Commit — NetDiag App vollständig implementiert [apk] 2026-05-19 12:01:56 +02:00

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)

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

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)
  backButton.svelte.ts  Hardware-Back (Single-Instance, KB #480/#549)
  updater.ts        APK-Auto-Update-Prüfung (KB #363)
  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/      (folgt: SIP, FreePBX, RTP)
src/routes/
  login/ auftraege/ kunden/ protokoll/[id]/ einstellungen/
android/            natives Android-Projekt inkl. Kotlin-Plugin (einzige Quelle)
native-plugin/      nur noch Anleitung/Hinweise zum Plugin

Neues Tool hinzufügen

  1. Datei unter src/lib/tools/<kategorie>/<id>.ts anlegen, Tool implementieren.
  2. In src/lib/tools/index.ts importieren und in TOOLS eintragen.

Kein Eingriff in App-Logik, Sync oder Datenbank — das Ergebnis ist generisches JSON. Braucht das Tool eine neue native Messroutine, eine Methode im Kotlin-Plugin ergänzen.

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).
  5. Abschließen & synchronisieren — Protokoll geht ans Dolibarr, PDF landet im ECM. Offline bleibt es lokal und synct automatisch bei Verbindung.