Admin-Dashboard (Modell / Budget / Usage)

Steuer- & Sichtfläche für die LLM-Kostengovernance aus ADR-0017. Entscheidung: ADR-0024. Gleichwertig als UI + API + MCP (AI-Parität, ADR-0018) — die Logik liegt einmalig in lib/llm/* (Single Source). Frage: siehst Du das?

Was man kann

  • Modell je Aufgabe wählen (classification, embedding, standardReport, premiumReport, pdfExtraction, toolUse, bulkParse) — Override schlägt ENV/Default, sofort wirksam (Cache-Invalidierung).
  • Budget-Cap (USD Tag/Monat) setzen — die Engine bremst fail-open bei Überschreitung (ADR-0017).
  • Ist-Kosten sehen: heute / Monat + je Task+Modell (Calls/Tokens/$).

Benutzerverwaltung & Impersonation

Eigener Admin-Bereich (ab Dashboard-Nav verlinkt), proxy.ts-gated (platform_admin + 2FA) und zusätzlich server-seitig geprüft.

  • /admin/users — Nutzerliste mit Suche (E-Mail/Name) + Rollen-Filter; pro Zeile Auge-Button (Session-Takeover, ADR-0026 v2 — wechselt in die Sicht des Nutzers mit dessen Rolle/Rechten; orange Leiste oben zeigt den Modus, dort auch „Beenden"), Kontext (read-only Inspektion via ?inspect=, auditiert) und Detail. Unten: Admin-Audit + Impersonation-Audit.
  • /admin/users/[id]Plattform-Rolle ändern (user / support / platform_admin) und Konto DSGVO-konform löschen (gleiche Erasure-Kaskade wie die Selbst-Löschung).
  • /admin/impersonate — nur noch Redirect auf /admin/users (Konsole dort integriert); die Headless-API GET/POST /api/v1/admin/impersonate bleibt unverändert.

Sicherheit (fail-closed): nur verifizierte platform_admin, nicht aus einer Impersonation heraus; kein Self-Target; kein Degradieren des letzten Admins (Lockout-Schutz); kein Löschen eines anderen Admins; Org-Owner-Guard vor der Löschung; striktes Audit vor der Löschung. Rollen-/Lösch-Eingriffe landen in admin_audit_log, Impersonation weiter in impersonation_log. Rollen-Änderungen wirken für den Ziel-Nutzer erst ab dessen nächstem Login/Token-Refresh (JWT-Sessions).

Zugänge

ZugangAuthFür
UI /adminAuth.js platform_admin + 2FA (ADR-0006, Gate in proxy.ts)Menschen
API /api/v1/admin/*API-Key mit admin-ScopeSkripte/KI
MCP get_usage/set_model/set_budgetdito (LANDNUTZEN_API_KEY)KI-Ops

Kein/ungültiger Key → 401, gültiger Key ohne Scope → 403.

Datenquellen und Drift-Überwachung

/admin/data-sources trennt weiterhin den letzten technischen Lauf vom Betriebsnachweis des tatsächlich aktiven Releases. Zusätzlich zeigt die Seite für jeden qualifizierten Active Pointer den Zustand fresh, due, stale, failed oder unknown, seine individuellen Fristen, Coverage-/Quality-Befunde, den letzten Zustandswechsel und die Alarmzustellung.

Der stündliche Cron monitor-data-source-drift verwendet das bestehende CRON_SECRET, das cron_runs-Ledger sowie die bereits eingerichtete Resend- Zustellung an POC_ADMIN_ALLOWLIST. Alarmiert werden nur neue, geänderte, verschärfte oder behobene Zustände; unveränderter Drift verursacht keine wiederholten E-Mails. Fehlgeschlagene oder nicht konfigurierte Zustellung bleibt im Dashboard sichtbar und wird beim nächsten gültigen Lauf wiederholt. Bekannte Teilabdeckung und bereits freigegebene Qualitätswarnungen sind keine neuen Vorfälle. Der Monitor verändert keinen Release und keinen Active Pointer.

/admin/cron/monitor-data-source-drift zeigt die Laufhistorie mit Beobachtungen, Übergängen, Zustellstatus und dedupliziertem Fingerprint. Die bestehende Resend-Testmodusgrenze bleibt unverändert: Vor Verifikation der Versanddomain kann nur die hinterlegte Resend-Konto-Adresse erreichbar sein.

Werkzeug-KPIs

/admin/metrics zeigt die kennungsfreien First-Party-Aggregate aus ADR-0042:

  • Aktivierungsfunnel vom ersten bewussten Formularkontakt bis zum ersten Ergebnis oder ehrlichen technischen Endzustand;
  • qualifizierte Serverläufe, Erfolgs- und Fehlerquoten;
  • p50/p95 als obere Grenzen fester Laufzeitklassen sowie die ausdrücklich als Näherung markierte Erstlauf-/Wiederverwendungs-Sicht je Serverinstanz;
  • Providerstatus, grobes Bundesland und direkt zurechenbare Providerkosten;
  • Stichprobe, erster Messtag und Reife der festen 14-Tage-Baseline einschließlich Funnel-Integrität und vollständiger Kostenzuordnung;
  • den separat ausgewiesenen, während D+1 bis D+14 fortgeschriebenen und ab D+15 eingefrorenen Ausgangswert mit denselben Funnel-, Fehler-, Provider-, Runtime-, Laufzeit- und Kostendimensionen wie die laufende Auswertung.

Es existieren keine Rohereignisse. Adresse, Koordinate, Eingabe, Ergebnis, URL, Referrer und Besucherkennungen sind weder in der Tabelle noch in der Admin-Antwort enthalten. Der tägliche Cleanup behält regulär den aktuellen und die 29 vorhergehenden Kalendertage; sein Laufstatus ist im Cron-Dashboard sichtbar. Davon getrennt bleiben der Baseline-Anker aus Tool-ID und ersten Funnel-/Server-Messtagen sowie die während D+1 bis D+14 fortgeschriebenen Dimensionsaggregate dauerhaft als Vergleichsreferenz erhalten. Mit Ablauf von D+14 ist der Snapshot vollständig und bleibt ab D+15 unverändert. Er enthält keinen Kalendertag und keine Region. Die UI nutzt Auth.js mit platform_admin und dem bestehenden 2FA-Gate.

Endpunkte

MethodePfadZweck
GET/api/v1/admin/usageUsage je Task+Modell + Spend + Budget
GET/api/v1/admin/modeleffektives Modell je Task
PUT/api/v1/admin/model{ task, model } setzen
GET/api/v1/admin/budgetBudget + Ist
PUT/api/v1/admin/budget{ dailyUsd, monthlyUsd } (null = kein Limit)
GET/api/v1/admin/metrics?days=14&tool=pv-yieldaggregierte Werkzeug-KPIs; Fenster 1/7/14/30 Tage
GET/api/v1/admin/data-sourcesQuellenkatalog, aktiver Release, pointergebundene Drift-Policy, Befunde und Alarmzustellung

MET-01-Baseline abschließen

Der revisionsfähige Abschlussprüfer liest ausschließlich die bestehenden Aggregate und gibt weder Tageswerte noch Regionen oder Besucherkennungen aus:

npm run qa:metrics:baseline -- --markdown

Vor Ablauf von D+14 endet der Befehl bewusst mit einem Fehlerstatus. Für einen reinen Zwischenstands-Readback während der laufenden Messung muss dieser Zustand ausdrücklich zugelassen werden:

npm run qa:metrics:baseline -- --markdown --allow-pending

Das Tag-30-Gate darf erst geschlossen werden, wenn der Prüfer abschlussbereit, 14/14 vollständig abgeschlossene Messtage, vorhandene Funnel- und Serverdaten, Funnel-Integrität und vollständige Kostenzuordnung meldet. Der ausgegebene SHA-256 bindet den tag- und regionsfreien Snapshot an den Nachweis.

Admin-Key erzeugen

node scripts/create-admin-key.mjs "Label"

Speichert nur den Hash (SHA-256(key+secret)); der Klartext wird einmalig ausgegeben (nicht wiederherstellbar). Scope {report, admin}. Verwendung:

curl -H "Authorization: Bearer ln_…" \
  https://www.landnutzen.at/api/v1/admin/usage

Sicherheit

Admin-Key ist mächtig: nur Hash gespeichert, Scope-getrennt, Rate-Limit/Audit wie jeder Key (ADR-0019/0023), Rotation manuell (neuen Key erzeugen, alten via revoked_at sperren). UI zusätzlich durch 2FA-Gate geschützt.