* * * * * /usr/bin/php = e(DC_ROOT) ?>/cli/tick.php --quiet
* * * * * curl -fsS -H "Authorization: Bearer <SHARED_KEY>" = e($baseUrl) ?>/api/watchdog/v1/evaluate > /dev/null
🛡️ Watchdog System-Hierarchie & Monitore
| Hierarchie / Entity Source | Typ | Status | Version | Letzte Meldung | Zuletzt Gesehen |
|---|---|---|---|---|---|
|
= $m['is_last'] ? '└─' : '├─' ?>
|
= htmlspecialchars($m['type']) ?> |
● = strtoupper($m['state']) ?> |
= htmlspecialchars((string)$m['app_version']) ?>
–
|
= htmlspecialchars($m['last_message'] ?? '-') ?> | = htmlspecialchars($m['last_seen_utc'] ?? 'Nie') ?> |
📁 Neues Projekt anlegen / Bearbeiten
Projekte Übersicht & Verwaltung
| ID | Slug | Projekt Name | Cache TTL | Verknüpfte Lizenzen | Verknüpfte Releases | Aktionen |
|---|---|---|---|---|---|---|
| = $p['id'] ?> | = htmlspecialchars($p['slug']) ?> |
= htmlspecialchars($p['name']) ?> | = $p['default_cache_ttl_hours'] ?> h (= round($p['default_cache_ttl_hours']/24, 1) ?> Tage) | = $licCount ?> Lizenzen | = $relCount ?> Releases |
⚠️ Projekt unwiderruflich löschen
Sind Sie sicher, dass Sie das Projekt löschen möchten?
Bitte geben Sie zur Sicherheitsbestätigung den Projekt-Slug ein:
✏️ Monitor & Icon bearbeiten
🔑 Neuen Lizenzschlüssel generieren
Erstellte Lizenzschlüssel
| Projekt | Lizenzschlüssel | Kunde | Aktivierungen | Status | Ablaufdatum | Aktionen |
|---|---|---|---|---|---|---|
| Noch keine Lizenzen angelegt. | ||||||
| = e($l['product_name']) ?> | = e($l['license_key']) ?> |
= e($l['customer_name'] ?? '—') ?>
= e($l['customer_email']) ?>
|
= $used ?> / = $max ?> | = e(strtoupper((string)$l['status'])) ?> | = !empty($l['expires_at']) ? e(dc_dt((string)$l['expires_at'], 'd.m.Y')) : 'Unbefristet' ?> | |
🖥️ Aktivierte Hardware
| Projekt | Lizenzschlüssel | Hardware-ID / Quelle | Plattform | Hostname | Zuletzt gesehen | Status | Aktionen |
|---|---|---|---|---|---|---|---|
| Noch keine Aktivierungen. | |||||||
| = e($a['product_name']) ?> | = e($a['license_key']) ?> |
= e($a['hardware_id']) ?>
Quelle: = e($a['hwid_source']) ?>
|
= e(strtoupper((string)($a['platform'] ?? 'WIN'))) ?> · v= (int)($a['hwid_version'] ?? 1) ?> | = e($a['hostname'] ?? '—') ?> | = e(dc_ago($a['last_seen'] ?? null)) ?> | = !empty($a['is_blocked']) ? 'GESPERRT' : 'AKTIV' ?> |
|
💾 Offline-Lizenzdatei (.lic)
Für Systeme ohne Internetzugang. Die Datei wird serverseitig erzeugt und mit
HMAC-SHA256 über den Schlüssel aus security.license_key signiert.
Am schnellsten geht es über den 📥 .lic-Knopf direkt in der Lizenzliste.
Diese Vorschau dient nur der Ansicht. Die gültige, signierte Datei liefert der 📥 .lic-Knopf in der Lizenzliste.
📜 Audit-Protokoll
| ID | Zeitpunkt | Akteur | Aktion | Details |
|---|---|---|---|---|
| Noch keine Einträge. | ||||
| = (int)$log['id'] ?> | = e(dc_dt((string)$log['created_at'])) ?> | = e($log['actor']) ?> |
= e($log['action']) ?> | = e($log['details'] ?? '—') ?> |
💻 Endpunkte & Anbindung
/validate trägt den Lizenzzustand im Feld
status auf oberster Ebene (valid, revoked,
expired, not_found, activation_limit) —
bewusst ohne den Umschlag der übrigen API, weil bereits ausgelieferte Clients
dieses Format erwarten.
Fertige Anbindung für .NET: Deploymentcenter.Client
(LicenseClient, HardwareId, verschlüsselter Offline-Cache).
Ausführlich in docs/LICENSE_INTEGRATION_GUIDE.md.
📁 Gruppen-Übersicht
🌳 Watchdog System-Hierarchie
| Name | Typ | Status | Version | Zuletzt gesehen | Kurz-Info / Message | Aktionen |
|---|---|---|---|---|---|---|
|
= $m['is_last'] ? '└─' : '├─' ?>
|
= htmlspecialchars($m['type']) ?> |
= strtoupper($m['state']) ?> |
= htmlspecialchars((string)$m['app_version']) ?>
–
|
= htmlspecialchars($m['last_seen_utc'] ?? 'Nie') ?> | = htmlspecialchars($m['last_message'] ?? '-') ?> |
🖥️ Monitor Anlegen
📜 Chronologisches Event-Log
| Zeitpunkt (UTC) | Source | Kind | Severity | Nachricht |
|---|---|---|---|---|
| = htmlspecialchars($e['at_utc']) ?> | = htmlspecialchars($e['source']) ?> | = htmlspecialchars($e['kind']) ?> |
= strtoupper($e['severity']) ?> | = htmlspecialchars($e['message'] ?? '-') ?> |
Neuen Agent-Token erstellen
Agent Tokens
| Token ID | Bezeichnung | Gebundene Source | Token Value | Status | Aktion |
|---|---|---|---|---|---|
= htmlspecialchars($tok['token_id']) ?> |
= htmlspecialchars($tok['name']) ?> | = htmlspecialchars($tok['monitor_source'] ?? 'Alle Sources') ?> |
= htmlspecialchars($masked) ?>
|
= $tok['revoked'] ? 'WIDERUFEN' : 'AKTIV' ?> |
📦 Veröffentlichte Software Releases
| Projekt | Kanal | Plattform | Version | Git Commit | Größe | Release Notes | Download & SHA256 | Datum | Aktionen |
|---|---|---|---|---|---|---|---|---|---|
| = htmlspecialchars($r['product_slug']) ?> | = strtoupper(htmlspecialchars($r['channel'] ?? 'prod')) ?> |
= htmlspecialchars($platformLabel) ?>
|
v= htmlspecialchars($r['version']) ?>
KRITISCH
UNSIGNIERT
|
= htmlspecialchars($r['git_commit'] ?? 'n/a') ?> |
= $sizeFormatted ?> | = htmlspecialchars($r['release_notes'] ?? '-') ?> |
⬇️ Download Package
SHA: = htmlspecialchars(substr($r['sha256_hash'], 0, 12)) ?>...
|
= htmlspecialchars($r['created_at']) ?> |
⬇️ Installer herunterladen
Ein Werkzeug für alles: Dasselbe Programm richtet eine Anwendung erstmalig ein und aktualisiert sie später. Es bringt die .NET-Laufzeit mit — auf dem Zielsystem muss nichts vorinstalliert sein.
scripts/build_installer.ps1 gebaut und mit
scripts/upload_installer.py nach /installer/
hochgeladen.
= e((string)($installerManifest['gitCommit'] ?? '?')) ?>
· = e(substr((string)($installerManifest['buildDateUtc'] ?? ''), 0, 10)) ?>
| Plattform | Größe | SHA256 | Download |
|---|---|---|---|
= e((string)($bin['platform'] ?? '?')) ?> |
= number_format(((int)($bin['sizeBytes'] ?? 0)) / (1024 * 1024), 1, ',', '.') ?> MB |
= e(substr($binHash, 0, 24)) ?>…
|
⬇️ Herunterladen |
Direkt auf dem Zielsystem
Linux — lädt das passende Binary, prüft die Prüfsumme und legt es ab:
Oder ohne Skript, direkt das Binary:
Windows (PowerShell):
Die Skripte richten nichts von selbst ein — sie laden, prüfen und sagen, wie es weitergeht. Ein Skript aus dem Netz, das ungefragt eine Anwendung aufsetzt und dabei nach Zugangsdaten fragt, wäre genau das, wovor man Nutzer sonst warnt.
Für die Installation wird ein Konto der Rolle installer gebraucht — anzulegen unter System → 👤 Benutzer. Ein Administratorkonto funktioniert auch, gehört aber nicht auf ein Zielsystem: seine Zugangsdaten würden damit auf jedem Rechner landen, auf dem je etwas installiert wurde.
Neues Software-Release veröffentlichen
✏️ Release bearbeiten
🗑️ Release löschen
Möchten Sie das Release für wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.
🤖 Aktive Agenten
🐛 Bugs, Features & Ideen = (int)$bugtrackerTotal ?> Treffer
| ID / Typ | Umgebung | Projekt & Titel | Build | Schweregrad | Anzahl | Status | Aktionen |
|---|---|---|---|---|---|---|---|
| Keine Einträge für diese Filterkombination. | |||||||
| #= (int)$item['id'] ?> = $typeBadge ?> |
= $envBadge ?> |
= e((string)$item['title']) ?>
Projekt:
= e((string)$item['project_slug']) ?>
Von: = e((string)$item['created_by']) ?>
= e(dc_ago($item['last_seen_at'] ?? null)) ?>
🔒 = e((string)$item['claimed_by']) ?>
📲 = e((string)$item['push_id']) ?>
🤖 = e((string)$item['target_agent']) ?>
📄 = e((string)$item['file_path']) ?>= !empty($item['line_no']) ? ':' . (int)$item['line_no'] : '' ?>
🏷️ = e((string)$item['tags']) ?>
|
= e((string)($item['build_version'] ?? 'unbekannt')) ?> |
= $sevBadge ?> | = (int)$item['occurrence_count'] ?>x | = $statusBadge ?> |
|
➕ Bug, Feature Request oder Idee Erfassen
⚡ Fehler-Stream = (int)$errorTotal ?> Gruppen
| Klasse | Fehler | Projekt / Umgebung | Build | Anzahl | Zuletzt | Aktionen |
|---|---|---|---|---|---|---|
|
Keine Fehler für diese Filterkombination.
Stummgeschaltete Einträge sind ausgeblendet — über „Nur stummgeschaltete“ sichtbar. |
||||||
| = $levelBadge ?> |
= e(mb_strimwidth((string)$item['title'], 0, 90, '…')) ?>
🔇 stummgeschaltet= !empty($item['ignore_rule_id']) ? ' (Regel #' . (int)$item['ignore_rule_id'] . ')' : '' ?>
1): ?>
📈 = $windowCount ?>× in dieser Stunde
📄 = e((string)$item['file_path']) ?>= !empty($item['line_no']) ? ':' . (int)$item['line_no'] : '' ?>
|
= e((string)$item['project_slug']) ?>
= e(strtoupper((string)$item['environment'])) ?>
|
= e((string)($item['build_version'] ?? '—')) ?> |
= number_format((int)$item['occurrence_count'], 0, ',', '.') ?>× | = e(dc_ago($item['last_seen_at'] ?? null)) ?> |
|
🔇 Bekannte, harmlose Fehler
Ein Treffer bedeutet nicht „wegwerfen“: Der Fehler wird weiterhin erfasst und hochgezählt, bleibt aber aus der Übersicht heraus und löst keine Benachrichtigung aus. Der Zähler ist dabei der eigentliche Gewinn — dass ein bekannter Fehler auftritt, ist normal; dass er plötzlich hundertmal so oft auftritt, ist ein Signal. Dafür ist die Alarmschwelle da.
Bestehende Regeln
| # | Projekt | Muster | Begründung | Alarmschwelle | Treffer | Status | Aktionen |
|---|---|---|---|---|---|---|---|
| Noch keine Regeln angelegt. | |||||||
| = (int)$rule['id'] ?> |
ALLE
= e((string)$rule['project_slug']) ?>
|
= e((string)$rule['pattern']) ?>
= e((string)$rule['match_type']) ?>
|
= e(mb_strimwidth((string)$rule['reason'], 0, 160, '…')) ?> | = (int)$rule['alert_on_rate'] ?>/h — |
= number_format((int)$rule['match_count'], 0, ',', '.') ?>
= (int)($rule['item_count'] ?? 0) ?> Item(s)
· = e(dc_ago((string)$rule['last_match_at'])) ?>
|
= $enabled ? 'AKTIV' : 'INAKTIV' ?> |
|
💻 Anbindung
Ein Aufruf, den man in den globalen Exception-Handler hängt. Titel und Dringlichkeit leitet der Server ab, die Regeln oben greifen automatisch.
👑 Master-Tokens (Selbst-Provisionierung für Client-Apps & Host-Skripte)
| Token ID | Bezeichnung | Typ / Identität | Projekt / Lizenz | Rechte (Scopes) | Sub-Tokens | Token Key | Aktionen |
|---|---|---|---|---|---|---|---|
= htmlspecialchars($mTok['token_id']) ?> |
= htmlspecialchars($mTok['name']) ?> |
= strtoupper($mTok['owner_type']) ?> = htmlspecialchars($mTok['owner_identity'] ?? '-') ?> |
= htmlspecialchars($mTok['project_slug'] ?? '-') ?>
= !empty($mTok['license_key']) ? ' Lic: ' . htmlspecialchars($mTok['license_key']) . '' : '' ?> |
= htmlspecialchars($sc) ?> | = (int)($mTok['sub_token_count'] ?? 0) ?> Sub-Tokens |
= htmlspecialchars($masked) ?>
|
WIDERUFEN
|
🔑 Aktive Sub-Tokens (Per Provisioning API Erstellt)
| Token ID | Parent Master ID | Bezeichnung / Client | Umgebung | Scopes | Token Key | Zuletzt Genutzt | Status | Aktionen |
|---|---|---|---|---|---|---|---|---|
= htmlspecialchars($sTok['token_id']) ?> |
= htmlspecialchars($sTok['parent_token_id'] ?? '-') ?> |
= htmlspecialchars($sTok['name']) ?> | = strtoupper($sTok['environment']) ?> | = htmlspecialchars($sc) ?> |
= htmlspecialchars($sMasked) ?>
|
= $sTok['last_used_at'] ? htmlspecialchars($sTok['last_used_at']) : 'Noch nie' ?> | = $sTok['revoked'] ? 'WIDERUFEN' : 'AKTIV' ?> |
|
➕ Neuen Master-Token Erstellen
⚙️ Server & Umgebung
🩺 Systemzustand
| Prüfung | Zustand | Hinweis |
|---|---|---|
| Watchdog-Evaluator | = $evaluatorStale ? 'INAKTIV' : 'AKTIV' ?> | Letzter Lauf: = e(dc_dt((string)$evaluatorLastRun)) ?> (= e(dc_ago((string)$evaluatorLastRun)) ?>) Noch nie gelaufen — ohne ihn bleiben ausgefallene Monitore „up“. |
| Log-Verzeichnis beschreibbar | = $logWritable ? 'OK' : 'PRÜFEN' ?> | var/log/ — Fehlerprotokolle |
| Konfiguration ausserhalb Git | OK | config/config.php ist per .gitignore ausgeschlossen |
💬 Rocket.Chat Benachrichtigungen & Statusberichte
Hier konfigurieren Sie die automatischen Rocket.Chat-Benachrichtigungen. Alle 12 Stunden wird ein detaillierter Systemstatusbericht an den Status-Kanal gesendet. Kritische Systemausfälle und Bugs landen sofort im Alarm-Kanal.
🧪 Aktionen & Testlauf
Hier können Sie die Erreichbarkeit Ihres Rocket.Chat-Servers testen oder sofort einen 12-Stunden-Statusbericht auslösen.
• Letzter Bericht: = !empty($rcCronJob['last_run_utc']) ? e(dc_dt((string)$rcCronJob['last_run_utc'])) . ' (' . e(dc_ago((string)$rcCronJob['last_run_utc'])) . ')' : 'Noch nie gelaufen' ?>
• Letzter Status: = e((string)($rcCronJob['last_status'] ?? 'bereit')) ?>
• Nächster geplanter Lauf: In ca. = !empty($rcCronJob['last_run_utc']) ? max(0, (int)round(($rcConfig['report_interval'] - (time() - strtotime((string)$rcCronJob['last_run_utc'] . ' UTC'))) / 3600)) . ' Std.' : 'sofort beim nächsten Tick' ?>
👤 Benutzerkonten
Für die Erstinstallation von Anwendungen gibt es die Rolle
installer. Solche Konten melden sich ausschließlich über
/api/setup/v1/login an und bekommen dafür ein Token, das nach
30 Minuten verfällt. Am WebUI können sie sich nicht anmelden.
Der Grund: Die Zugangsdaten werden auf jedem Zielsystem eingegeben — mit einem
Administratorkonto verteilte man damit den Zugang zu Tokens, Lizenzen und
Monitoren auf jeden Rechner, auf dem je etwas installiert wurde.
| Benutzer | Rolle | Status | Letzte Anmeldung | Angelegt | Aktionen |
|---|---|---|---|---|---|
| = e((string)$u['username']) ?> Sie | = e(strtoupper($uRole)) ?> | = $uDisabled ? 'DEAKTIVIERT' : 'aktiv' ?> | = !empty($u['last_login_at']) ? e((string)$u['last_login_at']) : 'nie' ?> | = e((string)($u['created_at'] ?? '-')) ?> |
|
Neues Konto anlegen
📖 API-Dokumentation
Die Schnittstelle beschreibt sich selbst. Der frühere fest im Quelltext hinterlegte Textblock ist durch eine maschinenlesbare OpenAPI-Beschreibung ersetzt — ein Agent kann sie abrufen und sich daran orientieren, ohne dass eine Prompt-Vorlage gepflegt werden muss.
🗄️ Datenbank-Migration
Führt ausstehende Migrationen aus. Bereits angewendete Versionen werden in
dc_migrations vermerkt und übersprungen.