Fehler-Schnittstelle - Neuer schlanker Eingang POST /api/errors/v1/report für den globalen Exception-Handler einer Anwendung. Titel und Dringlichkeit leitet der Server ab; gespeichert wird in derselben Tabelle wie der Bugtracker. Ein zweiter Speicher wäre nur ein zweiter Ort, an dem man suchen müsste. - error_level (fatal/error/warning) trennt die technische Art des Ereignisses von der geschäftlichen Dringlichkeit. Ein Duplicate-Entry ist technisch ein error, geschäftlich belanglos — beides zu vermischen war der Grund, warum solche Meldungen als Bug im Dashboard landeten. Ignore-Regeln gegen bekanntes Rauschen - bugtracker_ignore_rules mit contains/regex/exception_class, Pflichtfeld für die Begründung und optionaler Alarmschwelle. - 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 der eigentliche Zweck — dass ein bekannter Fehler auftritt, ist normal; dass er plötzlich hundertmal so oft auftritt, ist ein Signal. Dafür das rollende Stundenfenster und error.rate_exceeded. - Neue Regeln lassen sich rückwirkend auf bestehende Einträge anwenden. Gruppierung überarbeitet - Der Schlüssel nahm bisher 300 Zeichen Stacktrace auf. Derselbe Fehler zersplitterte dadurch, sobald ein Aufrufer den Stack einmal mitschickte und einmal nicht. Jetzt zählt der Ursprungsort: bevorzugt die Dateiangabe, sonst der erste Rahmen des Stacktrace. - Die Normalisierung ersetzte nur Zahlen ab vier Stellen, wodurch 'AA-1' und 'BB-2' getrennt blieben. Werte in Anführungszeichen, die Ziffern enthalten, gelten jetzt als veränderlich — der Schlüsselname bleibt erhalten, sodass verschiedene Unique-Keys unterscheidbar sind. Mit 9 Testfällen belegt. Metrik-Verlauf - watchdog_metrics speichert numerische Heartbeat-Werte mit Zeitstempel. Zuvor wurde metrics_json bei jedem Heartbeat überschrieben; damit ließ sich "die Platte läuft seit drei Tagen voll" nicht erkennen, nur "sie ist voll". - GET /api/watchdog/v1/metrics liefert den verdichteten Verlauf und die Abweichung vom eigenen Sieben-Tage-Durchschnitt. Dieser relative Ansatz braucht keine projektspezifischen Schwellwerte. - Aufbewahrung 14 Tage, Bereinigung stündlich durch den Evaluator. Health-Checks per Push statt Abruf - Der Heartbeat nimmt ein checks-Objekt entgegen, das die Anwendung selbst ermittelt. Das Deploymentcenter interpretiert die Namen nicht, es liest nur ok und message — was "gesund" bedeutet, entscheidet jede Anwendung selbst. Schlägt eine Prüfung fehl, wird ein als ok gemeldeter Heartbeat auf warning herabgestuft. - Bewusst ausgehend: auf den Zielmaschinen müssen keine Ports geöffnet werden. Abhängigkeitsbewusste Alarmierung - Fällt ein Monitor aus, dessen Parent selbst unten ist, wird der Alarm unterdrückt. Der Zustand bleibt sichtbar. Vorher erzeugte ein ausgefallener Hypervisor mit zwölf VMs dreizehn Meldungen für ein Problem. - Mehrere Ebenen und fehlerhafte Hierarchien (Zyklen, gelöschte Parents) sind abgesichert; mit 10 Testfällen belegt. WebUI - Neue Ansicht "Fehler-Stream" mit Filtern nach Projekt, Fehlerklasse, Umgebung, Zeitraum und Sichtbarkeit sowie Volltextsuche und Pagination. Stummgeschaltete Einträge sind standardmäßig ausgeblendet. - Verwaltung der Ignore-Regeln inklusive Trefferzähler. - Die Detailansicht zeigt Fehlerklasse, Stummschaltungsgrund und die Häufung im laufenden Stundenfenster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
17 KiB
Deployment Center — Agenten-Handbuch
Diese Seite beschreibt, wie ein Coding-Agent den Bugtracker und den UpdateService des Deployment Centers benutzt.
Maschinenlesbare Fassung: GET /api/openapi.json
0. Was sich geändert hat
Wer eine ältere Integration betreibt, muss zwei Dinge anpassen:
| Änderung | Auswirkung |
|---|---|
POST /api/bugtracker/v1/report verlangt jetzt zwingend ein Token |
Aufrufe ohne Token liefern 401 unauthorized |
GET /api/bugtracker/v1/projects verlangt jetzt ein Token |
dito |
POST auf UpdateService-Publish verlangt updateservice:publish |
Aufrufe ohne Token liefern 401 |
| Antwortformat vereinheitlicht | Erfolg: {"status":"success",...}, Fehler: {"status":"error","error":{"code":"…","message":"…"}} |
Der Feldname error_hash bleibt erhalten; zusätzlich gibt es dedup_key.
1. Authentifizierung
Alle Endpunkte akzeptieren das Token in einem dieser Header:
Authorization: Bearer dc_sub_xxxxxxxxxxxx
X-Agent-Token: dc_sub_xxxxxxxxxxxx
Token-Hierarchie
- Master-Token (
dc_master_…) — wird im WebUI unter Token-Verwaltung erzeugt. Langlebig, gehört auf den Rechner bzw. in die CI, nicht in ein Repository. - Sub-Token (
dc_sub_…) — erzeugt sich ein Agent selbst aus dem Master-Token. Rechte lassen sich dabei nur einschränken, nie erweitern.
Sub-Token anfordern
curl -X POST https://dc.mhdf.de/api/tokens/v1/provision \
-H "X-Master-Token: dc_master_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"client_name": "claude-code auf DEV-WORKSTATION-01",
"instance_id": "DEV-WORKSTATION-01",
"scopes": ["bugtracker:report", "bugtracker:read", "bugtracker:manage"],
"environment": "development"
}'
Das zurückgegebene sub_token wird nur einmal ausgeliefert.
Rechte (Scopes)
| Scope | Erlaubt |
|---|---|
bugtracker:report |
Bugs, Feature Requests und Ideen melden |
bugtracker:read |
Items und Projekte lesen |
bugtracker:manage |
Übernehmen, kommentieren, Status setzen, schließen |
watchdog:ping |
Heartbeats senden |
updateservice:read |
Auf Updates prüfen |
updateservice:publish |
Releases veröffentlichen |
bugtracker:* |
alle Bugtracker-Rechte |
* |
alles |
Ist ein Token an ein Projekt gebunden, greifen alle Aufrufe automatisch nur
auf dieses Projekt zu — ein Zugriff auf ein anderes liefert 403 project_forbidden.
2. Projekte finden
curl https://dc.mhdf.de/api/bugtracker/v1/projects \
-H "Authorization: Bearer $DC_TOKEN"
{
"status": "success",
"count": 4,
"projects": [
{
"slug": "deploymentcenter",
"name": "Deployment Center",
"repo_url": "https://git.example.com/Richard/Deploymentcenter.git",
"default_agent": null,
"open_items": 3,
"critical_items": 0
}
]
}
Findest du einen Fehler im Deployment Center selbst, melde ihn unter
project_slug: "deploymentcenter".
3. Etwas melden
curl -X POST https://dc.mhdf.de/api/bugtracker/v1/report \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: run-2026-08-07-42" \
-d '{
"project_slug": "myapp",
"type": "bug",
"title": "NullReferenceException in UserAuthService",
"description": "Tritt beim Login ohne gesetzte Session auf.",
"error_message": "Object reference not set to an instance of an object.",
"stack_trace": "at MyApp.Core.UserAuthService.ValidateToken(String token)",
"severity": "high",
"environment": "production",
"build_version": "v1.4.2",
"repo_url": "https://git.example.com/me/myapp.git",
"git_branch": "main",
"commit_sha": "a21536f",
"file_path": "src/Core/UserAuthService.cs",
"line_no": 42
}'
Felder
| Feld | Pflicht | Bedeutung |
|---|---|---|
title |
ja | Kurze Beschreibung, max. 255 Zeichen |
project_slug |
empfohlen | Aus der Projektliste; Vorgabe default |
type |
nein | bug (Vorgabe) oder feature_request |
severity |
nein | idea, wishlist, low, medium (Vorgabe), high, critical |
environment |
nein | production (Vorgabe), development, staging, testing |
client_ref |
empfohlen | Idempotenz-Schlüssel, alternativ Header Idempotency-Key |
repo_url, git_branch, commit_sha, file_path, line_no |
empfohlen | Code-Kontext — spart dem nächsten Agenten das Parsen des Stacktrace |
context |
nein | Beliebiges JSON-Objekt für Zusatzinformationen |
push_id, target_agent, tags |
nein | Workflow-Zuordnung |
created_by wird aus dem Token abgeleitet und kann nicht gesetzt werden.
Was der Server daraus macht
- Deduplizierung — gleiche Fehler werden zusammengefasst und
occurrence_counterhöht. Zeilennummern, Speicheradressen, GUIDs und Zeitstempel werden dabei ausgeblendet, damit derselbe Fehler nicht als neu gilt. Feature Requests und Ideen werden über den Titel dedupliziert. - Eskalation — wird ein offener Bug erneut mit höherem Schweregrad gemeldet, wird er hochgestuft (nie herabgestuft).
- Regression — tritt ein bereits gelöster Bug erneut auf, entsteht ein
neues Item mit
regression_ofals Verweis auf das alte. - Idempotenz — identische
client_refim selben Projekt legt kein Duplikat an.
Antwort
{
"status": "success",
"item_id": 42,
"is_new": true,
"idempotent_hit": false,
"occurrence_count": 1,
"dedup_key": "e2c918a514d89a42f...",
"item_status": "open",
"regression_of": null,
"message": "Bug erfasst."
}
4. Die Agenten-Schleife
Basis: https://dc.mhdf.de/api/bugtracker/v1/manage
4.1 Arbeit holen und übernehmen
Ein Aufruf, der die nächsten offenen Items liefert und exklusiv für dich reserviert — damit arbeiten nicht zwei Agenten am selben Bug:
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/manage?action=next" \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{"project_slug": "myapp", "limit": 1, "severity": "critical,high"}'
Die Reservierung (Lease) läuft nach 30 Minuten automatisch ab. Brauchst du
länger, erneuere sie mit action=claim auf dieselbe ID.
4.2 Zwischenstand dokumentieren
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/manage?action=comment&id=42" \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"comment": "Ursache gefunden: Session wird vor dem Redirect nicht initialisiert.",
"action_taken": "investigated"
}'
Empfohlene Werte für action_taken: investigated, fix_proposed,
pr_opened, needs_human, blocked, commented.
4.3 Abschließen
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/manage?action=resolve&id=42" \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resolved_in_build": "v1.4.3",
"resolution_notes": "Session-Initialisierung in AuthController vorgezogen."
}'
4.4 Wieder freigeben
Kommst du nicht weiter, gib das Item zurück, statt den Lease verfallen zu lassen:
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/manage?action=release&id=42" \
-H "Authorization: Bearer $DC_TOKEN" \
-d '{"note": "Benötigt Zugriff auf Produktivlogs."}'
5. Lesen und Filtern
curl "https://dc.mhdf.de/api/bugtracker/v1/manage?action=list&project_slug=myapp&status=open,in_progress&order=severity&limit=20" \
-H "Authorization: Bearer $DC_TOKEN"
| Parameter | Bedeutung |
|---|---|
status, severity |
Mehrere Werte kommagetrennt |
type, environment, project_slug |
Einzelwert oder all |
target_agent, claimed_by, push_id |
Exakte Übereinstimmung |
search |
Volltext über Titel, Beschreibung, Fehlermeldung, Tags, Dateipfad |
unclaimed_only |
true — nur Items, die kein Agent bearbeitet |
updated_since |
ISO-8601 — Delta-Abfrage für effizientes Polling |
order |
newest, oldest, updated, severity, occurrences |
limit, offset |
Pagination, max. 500 pro Seite |
Die Antwort enthält total, limit, offset und has_more.
Polling-Muster
# Nur was sich seit dem letzten Durchlauf geändert hat
curl "…/manage?action=list&updated_since=2026-08-07T09:00:00Z&order=updated" \
-H "Authorization: Bearer $DC_TOKEN"
6. Release veröffentlichen und Items automatisch schließen
Der Kreis schließt sich hier: Items, deren resolved_in_build der
veröffentlichten Version entspricht, werden beim Publish automatisch geschlossen.
curl -X POST https://dc.mhdf.de/api/updateservice/v1/publish \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"product_slug": "myapp",
"version": "1.4.3",
"channel": "prod",
"download_url": "https://dc.mhdf.de/downloads/myapp-1.4.3.zip",
"sha256_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"git_commit": "a21536f",
"release_notes": "Behebt den Login-Fehler."
}'
{
"status": "success",
"release_id": 12,
"created": true,
"auto_resolved": 3,
"message": "Release 1.4.3 (prod) für \"myapp\" veröffentlicht. 3 Bugtracker-Item(s) automatisch geschlossen."
}
Der Versionsvergleich folgt der semantischen Versionsordnung — 1.10.0 gilt
korrekt als neuer als 1.9.0.
7. Fehlerbehandlung
Fehler tragen einen stabilen, maschinenlesbaren Code. Reagiere auf code,
nicht auf message:
{
"status": "error",
"error": { "code": "already_claimed", "message": "Item #42 ist bereits vergeben." }
}
| Code | HTTP | Bedeutung und Reaktion |
|---|---|---|
unauthorized |
401 | Token fehlt, ist abgelaufen oder hat den Scope nicht |
project_forbidden |
403 | Token ist an ein anderes Projekt gebunden |
already_claimed |
409 | Anderer Agent arbeitet daran — nächstes Item nehmen |
not_claimed |
409 | Freigabe eines Items, das dir nicht gehört |
not_found |
404 | Item existiert nicht |
rate_limited |
429 | Sendefrequenz senken, später erneut |
invalid_json |
400 | Request-Body ist kein gültiges JSON |
missing_id, missing_status, missing_build |
400 | Pflichtfeld fehlt |
invalid_status, invalid_version, invalid_hash |
400 | Wert nicht zulässig |
internal_error |
500 | Serverfehler — wird automatisch selbst im Bugtracker erfasst |
Rate-Limit: 60 Reports pro Minute und IP. Bei 429 das Intervall verdoppeln.
8. Vollständige Beispielschleife (Python)
import os, requests
BASE = "https://dc.mhdf.de/api/bugtracker/v1/manage"
HEAD = {"Authorization": f"Bearer {os.environ['DC_TOKEN']}",
"Content-Type": "application/json"}
def next_item(project):
r = requests.post(f"{BASE}?action=next", headers=HEAD,
json={"project_slug": project, "limit": 1})
r.raise_for_status()
items = r.json().get("items", [])
return items[0] if items else None
def comment(item_id, text, action="investigated"):
requests.post(f"{BASE}?action=comment&id={item_id}", headers=HEAD,
json={"comment": text, "action_taken": action}).raise_for_status()
def resolve(item_id, build, notes):
requests.post(f"{BASE}?action=resolve&id={item_id}", headers=HEAD,
json={"resolved_in_build": build,
"resolution_notes": notes}).raise_for_status()
def release(item_id, reason):
requests.post(f"{BASE}?action=release&id={item_id}", headers=HEAD,
json={"note": reason}).raise_for_status()
item = next_item("myapp")
if item is None:
print("Nichts zu tun.")
else:
print(f"#{item['id']}: {item['title']}")
if item.get("file_path"):
print(f" -> {item['file_path']}:{item.get('line_no', '?')}")
comment(item["id"], "Analyse gestartet.")
try:
# ... hier die eigentliche Arbeit ...
resolve(item["id"], "v1.4.3", "Fix in AuthController.")
except Exception as exc:
release(item["id"], f"Abbruch: {exc}")
8a. Fehler melden (Laufzeitfehler)
Für den globalen Exception-Handler einer Anwendung gibt es einen schlankeren Eingang. Titel und Dringlichkeit leitet der Server ab:
curl -X POST https://dc.mhdf.de/api/errors/v1/report \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"project_slug": "polytrader",
"exception": "PDOException",
"message": "SQLSTATE[23000]: Duplicate entry '\''MKT-88213'\'' for key '\''uq_market'\''",
"stack_trace": "at Importer.php:142",
"level": "error",
"build": "v2.0.1",
"environment": "production",
"file": "src/Market/Importer.php",
"line": 142
}'
level unterscheidet die technische Art des Ereignisses — unabhängig von der
geschäftlichen Dringlichkeit:
| Wert | Bedeutung |
|---|---|
fatal |
Der Prozess hat sich beendet |
error |
Ein Vorgang ist fehlgeschlagen, das Programm läuft weiter (Vorgabe) |
warning |
Auffälligkeit ohne Funktionsverlust |
Gruppierung
Gleiche Fehler werden zu einer Gruppe zusammengefasst und hochgezählt. Veränderliche Bestandteile werden dabei ausgeblendet — Werte in Anführungszeichen, die Ziffern enthalten, Speicheradressen, GUIDs, Zeitstempel und Zeilennummern. Diese drei Meldungen ergeben eine Gruppe:
Duplicate entry 'MKT-88213' for key 'uq_market'
Duplicate entry 'AA-1' for key 'uq_market'
Duplicate entry 'X-99471' for key 'uq_market'
Ein anderer Unique-Key (uq_orders) bleibt dagegen eine eigene Gruppe — der
Schlüsselname enthält keine Ziffern und zählt damit zur Identität des Fehlers.
Bekannte, harmlose Fehler
Manche Fehler treten betriebsbedingt auf und sind belanglos. Dafür gibt es Ignore-Regeln, die im WebUI unter Bugtracker → Ignore-Regeln gepflegt werden. Greift eine Regel, wird der Fehler weiterhin erfasst und hochgezählt, bleibt aber aus der Übersicht heraus und löst keine Benachrichtigung aus:
{ "status": "success", "item_id": 42, "ignored": true,
"ignore_rule_id": 3, "occurrence_count": 3841, "rate_alerted": false,
"message": "Als bekannt eingestuft, gezaehlt, nicht gemeldet." }
Der Zähler ist dabei der eigentliche Zweck: Zu jeder Regel lässt sich eine
Alarmschwelle hinterlegen. Dass ein bekannter Fehler auftritt, ist normal —
dass er plötzlich hundertmal so oft auftritt, ist ein Signal. Wird die Schwelle
überschritten, meldet die Antwort "rate_alerted": true und ein Webhook
error.rate_exceeded wird ausgelöst.
9. Watchdog-Heartbeat
Läuft dein Agent als Dienst, melde dich regelmäßig:
curl -X POST https://dc.mhdf.de/api/watchdog/v1/ping \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{"source": "agent-worker-01", "status": "ok", "interval": 60,
"message": "Verarbeite Warteschlange", "metrics": {"queue": 3}}'
interval ist der erwartete Abstand in Sekunden. Bleibt der Heartbeat aus,
stuft der Evaluator den Monitor nach dem Doppelten auf warning und nach dem
Vierfachen auf down.
Eigenen Gesundheitszustand mitsenden
Ein Heartbeat beweist nur, dass ein Thread läuft — nicht, dass die Anwendung ihre Arbeit tut. Deshalb kann sie ihren Zustand selbst mitschicken:
{ "source": "polytrader-worker",
"status": "warning",
"interval": 60,
"checks": {
"db": { "ok": true },
"market_feed": { "ok": false, "message": "Letzter Tick vor 14 min" },
"queue": { "ok": true, "value": 23 }
},
"metrics": { "cpu": 18, "ram": 42, "queue_depth": 23 } }
Das Deploymentcenter interpretiert die Namen der Prüfungen nicht — es liest
nur ok und message. Was „gesund" bedeutet, entscheidet jede Anwendung
selbst. Schlägt eine Prüfung fehl, wird ein als ok gemeldeter Heartbeat auf
warning herabgestuft.
Der Weg ist bewusst ausgehend: Es müssen keine Ports auf den Zielmaschinen geöffnet werden.
Metriken
Numerische Werte aus metrics landen im Verlauf und lassen sich abfragen:
# Welche Metriken liefert dieser Monitor?
curl "https://dc.mhdf.de/api/watchdog/v1/metrics?source=polytrader-worker" \
-H "Authorization: Bearer $DC_TOKEN"
# Verlauf einer Metrik, auf 15-Minuten-Fenster verdichtet
curl "https://dc.mhdf.de/api/watchdog/v1/metrics?source=polytrader-worker&metric=queue_depth&hours=24" \
-H "Authorization: Bearer $DC_TOKEN"
Die Antwort enthält zusätzlich deviation — den Vergleich des aktuellen Werts
mit dem Durchschnitt der letzten sieben Tage desselben Monitors. Damit lassen
sich Auffälligkeiten erkennen, ohne für jedes Projekt Schwellwerte zu pflegen.
Verschachtelte Werte werden flach abgelegt: {"cpu":{"load":1.2}} wird zu
cpu.load. Rohwerte werden 14 Tage aufbewahrt.
Abhängigkeiten
Ist bei einem Monitor parent_source gesetzt und fällt der übergeordnete
Monitor aus, werden Alarme für die Kinder unterdrückt. Ihr Zustand bleibt im
Dashboard sichtbar — es entsteht nur nicht für jede VM eines ausgefallenen
Hypervisors eine eigene Meldung.
10. Verfügbarkeit prüfen
curl https://dc.mhdf.de/api/health -H "Authorization: Bearer $DC_TOKEN"
Meldet Datenbankzustand, ausstehende Migrationen, Bugtracker-Kennzahlen und wann der Watchdog-Evaluator zuletzt lief.