Vier Werkzeuge haben nachweislich Unsinn ins Kundenprotokoll geschrieben. Belege
sind echte Prod-Messungen; jeder Fix wurde im Emulator gegen den passenden
Fehlerfall nachgestellt.
SNMP (Snmp.kt, snmp.ts)
Snmp.get lieferte bei JEDEM Problem null -> "-" -> parseInt("-")||0 -> 0.
Ein Switch, der gar nicht antwortet, stand damit als "0 Fehler" in Gruen im
Kunden-PDF (Prod #95/#96). Neu: Ergebnistyp Value/Timeout/Failure statt
String?, Request-ID- und error-status-Pruefung, v2c-Ausnahmen (0x80/0x81/0x82)
erkannt, ein Wiederholversuch bei Timeout. Das Werkzeug meldet jetzt
"nicht messbar" statt Zahlen zu erfinden.
Test: SNMP gegen einen Host ohne Agent -> status 3 "keine SNMP-Antwort".
Traceroute (pingWithTtl, traceroute.ts)
Der Fallback-Regex \((\d+\.\d+\.\d+\.\d+)\) traf IMMER zuerst die ping-Kopfzeile
"PING 8.8.8.8 (8.8.8.8) ...". Ein stummer Hop wurde dadurch als Ziel ausgegeben
und der Trace beendet — daher "2 Hops bis 8.8.8.8, beide 0 ms" (Prod #13).
Zwischen-Hops liefern zudem nie ein time=, die Zeit war strukturell 0.
Neu: Kopfzeile verworfen, zeilenweise geparst, Reverse-DNS-Antworten erkannt,
RTT selbst per nanoTime gestoppt, 3 Proben je TTL, waitFor(3s)+destroyForcibly,
"keine Antwort" ist null und nicht 0, Bewertung haengt an "Ziel erreicht".
Test: 8.8.8.8 -> 1 Hop mit echten 13,3 ms (statt 0 ms);
192.0.2.1 -> status 3, alle Hops "* (keine Antwort)" statt gruen.
Ping (measurePing, ping.ts)
Kein WifiLock, keine Aufwaermproben: zwischen den Proben schlief das Funkmodul
ein, die Aufwachzeit landete in der Messung — 296 ms zum LAN-Gateway bei 0 %
Verlust und rotem Status (Prod #4). WAKE_LOCK fehlte im Manifest, weshalb
WifiLock.acquire() eine SecurityException warf, die ein leerer catch schluckte.
Neu: WAKE_LOCK im Manifest, WifiLock (LOW_LATENCY) + PARTIAL_WAKE_LOCK um jede
Messung, 2 verworfene Aufwaermproben, Median und Messaufschlag (avg-min)
zusaetzlich ausgewiesen, Verlust als Kommazahl statt Ganzzahl-Division,
Bewertung auf den Median statt den Mittelwert, "keine Antwort" != "0 ms".
Test: 20 Proben -> Median 0,3 ms, Messaufschlag 0,1 ms, Verfahren dokumentiert.
Durchsatz (measureThroughput, iperf.ts)
Kein soTimeout: nahm die Gegenstelle an, ohne zu senden, blockierte read()
unbegrenzt und das Werkzeug-Fenster hing dauerhaft auf "Messung laeuft ...".
Neu: soTimeout 4 s je Phase, harter withTimeout-Guard, Ist-Zeit statt
angenommener halber Dauer, measured-Flag — ohne uebertragene Bytes gibt es
kein rotes "0 Mbit/s" mehr, sondern "nicht messbar".
Test: Gegenstelle nimmt an und schweigt -> Ergebnis nach 30 s statt Dauerhaenger.
Netzerkennung (firstLocalIpv4, getLocalSubnet, hostsInSubnet)
firstLocalIpv4() gab bei fehlendem Netz hart "192.168.1.1" zurueck; zusammen mit
dem Praefix-Fallback /24 entstand das Phantom-Netz 192.168.1.0/24, das auch noch
ins Protokoll geschrieben wurde. Der Fehlerzweig in ipscan.ts konnte deshalb nie
greifen. Neu: "" statt Phantom-IP, Link-Local uebersprungen, getLocalSubnet
meldet einen Fehler, DHCP-Fallback nur bei WLAN-Transport (sonst wurde bei
gestecktem USB-RJ45 die Maske aus dem WLAN genommen), unlesbares CIDR-Praefix
wird abgelehnt statt still durch /24 ersetzt.
Test: Flugmodus -> "Kein Netzbereich — WLAN/LAN nicht aktiv?" statt Phantom-Netz.
Stresstest-Ziel (stresstest.ts)
Vorgabe 192.168.1.1 im Kundennetz 192.168.178.0/24 -> 5 Minuten ins Leere
gemessen, Ergebnis "100 % Verlust" rot im Protokoll (Prod #126). Neu: kein
fester Vorgabewert, leer = Gateway des aktiven Adapters, und eine Vorlaufprobe
bricht ab, bevor minutenlang gegen ein totes Ziel gemessen wird.
Test: Ziel 192.168.1.1 -> nach 7 s "antwortet nicht — Test nicht gestartet"
(vorher: 60 s Messung mit rotem 100-%-Ergebnis).
Neue Bewertung "nicht messbar" (MeasureStatus 3)
Bisher gab es nur ok/warn/fail. Ein Test, der gar nicht durchgefuehrt werden
konnte, musste sich als eines davon ausgeben — meist als Gruen. Status 3 wird
neutral grau dargestellt (Messkarte und Geraetekarte) und ist keine Aussage
ueber das Kundennetz.
Geprueft: gradle compileDebugKotlin ok, svelte-check 0 Fehler (2 vorbestehende
Warnungen), alle sieben Faelle im Emulator (Pixel 6 / Android 14) durchgespielt
und die Ergebnisse in der Datenbank gegengelesen statt am Bildschirm geraten.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .forgejo/workflows | ||
| android | ||
| native-plugin | ||
| src | ||
| .gitignore | ||
| capacitor.config.ts | ||
| package.json | ||
| README.md | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
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
- Datei unter
src/lib/tools/<kategorie>/<id>.tsanlegen,Toolimplementieren. - In
src/lib/tools/index.tsimportieren und inTOOLSeintragen.
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
- Anmelden (Dolibarr-Zugang; auf dem Gerät zusätzlich Server-URL).
- Aufträge — aktive direkt sichtbar, abgeschlossene per Checkbox, Suche. Alternativ über Kunden suchen.
- Auftrag/Kunde antippen → Diagnose-Protokoll öffnet sich.
- Werkzeuge ausführen (IP-Scan füllt die Geräteliste, je Gerät weitere Tools).
- Abschließen & synchronisieren — Protokoll geht ans Dolibarr, PDF landet im ECM. Offline bleibt es lokal und synct automatisch bei Verbindung.