- check_license() liefert jetzt unlimited_budget, credits_total, credits_used,
read_only_reason. Bei nicht-unlimited UND credits_used >= credits_total wird
status=budget_exceeded, read_only=True gesetzt.
- require_writable_license blockiert mit 403 + X-License-Status-Header je nach Reason.
- /api/auth/me liefert read_only_reason und unlimited_budget; credits_percent_used
wird nicht mehr auf 100 gekappt (echte Prozente).
- Frontend: Banner-Text dynamisch je nach reason (budget_exceeded/expired/...).
Refresh-Button bei read_only deaktiviert + Tooltip. Globaler 403-Handler in
api.js: bei X-License-Status -> Banner + Toast aktualisieren.
Neuer Tab "Analysepipeline" zwischen Faktencheck und Quellenuebersicht.
Zeigt 9 Verarbeitungsschritte als n8n-artige Blockkette: Quellen sichten,
Nachrichten sammeln, Doppeltes filtern, Relevanz bewerten, Orte erkennen,
Lagebild verfassen, Fakten pruefen, Qualitaetscheck, Benachrichtigen.
- Backend: refresh_pipeline_steps-Tabelle persistiert pro Refresh+Pass die
Status- und Zahlen-Werte. pipeline_tracker.py kapselt Start/Done/Skip/Error
inkl. WebSocket-Broadcast (Event-Typ pipeline_step). 9 Hooks im Orchestrator
speisen die Anzeige.
- API: GET /api/incidents/{id}/pipeline liefert Definition + letzten Stand
(Zahlen aus letztem Refresh, Multi-Pass-Konsolidierung).
- Frontend: pipeline.js rendert Vollbild-Blockkette mit pulsierendem Glow am
aktiven Block, animierten Pfeilen bei Datenfluss, Haekchen am fertigen Block.
Hover-Tooltip mit Erklaerung in Nutzersprache, Klick oeffnet Detail-Popup.
Bei Research-Lagen leuchtet ein Schleifen-Pfeil pro Mehrfach-Durchlauf auf.
Mini-Variante (nur Icons) im Refresh-Progress-Popup.
- CSS: Light/Dark-Theme-fest, dezenter Circuit-Hintergrund (5% Opacity),
Mobile-vertikale Stapelung unter 900px, prefers-reduced-motion respektiert.
- Uebersprungene Schritte (z.B. Geoparsing ohne neue Artikel) werden
ausgeblendet, brandneue Lagen ohne Refresh zeigen Hinweis.
Tooltips bewusst in normaler Sprache ohne Internas (keine Modellnamen,
keine Toolnamen, keine Phasen-Labels).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Neue Exception-Klasse ClaudeCliError(error_type, message) in claude_client.py
mit Kategorien rate_limit / auth_error / timeout / cli_error.
- _classify_cli_error() als geteilter Klassifikator (Keywords fuer Rate-Limit
und Auth-Fehler wie "does not have access", "login again").
- call_claude() erkennt jetzt auch is_error=true im JSON bei returncode=0
(Hauptursache des Ausfalls vom 22.04.: CLI liefert "Your organization
does not have access" mit is_error=true statt Exit-Code).
- Orchestrator: ClaudeCliError mit rate_limit/timeout als transient behandelt
(3 Retries mit Backoff 0s/120s/300s). auth_error/cli_error brechen sofort
ab ohne Retry. Behebt den bestehenden Bug, dass Rate-Limit-Fehler gar nicht
retried wurden.
- routers/incidents.py Enhance-Endpoint: ClaudeCliError wird auf
503 (auth_error) / 429 (rate_limit) gemappt, TimeoutError auf 504.
- routers/chat.py _call_claude_chat(): wirft jetzt ClaudeCliError statt
generischem RuntimeError. Chat-Endpoint mappt auth_error auf 503.
- Frontend: neue ApiError-Klasse in api.js mit status+detail.
generateDescription() in app.js zeigt differenzierte Toasts nach
HTTP-Status (503/429/504/403).
- dashboard.html: Cache-Bust api.js + app.js auf v=20260423a
Backend:
- GET /{id}/articles paginiert jetzt per limit/offset (Default 500,
Max 1000) und unterstuetzt optionalen search-Parameter (LIKE ueber
headline/source/content). Response-Shape: {total, articles}.
- Neuer Endpunkt GET /{id}/articles/sources-summary liefert pro Quelle
{source, article_count, languages} sowie language_counts gesamt —
serverseitige Aggregation, unabhaengig von Artikel-Paginierung.
- Neuer Endpunkt GET /{id}/articles/timeline-buckets?granularity=hour|day|week|month
aggregiert Artikel + Snapshot-Counts pro Zeitbucket (fuer spaetere
Timeline-Zaehler ueber die volle Historie).
- database.py: Index idx_articles_incident_collected auf
(incident_id, collected_at DESC) fuer schnelleres ORDER BY + Pagination.
Frontend:
- api.js: getArticles({limit, offset, search}),
getArticlesSourcesSummary(), getArticlesTimelineBuckets().
- app.js: loadIncidentDetail laedt erste Seite (500 Artikel), startet
_loadSourcesSummary parallel und zieht restliche Artikel
batchweise (500er Bloecke) im Hintergrund nach, bis _currentArticlesTotal
erreicht ist. rerenderTimeline nach jedem Batch.
- components.js: renderSourceOverviewFromSummary(data) rendert aus
Aggregat-Daten (ersetzt clientseitige Zaehlung ueber geladene Artikel).
Hintergrund: /articles lieferte bei der Iran-Lage 22 MB (17.286 Artikel
mit SELECT *). Die Erstantwort sinkt auf ~650 KB (500 Artikel), weitere
werden progressiv im Hintergrund nachgeladen. Quellenuebersicht zeigt
dank Aggregat-Endpunkt sofort alle Quellen + Sprachen komplett.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend:
- GET /{id}/snapshots liefert nur noch schlanke Shape (Metadaten +
SUBSTR(summary,1,300) AS summary_preview), kein Volltext, kein sources_json.
- Neuer Endpunkt GET /{id}/snapshots/{snapshot_id} fuer Volltext-Lazy-Load.
- Neuer Endpunkt GET /{id}/snapshots/search?q=... fuer serverseitige
Volltextsuche ueber alle Snapshots einer Lage.
Frontend:
- api.js: getSnapshot() und searchSnapshots() ergaenzt.
- app.js: _snapshotFullCache, Volltext wird beim Aufklappen eines
Snapshot-Eintrags per lazyLoadSnapshotDetail() nachgeladen und gecacht.
- Suche ueber Snapshots filtert weiterhin clientseitig ueber summary_preview.
Hintergrund: Bei grossen Lagen (Iran-Lage: 347 Snapshots) fiel die
Snapshots-Listenantwort mit Volltext-Summaries auf ~54 MB. Die Liste
faellt damit auf ~150 KB; Volltexte werden nur on-demand geladen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ermoeglicht dem Global Admin (is_global_admin Flag) zwischen
Organisationen zu wechseln. Neue Endpoints: GET /api/auth/organizations,
POST /api/auth/switch-org. Org-Dropdown im Header-Menue, nur fuer
Global Admin sichtbar. Komplett herausnehmbar (Flag + Code-Bloecke).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
KI-gestütztes Prompt Enhancement: Button generiert per Haiku aus dem
Titel eine strukturierte Beschreibung. Unterscheidet zwischen
Live-Monitoring (kompakte Vorfallsbeschreibung) und Recherche
(strukturiertes Briefing mit Schwerpunkten und Suchbegriffen).
- Neuer Endpoint POST /api/incidents/enhance-description
- Button erscheint für beide Lage-Typen, aktiv ab 3 Zeichen Titel
- Info-Hinweis wechselt je nach Typ mit Beispiel
- Spinner-Animation während der Generierung
- Neuer Router /api/tutorial mit GET/PUT/DELETE für Fortschritt pro User
- DB-Migration: tutorial_step + tutorial_completed in users-Tabelle
- Resume-Dialog bei abgebrochenem Tutorial (Fortsetzen/Neu starten)
- Chat-Hinweis passt sich dem Tutorial-Status dynamisch an
- API-Methoden: getTutorialState, saveTutorialState, resetTutorialState
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- File input in feedback modal (max 3 images, 5 MB each)
- Frontend validation for file count and size
- Backend: multipart/form-data with UploadFile, MIME attachments
- Images attached to feedback email as base64-encoded attachments
- Only JPEG and PNG allowed (validated server-side)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Neue Tabelle user_excluded_domains für benutzerspezifische Ausschlüsse
- Domain-Ausschlüsse wirken nur für den jeweiligen User, nicht org-weit
- user_id wird durch die gesamte Pipeline geschleust (Orchestrator → Researcher → RSS-Parser)
- Grundquellen (is_global) können nicht mehr bearbeitet/gelöscht werden im Frontend
- Grundquelle-Badge bei globalen Quellen statt Edit/Delete-Buttons
- Filter Von mir ausgeschlossen im Quellen-Modal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Endpunkt startet async Background-Task statt synchron zu warten
- Batch-Verarbeitung (50 Artikel pro Batch)
- Neuer Status-Endpunkt GET /incidents/{id}/geoparse-status
- Frontend pollt alle 3s und zeigt Fortschritt im Button (z.B. "150/427 Artikel...")
- Kein Timeout-Problem mehr bei grossen Lagen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Neues Geoparsing-Modul (spaCy NER + geonamescache/Nominatim)
- article_locations-Tabelle mit Migration
- Pipeline-Integration nach Artikel-Speicherung
- API-Endpunkt GET /incidents/{id}/locations
- Leaflet.js + MarkerCluster im Dashboard-Grid
- Theme-aware Kartenkacheln (CartoDB dark / OSM light)
- Gold-Akzent MarkerCluster, Popup mit Artikelliste
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Die Toggle-Switches im Lage-Modal (Anlegen/Bearbeiten) waren nicht
mit den API-Endpunkten verbunden. Jetzt werden die Subscription-
Einstellungen korrekt geladen, gespeichert und zurueckgesetzt.
- api.js: getSubscription() und updateSubscription() hinzugefuegt
- app.js: handleFormSubmit() speichert Subscription nach Create/Edit
- app.js: handleEdit() laedt bestehende Subscription beim Oeffnen
- app.js: openModal() setzt Checkboxen im Create-Modus zurueck