- Shutdown-Event sendet stopped_graceful statt stopping: der Server kennt "stopping" im Router, aber event_log.kind ist ein ENUM ohne diesen Wert. Folge war HTTP 500 nach dem Zustandswechsel, das Event fehlte in der Historie. - Default-Source auf "Predictalytics" korrigiert (Schreibweise des bereits angelegten Monitors auf dem Server). Heartbeat, Metrics-Payload, Lizenzvalidierung und der Startpfad ueber den Cache sind end-to-end gegen die Produktivserver getestet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.9 KiB
Betrieb: Watchdog-Überwachung & LicenseLabrador-Lizenzierung
Beide Integrationen sitzen im Predictalytics.WinFormsHost (dem Produktiv-Host) und
binden zwei eigenständige Schwester-Projekte an:
| Projekt | Pfad | Rolle |
|---|---|---|
| Watchdog | J:\Softwareprojekte\WatchDog |
PHP/MySQL-Server auf watchdog.mhdf.de, empfängt Heartbeats |
| LicenseLabrador | J:\Softwareprojekte\LicenseLabrador |
PHP-Lizenzserver auf license.mhdf.de + C#-SDK |
1. Watchdog (Dead-Man's-Switch)
Services/WatchdogHeartbeatService.cs sendet alle n Sekunden einen
POST /api/heartbeat an den Watchdog. Bleiben die Heartbeats aus — weil die App
abgestürzt ist oder die ganze Maschine weg ist — schlägt der Watchdog Alarm.
Beim regulären Schließen geht ein POST /api/event mit kind=stopped_graceful
raus, damit ein geplantes Beenden nicht als Crash alarmiert wird.
Nicht auf
kind=stoppingändern. Der Watchdog akzeptiert den Wert im Router, aberevent_log.kindist ein ENUM ohnestopping. Der Server setzt dann zwar noch den Zustand aufstopped, scheitert aber am Insert und liefert HTTP 500 — das Event fehlt in der Historie. Verifiziert am 2026-07-30.
Wichtig: Ein Ausfall des Watchdogs darf Predictalytics nie beeinträchtigen. Alle Aufrufe sind best effort; der erste Fehlschlag wird als Warnung geloggt, Folgefehler nur noch auf Debug-Level (keine Log-Flut).
Konfiguration (PropertyGrid im Host, Kategorie „Watchdog")
| Feld | Default | Bedeutung |
|---|---|---|
Enabled |
true |
Heartbeats an/aus |
Server URL |
https://watchdog.mhdf.de |
Basis-URL |
API Key |
(leer) | X-Watchdog-Key — Shared Key oder Agent-Token. Ohne Key passiert nichts. |
Source |
Predictalytics |
Monitor-Name im Dashboard (Auto-Registrierung beim ersten Beat) |
Instance |
default |
falls mehrere Instanzen laufen |
Interval (Sekunden) |
60 |
Sende-Takt; Alarm nach ca. Intervall × 1,5 + 30 s |
Der Key landet in der settings.json neben der Exe (nicht im Git).
PolyTrader-Maschine mit überwachen
Der Heartbeat aus Predictalytics deckt nur diesen Prozess ab. Damit auch die
Maschine überwacht wird, auf der PolyTrader läuft, gehört dort zusätzlich der
OS-Agent hin: WatchDog\agents\windows\watchdog-agent.ps1 als Scheduled Task
(inkl. Shutdown-Hook), bzw. agents/linux/watchdog-agent.sh per systemd-Timer.
2. LicenseLabrador (Kopierschutz)
Services/LicenseGuard.cs prüft beim Start, ob eine nutzbare Lizenz vorliegt
(Program.Main bricht sonst ab, bevor die MainForm überhaupt entsteht).
Ohne gültige Lizenz erscheint Services/LicenseDialog.cs zur Key-Eingabe.
Produkt-Slug, Endpoint und der Ed25519-Public-Key sind bewusst einkompiliert und nicht konfigurierbar — ein einstellbarer Endpoint würde erlauben, die App auf einen gefälschten Lizenzserver zu zeigen.
- Produkt-Slug:
predictalytics - Offline-Gnadenfrist: 168 h (7 Tage) — danach ist Serverkontakt nötig
- Revalidierung zur Laufzeit: alle 12 h; bei Widerruf/Ablauf beendet sich die App
- Härtung:
VerifyChecksum(HMAC über State + Key + Hardware-ID) gegen Memory-Patches; Nonce-Reflexion und Signaturprüfung übernimmt das SDK
Status
Produkt predictalytics und Lizenzschlüssel sind angelegt; die Aktivierung wurde
am 2026-07-30 gegen den Produktivserver verifiziert (Valid, gültig bis
2040-12-31, Checksum-Prüfung bestanden). Der einkompilierte Public Key passt zum
signing.pub des Servers — sonst käme TamperSuspected statt Valid.
Die Aktivierung ist an die Hardware-ID der jeweiligen Maschine gebunden. Auf
einem neuen Rechner erscheint einmalig der Dialog; der Cache liegt danach unter
%AppData%\predictalytics\license.
Deaktivierung bei PC-Wechsel
LicenseClient.DeactivateAsync() gibt die Aktivierung wieder frei. Aktuell nicht
in der UI verdrahtet — bei Bedarf als Menüpunkt ergänzen.