- source_meta.py kennt jetzt den echten Bestand: Kategorien telegram (107 Quellen)
und x (40), Typen x_account und pdf_document. Die 10 nie belegten
Lagen-Kategorien und der ungenutzte Typ excluded sind raus.
- Pydantic-Pattern source_type um x_account ergaenzt, excluded raus.
Behebt 422 beim Speichern von 40 X-Account-Quellen.
- Modal-Selects (Typ, Kategorie, PDF-Kategorie) werden aus /api/sources/meta
befuellt statt hartkodiert. Submit sendet category/source_type nur noch,
wenn nicht leer. Behebt stilles Loeschen der Kategorie bei Telegram-Quellen.
- source_suggester: Import auf shared.agents.claude_client angepasst
(war im Portal seit jeher kaputt, Konvention wie source_classifier).
- Toter Code raus: POST /health/run-stream (147 Z. SSE-Duplikat),
runHealthCheck() im Frontend, excluded_counts-CTE + Sperren-Spalte
(immer 0), Trend-Delta (braucht 2 Runs, es gibt 1), Alignment-Chips
(source_alignments ist leer), doppeltes formatDateTime, redundanter
setupHealthTab-Listener, toter healthContent-Zugriff.
- Tests: Kategorien-/Typen-Sets neu gepinnt, Smoke-Karteileichen entfernt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Slug ist eine rein technische Kennung und verschwindet aus Tabelle,
Kopfzeile und Anlege-Formular. Beim Anlegen wird er unsichtbar aus dem
Namen erzeugt, bei Kollision hängt das Portal selbstständig eine Nummer
an. Die Info-Zeile unter dem Org-Namen (Slug, Nutzer, Lizenz,
Kontingent) entfällt komplett, dieselben Werte stehen direkt darunter
in der Übersicht und der Bearbeiten-Karte.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Detailansicht dafür ist das Audit-Log, die Dashboard-Dublette ist
auf Nutzerwunsch raus. Bald ablaufende Lizenzen läuft jetzt volle Breite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Kachel heißt jetzt API-Kosten aktueller Monat (Läufe des Monats und
Lebenszeit-Summe klein in der Unterzeile) statt der nackten
Gesamtsumme. Datenquelle ist der Statistik-Endpoint in einem Aufruf.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Lagen werden ausschließlich im Monitor verwaltet, die Kachel im Portal
war ein reiner Zähler ohne Ziel und ist auf Nutzerwunsch raus.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Korrektur des Verbrauchszählers sitzt jetzt direkt an der Kachel
"Verbrauchte Credits", wo man den Zähler sieht, als Eingabefeld mit
Korrigieren-Knopf und Sicherheitsrückfrage. Das Feld im Kontingent-
Formular entfällt dafür. Außerdem sind die Hochzähl-Pfeile an allen
Zahlenfeldern des Portals entfernt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Auf Nutzerwunsch ist das Korrektur-Feld (Kulanz, Fehlbereinigung) jetzt
ein normales sichtbares Formularfeld neben der Warnschwelle, mit
deutlichem Hinweistext, statt in einem Aufklapp-Bereich zu stecken.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Kosten pro Credit (USD) und Budget-Limit (USD) gehörten zum
abgeschalteten Altmodus (BILLING_MODE=actual) und sind aus dem
Kontingent-Formular, dem Lizenz-Modal und der Org-Anlage entfernt.
Der Erweitert-Bereich heißt jetzt "Verbrauch korrigieren" und enthält
nur noch das Eingriffsfeld für den Verbrauchszähler. Die DB-Spalten,
die API-Felder und der Rückfallmodus im Monitor bleiben unangetastet,
falls der Altmodus je reaktiviert wird, setzt man die Werte per API.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Karte heißt jetzt "Lizenz, Nutzer & Credits-Kontingent bearbeiten"
und enthält alles Einstellbare einer Organisation untereinander,
Lizenz-Tabelle, Nutzer-Verwaltung (Limit-Anzeige, Nutzer anlegen,
Nutzerliste) und das Kontingent-Formular. Der separate Nutzer-Block
entfällt, das Org-Detail ist damit ein einziger Bereich.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zwei Rückmeldungen des Nutzers.
- Der Widerrufen-Knopf in der Lizenz-Tabelle ist raus. Eine neue Lizenz
widerruft die alte automatisch, und einen Kunden abschalten erledigt
der prominente Org-Status-Umschalter. Der API-Endpoint /revoke bleibt.
- Die Warnschwelle lässt sich jetzt abschalten, 0 = aus, in allen drei
Formularen (Budget, Neue Lizenz, Org-Anlage) samt Modell- und
Endpoint-Validierung. Gegenstück im Monitor ist Commit 17b1886
(bisher fiel eine 0 dort still auf die Voreinstellung 80 zurück).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Statt des kleinen Auswahlfelds neben dem Namen jetzt ein deutlich
sichtbarer Zwei-Knopf-Umschalter (Aktiv grün mit Haken, Deaktiviert rot
mit Sperr-Symbol), der aktive Zustand ist farbig gefüllt, Klick
speichert sofort wie bisher.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zwei Verbesserungen auf Nutzer-Rückmeldung.
- Max Nutzer war nach dem Anlegen einer Lizenz nirgends mehr änderbar.
In der aktiven Lizenz-Zeile ist es jetzt ein Zahlenfeld mit
Sofort-Speicherung (der generische Lizenz-Updater akzeptiert max_users
mit Prüfung 1 bis 1000), die Limit-Anzeige über der Nutzerliste zieht
mit.
- "Status" (Lizenz) direkt neben "Org-Status" war verwirrend. Der
Org-Status sitzt jetzt als Umschalter in der Kopfzeile der
Organisation (an der Stelle des bisherigen Abzeichens), die Tabelle
behält nur noch Lizenz-Status und Pipeline-Sprache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der frühere Bereich Einstellungen ist weg, seine Inhalte sind dorthin
gewandert, wo man sie sieht.
- Org-Status (Aktiv/Deaktiviert) und Pipeline-Sprache sind neue Spalten
in der Lizenz-Tabelle, in der aktiven Zeile direkt umschaltbar mit
Sofort-Speicherung und Toast, widerrufene Zeilen zeigen einen Strich.
- Umbenennen (kleines Modal) und Organisation löschen (mit Rückfrage)
sitzen als Knöpfe in der Kopfzeile der Organisation.
- Das Org-Detail besteht damit nur noch aus zwei Bereichen, Verbrauch &
Kontingent und Nutzer. Kein Backend-Change nötig, PUT /api/orgs/{id}
konnte Name, Status und Sprache schon immer einzeln ändern.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Auf Nutzerwunsch vier Änderungen im Org-Detail.
1. Kundensicht (Credits) und interner Einkauf (USD) stehen in EINER
Karten-Reihe (Verbraucht, Verbleibend, API-Kosten Monat). Die Karte
"Budget-Limit (USD, Altmodus)" entfällt in der Anzeige, das Feld
bleibt im Erweitert-Bereich des Formulars erhalten.
2. Die Laufzeitwerte-Karte (Übertrag, laufende Periode, Verfügbar
gesamt) ist raus. Der Übertrag bleibt im Verbleibend-Wert als
Zusatz "(inkl. X Übertrag)" sichtbar.
3. "Lizenz & Credits-Kontingent bearbeiten" steht jetzt an zweiter
Stelle direkt unter der Karten-Reihe und enthält BEIDES, die
Lizenz-Verwaltung (Tabelle, Neue Lizenz, Verlängern, Widerrufen)
und darunter das Kontingent-Formular. Der eigene Lizenzen-Block
entfällt, der Monatliche Verlauf rückt ans Ende.
4. Die Sprungmarken-Leiste (Verbrauch/Nutzer/Lizenzen/Einstellungen)
oben im Org-Detail ist entfernt, die Seite ist kurz genug.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neuer Reiter zwischen Audit-Log und Verbrauchsrechner, Anlass war die
Dashboard-Kachel API-Kosten gesamt, die nirgendwo hinführte (sie springt
jetzt hierher). Kennzahlen-Set nach Betreiber-Best-Practices für
nutzungsbasierte KI-Produkte (Kostenverlauf, Marge je Kunde, Betrieb).
- GET /api/statistik?months=N liefert alles in einem JSON. Kosten und
Läufe je Monat und Lagentyp (führende Quelle refresh_log mit
lückenlosem incidents-Join), Quellen-Split aus token_usage_monthly,
Erfolgsquote, normalisiertes Fehler-Ranking, Dauer je Typ, Wachstum,
MAU/DAU aus user_activity_days und je Organisation Ist-Kosten plus
Margen-Schätzung zu heutigen Sätzen (Recherche-Anlage zählt dreifach,
weil der Multi-Pass nur eine Log-Zeile erzeugt). Aggregation als pure,
unit-getestete Funktionen, Monatsachse lückenlos gefüllt, Mediane nur
über Läufe mit Kosten (Erfassung begann erst 03/2026).
- statistik.js injiziert sich selbst nach dem rechner.js-Muster,
Platzierung doppelt gesichert (Ladereihenfolge mit async=false plus
insertBefore). Charts als Inline-SVG ohne Bibliothek, eine Achse je
Chart, Hover-Titel mit großen Trefferflächen, Legenden, Serienfarben
je Theme mit dem dataviz-Palette-Validator geprüft (alle Checks PASS).
Zeitraum 6/12/Alles, Datenstand-Hinweis, ehrliche Fußnote unter der
Margen-Tabelle, Leerzustand für die junge Aktivitäts-Erfassung.
- Migration user_activity_days für die Portal-Staging-DB (auf Live legt
sie der Monitor an, dort läuft die Erfassung in get_current_user).
- 10 neue Unit-Tests plus Auth-Smoke für den Endpoint, 96 Tests grün
(die zwei bekannten shared-Import-Fehlschläge bestehen unverändert).
Gegenstück im Monitor: Commit d367c60 (Aktivitäts-Erfassung).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Credits-Sätze sind im Portal nicht mehr hart codiert. Neuer Endpoint
GET /api/pricing/tariff liest die geteilte Tabelle billing_tariff (mit
den beschlossenen Werten als Rückfallebene, falls die Tabelle fehlt),
PUT /api/pricing/tariff schreibt sie mit Validierung und Audit-Eintrag.
- Die Infozeile im Verbrauch-Bereich rendert ihre Zahlen aus der Tabelle,
der statische Text bleibt nur als Rückfallebene stehen.
- Die Rechner-Regler starten auf den aktiven Preisen, der Hinweis nennt
die tatsächlich abgerechneten Sätze, und der neue Knopf "Diese Sätze
als aktive Preise speichern" schreibt sie nach Rückfrage in die
Tabelle. Der Monitor bucht ab der nächsten Aktion mit den neuen Werten.
- Migration migrations/2026-07-25_billing_tariff.py für die eigene
Staging-DB (auf Live legt die Tabelle der Monitor an und befüllt sie
mit seinen wirksamen Konfigurationswerten).
Gegenstück im Monitor: Commit 027244a (billing_tariff als Quelle der
Buchung). Promote-Reihenfolge bleibt, erst Monitor, dann Verwaltung.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drei Vereinfachungen auf Nutzerwunsch.
1. Das Org-Detail hat keine Unterreiter mehr. Verbrauch & Kontingent,
Nutzer, Lizenzen und Einstellungen stehen untereinander auf einer
Seite (Verbrauch optisch zuerst, per CSS-Order ohne Block-Verschiebung),
die bisherigen Reiter sind Sprungmarken, die nur scrollen. Alle
Bereiche laden sofort, der Org-Kopf zeigt den Kontingent-Stand als
Kurzinfo.
2. Die Organisations-Tabelle bekommt eine Kontingent-Spalte mit
Verbraucht/Verfügbar und Mini-Balken (gelb ab 50, rot ab 80 Prozent),
Datenquelle ist die vorhandene Overview-API. Ganze Zeile klickbar.
3. Der globale Hauptreiter "Lizenzen" entfällt, er zeigte nur die
Ablauf-Liste, die bereits auf dem Dashboard steht. Die Einträge dort
öffnen jetzt direkt die jeweilige Organisation, die Kachel "Aktive
Lizenzen" führt zur Organisations-Verwaltung. loadExpiringLicenses
bleibt als abgesicherter No-op für Alt-Aufrufer erhalten.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Statistik-Kacheln springen jetzt zu ihren Zielen. Organisationen und
Nutzer zur Organisations-Verwaltung, Aktive Lizenzen zum Lizenzen-Tab,
Vorfälle öffnen den Monitor in einem neuen Tab (im Portal gibt es keine
Vorfalls-Seite). Die Karte "Bald ablaufende Lizenzen" führt zum
Lizenzen-Tab, "Letzte Aktivität" zum Audit-Log. Hover-Optik mit
Gold-Rahmen und Chevron, bedienbar auch per Tastatur (Enter/Leertaste).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drei Pakete auf Nutzerwunsch.
1. Design-Angleichung an das AegisSight-Design-System. Navy/Gold-Token
statt Slate/Amber, Light- UND Dark-Theme mit goldenem Schiebeschalter
oben rechts (Dark = Standard, Wahl persistiert), Barrierefreiheits-
Panel über js/a11y.js (identische Datei wie im Monitor), echtes Logo
mit heller Plakette in Kopfzeile und Login, Poppins/Inter-Typografie,
Radius 6/8 nach Styleguide. Automatisch erzeugte Light-Theme-
Überschreibungen für alle Badge-Pastelltöne.
2. Lucide-Icons (Inline-SVG, keine externen Quellen) für alle
Navigations-Tabs inkl. nachgeladenem Verbrauchsrechner, die
Anlege-Knöpfe, Abmelden und Speichern.
3. Verbrauchs-Bereich aufgeräumt. Reiter heißt jetzt Verbrauch,
Statistik in Kundensicht (Credits) und Interne Kosten (Einkauf, USD)
getrennt, Leiste heißt Kontingent-Auslastung, Sätze-Infozeile mit
Sprung zum Verbrauchsrechner, Altmodus-Felder (USD) und die
Verbrauchs-Korrektur liegen in einem eingeklappten Bereich
Erweitert mit Erklärtext. Der Rechner trägt einen deutlichen
Simulations-Hinweis. Lizenz verlängern nutzt ein eigenes Modal
statt des Browser-prompt().
Cache-Buster auf 20260725 gebumpt, alle Restfarben tokenisiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Auf Nutzerwunsch findet ohne bewusste Entscheidung kein Übertrag statt.
Modell-Default, beide Checkboxen (Lizenz-Modal, Org-Modal) und der
Modell-Test stehen jetzt auf aus, der Übertrag bleibt pro Kunde
zuschaltbar. Der DB-Spalten-Default stand ohnehin schon auf 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bedienseite für das Credits-Monatskontingent des Monitors. Das Portal
setzt jetzt alle Stellwerte, der Monitor bleibt Herr der Laufzeitfelder.
- Lizenz-Modal und Budget-Formular um Abrechnungszeitraum (monthly/total),
Übertrag-Checkbox und Warnschwelle erweitert, Vorbelegungen auf das
beschlossene Modell (10.000 Credits, monatlich, Übertrag an, 0,20 USD).
- Neue Organisation kann direkt eine Lizenz mit Kontingent anlegen
(OrgCreate.license, verschachtelt). Org- und Lizenz-Insert laufen in
EINER Transaktion, schlägt der Lizenz-Teil fehl, entsteht keine
halbe Organisation. Gemeinsamer Helper insert_license_row statt
Duplikation der Widerruf- und Audit-Logik.
- PUT /api/token-usage/budget validiert credits_period (monthly|total)
und budget_warning_percent (1 bis 100), credits_rollover wird wie
unlimited_budget normalisiert. Laufzeitfelder bleiben bewusst
außerhalb der Whitelist.
- Overview und Org-Detail rechnen den Rest jetzt gegen verfügbar =
Kontingent + Übertrag, dieselbe Bezugsgröße wie der Hard-Stop im
Monitor. Neuer read-only Block Laufzeitwerte im Token-Subtab.
- Startup-Check loggt einen deutlichen Fehler, wenn die licenses-Tabelle
die Credits-Spalten noch nicht hat (falsche Deploy-Reihenfolge).
- Migration migrations/2026-07-25_credits_period.py (idempotent,
wortgleich mit der Monitor-Migration) für die Portal-Staging-DB,
auf Live gilt: Monitor VOR Portal promoten.
- 13 neue Modell-Tests, pytest grün (die zwei bekannten
shared-Import-Fehlschläge bestehen unverändert seit vorher).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neuer Router pricing.py (GET /api/pricing/cost-basis), liest die geteilte
Live-DB read-only und liefert Median-Kosten je Lagentyp plus Credit-Empfehlung.
main.py um den Router erweitert. Frontend rechner.js mit Reglern statt fester
Saetze und Empfehlungsanzeige je Aktion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Eigenstaendiges Modul rechner.js, injiziert Tab, Bereich und Styles selbst.
dashboard.html und main.py bleiben unveraendert, damit der Staging-Deploy
nicht mit dem lokalen KB-Arbeitsstand kollidiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neuer Sub-Tab "X-Recherche-Konten" unter Quellen: die X-Login-Konten,
mit denen der Monitor bei X scrapt (twscrape-Account-Pool), anzeigen,
hinzufuegen, Cookies erneuern, aktiv/inaktiv schalten, entfernen, plus
Sperren-Reset.
- neuer Router x_scraper.py, verwaltet den twscrape-Pool ueber dessen API
- X_ACCOUNTS_DB_PATH in config.py
- twscrape als Abhaengigkeit (git-main-Pin)
- Sub-Tab, Tabelle und zwei Modals in dashboard.html, Logik in x-scraper.js
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neuer Sub-Tab "X-Accounts" unter Quellen: die als Recherchequelle
eingebundenen X-Accounts anzeigen, hinzufuegen, bearbeiten und entfernen.
Schreibt source_type=x_account in die geteilte sources-Tabelle, von wo
der Monitor sie pro Lage nutzt.
- x_account im source_type-Pattern von GlobalSourceCreate/Update
- primary_language in Create/Update plus INSERT (Keyword-Matching)
- x_account-Typ und x-Kategorie in source_meta.py
- Sub-Tab, Tabelle und Modal in dashboard.html, Logik in sources.js
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fremdsprachige Artikel ohne deutsche Fassung lassen sich jetzt manuell
über das Verwaltungs-Dashboard übersetzen. Hintergrund: die automatische
Übersetzung im Monitor wurde deaktiviert (TRANSLATOR_ENABLED=false),
nachdem ein sehr großer Lauf den Refresh-Worker blockiert hatte.
- translation_agent.py: Verwaltungs-Adaption des Monitor-Translators
(Haiku-Batches), Imports auf shared.agents.claude_client umgestellt
- routers/translation.py: Endpoints /api/translation/status, /run und
/cancel. Der Lauf läuft als entkoppelter Hintergrund-Task, blockiert
keinen Request und ist jederzeit abbrechbar
- Dashboard-Karte mit Fortschrittsbalken, Aufwandsschätzung vorab und
Abbrechen-Button
- test_imports.py: neuen Router in den Smoke-Test aufgenommen
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Single Source of Truth (source_meta.SOURCE_CATEGORIES) um den Eintrag
"Forum / Stimmungsbild" erweitert. Wird vom Frontend ueber /api/sources/meta
geladen und in den Filter-Dropdowns angezeigt.
Hintergrund: jp_demo nutzt 5ch (Phase 2), Hatena Bookmark und Note Trending
als anonyme Foren-Quellen fuer eine eigene Stimmungs-Kachel im Monitor.
Diese Quellen bekommen in der DB category='stimmungsbild' + media_type='forum',
sodass sie aus dem Faktencheck rausfallen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bisheriger Default /home/claude-dev/.claude/local/claude existiert auf dem
Live-Server nicht. Folge: jeder call_claude im verwaltungsportal stirbt mit
FileNotFoundError [Errno 2]. Konkret betroffen: bulk_classify (alle Quellen-
Klassifizierungen schlugen still fehl bzw. brachen nach der ersten Quelle ab).
Live wurde uebergangsweise per CLAUDE_PATH-Env in /home/claude-dev/AegisSight
-Monitor-Verwaltung/.env ueberschrieben. Dieser Commit zieht den Fix in den
Code, damit der Default auch ohne .env-Override funktioniert (bzw. die .env-
Zeile spaeter wieder entfernt werden kann).
Monitor-config.py:30 hat einen abweichenden Default (/usr/bin/claude) —
nicht in diesem Commit angefasst, da Monitor heute funktioniert; getrennt
nachhalten falls auch dort Drift auftritt.
Die Anfuehrungszeichen waren beim Einfuegen verloren gegangen
(onclick="closeModal(modalPdfUpload)" statt closeModal())
-> Browser warf ReferenceError und der Klick blieb wirkungslos.
Mit ' (HTML-Entity-Apostroph) im Attribut-Wert eindeutig.
- OrgCreate / OrgUpdate / OrgResponse um output_language (de | en).
- routers/organizations.py persistiert die Sprache nach create/update
via shared.services.org_settings.set_org_setting.
- _enrich_org liest output_language aus organization_settings (Default de).
- Frontend: Dropdown im Modal Neue Organisation und im Org-Edit-Formular,
Auto-Befuellung aus org.output_language. Cache-Buster auf app.js gebumpt.
Phase 7 von 8 (eng_demo / Org-Sprache).
Helper aus AegisSight-Monitor/src/services/org_settings.py uebernommen.
Wird in Phase 7 vom Verwaltungs-Org-Router verwendet, um output_language
beim Org-Anlegen/Bearbeiten zu setzen.
Phase 1 von 8 (eng_demo / Org-Sprache).
Service-Module (source_classifier, external_reputation) liegen jetzt in shared/services/, Endpoints unter /api/sources/classification/* sind hier statt im Monitor:
- classification/{stats,queue,bulk-classify,bulk-approve}
- {id}/classification/{approve,reject,reclassify}
- external-reputation/sync
modalSource erweitert um Klassifikations-Section (Politik, Medientyp, Reliability, state-affiliated, Land, 12 Alignment-Chips). Neuer Sub-Tab Klassifikation mit Review-Queue, Pending-Counter, Bulk-Actions. Auth via get_current_admin, Audit-Logging.
Begleit-Refactor: Monitor verliert die Klassifikations-UI/-Endpoints separat.
Drei zusammenhaengende Verbesserungen am Quellen-Health-Bereich:
1. shared/services/source_suggester.py:
- sync mit Monitor commit 49c5572.
- Neue Funktion generate_strategy_escalation_suggestions: erzeugt
deactivate-Vorschlaege fuer Quellen mit fetch_strategy=googlebot|
paywall, deren Reachability-Check trotzdem error meldet.
2. source-health.js: Loesung-suchen-Button erweitert.
Bisher nur bei status=error AND check_type=reachability. Jetzt auch
bei status=warning AND check_type=feed_validity (z.B. "Feed
erreichbar aber leer"). Backend-Endpoint /api/sources/health/
search-fix wird in beiden Faellen aufgerufen, Claude sucht eine
bessere URL fuer die Quelle.
3. source-health.js: Trend-Delta im Counter.
Liest healthHistoryCache[1] (vorletzter Run) und vergleicht mit
aktuellen errors/warnings/ok. Zeigt z.B. "3 Fehler (+2)" rot oder
"143 Warnungen (-15)" gruen. Bei steigenden ok-Counts ist Plus
gruen, bei steigenden Fehlern ist Plus rot. Wenn der vorletzte
Run nicht verfuegbar (Initial-Lauf): kein Delta.
Cache-Buster source-health.js auf 20260509l gebumpt.
Spiegelung von AegisSight-Monitor commit d973dc7. Identische Datei
(Pre-Commit-Hook prueft Drift gegen Monitor-Master = 0).
Neue Funktion generate_stale_deactivation_suggestions wird beim
manuellen Health-Check-Run ueber das Verwaltungsportal-UI aufgerufen
(/api/sources/health/run-stream am Ende). Karteileichen-Quellen
landen damit im Vorschlaege-Tab als deactivate_source-Vorschlaege
und koennen per Klick angenommen werden.
Der globale setupNavTabs in app.js fing nav-tab-Clicks aus ALLEN
nav-tabs ab, ausser #orgDetailTabs und #sourceSubTabs. Das neue
#healthSubTabs (aus dem letzten Commit) war nicht in der :not()-
Liste und triggerte daher den Top-Level-Handler, der getElementById("sec-suggestions")
suchte und null bekam -> Crash beim classList.add("active").
Fix: :not(#healthSubTabs) ergaenzt an allen drei Stellen
(setupNavTabs, setupNavTabs Click-Handler, openSection-Helfer in Z. 408).
Cache-Buster fuer app.js gebumpt 20260509d -> 20260509j.
Splittet die Quellen-Health-Section in drei eigene Sub-Tabs auf, damit
der User je nach Aufgabe nur den relevanten Bereich sieht und nicht
durch die ganze Seite scrollen muss.
dashboard.html:
- Innerhalb von <div id=sub-source-health>: neue nav-tabs healthSubTabs
mit drei Buttons (Vorschläge / Health-Status / Verlauf).
- Drei Pane-Container ht-suggestions / ht-checks / ht-verlauf,
jeweils per inline-style display kontrolliert.
source-health.js:
- setupHealthSubTabs(): Click-Handler fuer den Tab-Wechsel
(toggle .active auf den Buttons + display none/block auf den Panes).
- renderHealthDashboard splittet jetzt in drei innerHTML-Calls,
einen pro Pane:
paneSuggestions <- Vorschlaege offen
paneChecks <- Counter + Filter + Tabelle + Mehr-laden
paneVerlauf <- erledigte Vorschlaege + Run-Verlauf
- Tab-Label "Vorschlaege" wird mit Counter angereichert (z.B.
"Vorschlaege (24 offen)"), wenn welche offen sind.
- LUCIDE_ICONS-Konstante mit Inline-SVG fuer check, x, search,
refresh. Emojis und HTML-Entities (✓ × ) ersetzt.
Inline-SVG statt CDN-Library, damit keine externe Abhaengigkeit.
Cache-Buster fuer source-health.js auf 20260509i gebumpt.
Vier UX-Hebel zusammengelegt, alle reines Frontend:
1. Vorschlaege-Tabelle: Beschreibung als Einzeiler mit Ellipsis;
voller Text im title-Tooltip. Spart bei 24 offenen Vorschlaegen
~25 Bildschirmhoehen.
2. Verlauf-Card: standardmaessig eingeklappt via <details>-Element.
Header zeigt nur "Verlauf (N erledigte Vorschlaege - klick zum
Aufklappen)". Klick expandiert die Tabelle.
3. Health-Tabelle: Spalten Domain und Sprache aus der Tabelle raus,
beide als Tooltip auf dem Quellen-Namen. Tabelle hat statt 8
Spalten nur noch 6, ist schmaler und besser lesbar.
4. Aktionen-Spalten: Text-Buttons ("Annehmen", "Ablehnen", "Lösung
suchen") durch kompakte Icon-Buttons ersetzt (✓ ✗ 🔍).
Funktion identisch, Tooltip via title-Attribut.
Cache-Buster fuer source-health.js auf 20260509h gebumpt.
Frontend ruft ausschliesslich /health/run-stream auf. Der Legacy-Endpoint
/health/run war ein simples synchrones Pendant ohne Fortschrittsanzeige
und wurde nirgends mehr aufgerufen (verifiziert via grep -r im Repo).
Schritt 2 der Quellen-Health-Aufraeumung. Reine Code-Saeuberung,
keine UX- oder Backend-Verhaltensaenderung.
Schritt 1 der Quellen-Health-Aufraeumung. Drei UX-Verbesserungen, kein Daten-Eingriff:
1. Default-Filter "Nur Probleme" (errors + warnings, ohne OK).
- Neuer Status-Filter-Wert "issues" als virtuelles Frontend-Konstrukt.
- applyHealthFilter behandelt "issues" als status != ok.
- Default in healthFilters ist jetzt "issues". User sieht beim
Tab-Klick sofort die kritischen 146 Eintraege statt der 281
gruenen OK-Zeilen.
2. Counter aufgegliedert nach check_type.
- Backend (/api/sources/health): zusaetzliches Feld "breakdown"
mit der GROUP-BY (check_type, status) Aggregation.
- Frontend rendert pro Status-Zeile die feine Aufschluesselung,
z.B. "143 Warnungen (112 Aktualität, 27 Feed-Validität, 3 Duplikat,
1 Erreichbarkeit)".
- Hilft dem Admin, sofort zu sehen wo das Problem liegt.
3. Filter-Hint bei Pagination + leeren Treffern.
- Wenn der aktuelle Filter ueber die geladenen 100 Items keinen
Treffer findet UND has_more=true, zeigt das Frontend einen
Hinweis-Link "Alle X Health-Checks laden und Filter erneut
anwenden".
- Loest das Edge-Problem, dass z.B. Filter "Nur OK" auf den
Default-100 (errors first) leer schien.
Cache-Buster fuer source-health.js auf 20260509g gebumpt.
Tab-Button "Quellen-Health" verlinkte auf eine Sub-Section, die
es im DOM gar nicht gab:
- <button data-subtab="source-health"> existierte bereits
- <div id="sub-source-health"> fehlte komplett
- <div id="healthContent"> (Render-Anker für source-health.js) fehlte
ebenfalls
Folge:
1. sources.js Click-Handler crashte mit
"Cannot read properties of null (reading classList)" beim Versuch,
die Sub-Section auf .active zu setzen
2. loadHealthData() lief zwar (über separaten Listener in
source-health.js) und der Backend-Call ging durch, aber
renderHealthDashboard fand kein #healthContent und brach still ab
(if (!container) return). Nutzer sah niemals Inhalt.
Fix: Sub-Section <div id="sub-source-health"><div id="healthContent">
zwischen sub-tenant-sources und der Audit-Section eingefügt. Außerdem
das ohnehin fehlende </div> für sec-sources sauber geschlossen.
Damit löst sich das gefühlte "Quellen Health lädt minutenlang":
beim Klick wird der Tab korrekt aktiviert, der Render landet in
#healthContent und ist dank der Pagination + Cache aus den letzten
zwei Commits sofort sichtbar.
Echter Bottleneck war der DOM-Render von 519 Tabellen-Zeilen, nicht
das Backend (45ms). Backend-Slim und Cache aus dem letzten Commit
haben Bandbreite und wiederholte Klicks beschleunigt, aber der erste
Klick blieb langsam, weil weiterhin alle 519 Items in einem
innerHTML-Schub gerendert wurden.
Lösung: Server-Side-Pagination.
Backend (/api/sources/health):
- Neue Query-Param: limit (default 100, max 5000), offset (default 0)
- Counters errors/warnings/ok/total_checks aus separater GROUP-BY-
Aggregat-Query über den GESAMTEN Bestand, nicht über die Page.
- Neues Feld all_orgs in der Antwort: alle Tenants mit Health-Checks,
damit das Filter-Dropdown auch im Pagination-Modus die volle
Org-Liste hat.
- Neue Felder limit, offset, has_more.
Frontend (source-health.js):
- healthLoadLimit (default 100), wird durch loadMoreHealth() um 200
hochgesetzt oder durch loadAllHealth() auf alles gesetzt.
- Cache-Key beinhaltet jetzt auch das aktuelle Limit, damit beim
Mehr-laden nicht aus altem Cache bedient wird.
- Org-Liste kommt aus healthData.all_orgs statt aus den geladenen
Page-Items, sonst wäre sie nach Pagination unvollständig.
- Footer mit zwei Buttons ("+200 laden", "Alle N weiteren laden")
unter der Tabelle, nur sichtbar bei has_more=true.
- Counter-Anzeige: "X / Y angezeigt (von Z insgesamt)".
Cache-Buster für source-health.js auf 20260509f gebumpt.
Tab "Quellen Health" lädt deutlich schneller:
1. /api/sources/health: SELECT reduziert auf nur die im Frontend wirklich
gerenderten Felder. Weg sind: h.id, s.url, s.source_type, s.category,
s.bias, h.details, h.checked_at. Response-Größe sinkt damit von ~198 KB
auf grob die Hälfte (bei 519 Health-Checks) ohne UI-Verlust.
2. source-health.js: 60-Sekunden In-Memory-Cache fürs loadHealthData.
Tab hin und her klicken ist damit instant statt jedes Mal voller
Reload + Render der 519 Tabellen-Zeilen.
Bei Mutationen (Vorschlag annehmen/ablehnen, run-stream beendet,
search-fix) wird mit loadHealthData(true) der Cache umgangen,
damit frische Daten gezeigt werden.
3. dashboard.html: Cache-Buster für source-health.js auf 20260509e gebumpt.