Reset scrollTop on summary-content and factcheck-list containers
so scroll position from previous incident is not preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents brief flash of previous incident content (Lagebild,
Faktencheck, Quellen, Timeline, title) while new data loads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The double-rAF callbacks from resizeTileToContent fire after the
initial scrollTop=0 reset. Add a scroll event listener that forces
scrollTop=0 during the entire rendering phase, then remove it after
3 animation frames (covering all double-rAF resize callbacks).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove grid-stack-animate class before rendering to prevent CSS
transitions from causing browser scroll-follow to repositioned tiles.
Re-enable animation after content is loaded and scroll is reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Der Scroll zum Faktencheck wurde durch den display:none->flex Wechsel
und/oder GridStack-Init ausgeloest. overflow:hidden wird jetzt ganz
am Anfang von selectIncident gesetzt, BEVOR das incident-view
sichtbar wird. Erst 500ms nach Abschluss aller Render-Operationen
wird overflow wiederhergestellt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scroll-Event-Listener setzt scrollTop=0 bei jedem Scroll-Versuch
waehrend 500ms nach dem Laden. Verhindert zuverlaessig, dass
GridStack, Leaflet oder Fokus-Aenderungen den View verschieben.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
overflow:hidden bleibt 300ms nach loadIncidentDetail aktiv, damit
die verzögerten GridStack resizeTileToContent-Operationen keinen
Scroll zum Faktencheck ausloesen koennen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Statt den Scroll nach unten mit Timeouts zurueckzukaempfen, wird
overflow:hidden auf main-content gesetzt bevor das Rendering startet.
Nach Abschluss wird scrollTop=0 gesetzt und overflow wiederhergestellt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scroll-Reset erfolgt nun an 4 Zeitpunkten um sicherzustellen, dass
der Hauptbereich nach oben scrollt, auch wenn GridStack oder andere
asynchrone Rendering-Operationen den Scroll verschieben.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Modal (Anlegen/Bearbeiten) schliesst nur noch ueber den X-Button,
nicht mehr durch Klick auf den dunklen Hintergrund
2. Beim Anklicken einer Lage in der Sidebar scrollt der Hauptbereich
nach oben statt zum Faktencheck-Bereich
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gleicher Bug wie bei der Summary: Wenn die Claude-API-Analyse keine Quellen
zurueckgibt, wurde sources_json mit NULL ueberschrieben. Dadurch konnten die
Quellenverweise [1], [2] etc. im Dashboard nicht mehr als Links gerendert werden.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regel in alle 4 Analyse-Prompt-Templates eingefuegt: Claude soll keine
Gedankenstriche verwenden, sondern Kommas, Doppelpunkte oder neue Saetze.
Bestehende Dashes in DB (Summary + 76 Snapshots) bereinigt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wenn die Claude-API-Analyse keinen oder einen leeren Summary zurueckgibt,
wird jetzt die vorherige Summary beibehalten statt mit einem leeren String
ueberschrieben zu werden.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Antworten mit ```json ... ``` Wrapping werden korrekt geparst.
Verhindert den Verlust von Analyse-Ergebnissen bei inkrementellen Refreshes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Neuer Zwei-Phasen-Faktencheck: Haiku-Triage identifiziert betroffene Fakten,
dann parallele Opus-Verifikation pro thematischer Gruppe (max 8 Fakten/Gruppe)
- Analyse und Faktencheck laufen jetzt parallel via asyncio.gather
- Snapshot-Erstellung vor parallele Verarbeitung verschoben
- Fallback auf Standard-Faktencheck bei Triage-Fehler
- Erwartete Verbesserung: ~19 Min -> ~8 Min pro Refresh bei gleichbleibender Qualität
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Behebt falsche Geocodierung bei Laendernamen die auch als Staedte
existieren (Lebanon->US statt Libanon, Jordan->HK statt Jordanien).
- Laender-Aliase (50+ deutsch/englisch) werden zuerst geprueft
- geonamescache Laendersuche vor Staedtesuche
- Stadtsuche in eigene _geocode_city() Funktion extrahiert
- Bestehende falsche Marker in DB korrigiert
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_validate_facts() prueft nach dem Parsen: confirmed/established ohne
URL in der Evidenz wird zu unconfirmed/unverified herabgestuft.
183 bestehende confirmed-Fakten ohne URL wurden ebenfalls korrigiert.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PRAGMA busy_timeout=5000 in get_db() hinzugefügt (SQLite wartet bis zu 5s auf Lock-Freigabe)
- Try/except im Delete-Endpoint: gibt HTTP 409 statt 500 bei Lock-Konflikt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Beim Mergen von Duplikaten werden jetzt URLs und Quellen aus allen
Duplikaten in den besten Fakt uebernommen, bevor die Duplikate
entfernt werden. So gehen keine Belege verloren.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3-Ebenen-System gegen Duplikate:
1. Pre-Dedup: LLM-Antwort wird vor DB-Insert dedupliziert (deduplicate_new_facts)
2. Auto-Resolve: Bestaetigte Fakten loesen automatisch stale developing/unconfirmed Fakten auf
3. Periodische Konsolidierung: Haiku clustert alle 6h semantische Duplikate und entfernt sie
Verbessertes Claim-Matching: SequenceMatcher (70%) + Jaccard-Keyword-Overlap (30%)
statt reinem SequenceMatcher. Threshold von 0.7 auf 0.75 erhoeht.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Duplikat-Check basiert auf source_id+type statt exaktem Titel
- add_source ohne source_id prüft per Domain-Match
- Stale-Check überspringt web_sources (nur RSS-Feeds prüfen)
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>
- status_history Spalte für fact_checks (Faktencheck-Verlauf als JSON)
- category Spalte für article_locations (Marker-Klassifizierung)
- Prompt-Übergabe an Claude CLI via stdin statt Argument (ARG_MAX)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- researcher.py: Neuer dedizierter Haiku-Call extract_dynamic_keywords()
analysiert die letzten 30 Headlines und generiert 5 DE+EN Begriffspaare
- orchestrator.py: Dynamische Keywords vor Feed-Selektion aus DB-Headlines
- rss_parser.py: min_matches auf max 2 gedeckelt (vorher n/2, bei 10 Keywords = 5)
- analyzer.py: Fettdruck-Anweisungen entfernt
Vorher: 0 RSS-Treffer (min_matches=5 unerreichbar)
Nachher: 22 RSS-Treffer (Tagesschau 11, Al Jazeera 5, BBC 4, NYT 2)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- geoparsing.py: Komplett-Rewrite (spaCy NER + Nominatim -> Haiku + geonamescache)
- orchestrator.py: incident_context an geoparse_articles, category in INSERT
- incidents.py: incident_context aus DB laden und an Geoparsing uebergeben
- public_api.py: Locations aggregiert im Lagebild-Endpoint
- components.js: response-Kategorie neben retaliation (beide akzeptiert)
- requirements.txt: spaCy und geopy entfernt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
parseUTC() hängte blind ein 'Z' (UTC) an alle Timestamps, aber
die DB speichert Lokalzeit (Europe/Berlin). Bei CET (UTC+1) wurden
alle Zeiten 1 Stunde zu spät angezeigt.
Neue Logik: Timestamps mit 'Z' oder '+' werden direkt geparst.
Timestamps ohne Zeitzonen-Info werden als Europe/Berlin interpretiert
mit korrektem Offset (auch bei Sommer-/Winterzeit-Wechsel).
Betrifft: Refresh-Verlauf, Artikel-Zeitstempel, Snapshots, Lagebild-Stand
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ursache: Server sendete started_at als Lokalzeit (Europe/Berlin),
aber der Client interpretierte es als UTC via parseUTC().
Bei UTC+1 lag die Startzeit dadurch 1 Stunde in der Zukunft.
- orchestrator.py: started_at in WebSocket-Nachrichten als echtes UTC
(ISO 8601 mit Z-Suffix) senden, DB-Timestamps bleiben Lokalzeit
- components.js: elapsed auf min. 0 clampen als Sicherheitsnetz
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- researcher.py/factchecker.py: TimeoutError wird nach oben durchgereicht
statt vom breiten except Exception geschluckt zu werden
- orchestrator.py: Built-in TimeoutError zu TRANSIENT_ERRORS hinzugefuegt
(war nur asyncio.TimeoutError, aber claude_client wirft TimeoutError)
- config.py: CLAUDE_TIMEOUT von 300s auf 420s erhoeht
Vorher: Timeout fuehrte zu "0 Artikel" ohne Retry (8 Timeouts seit 28.02.)
Nachher: Timeout loest bis zu 3 Retries aus (sofort, +2min, +5min)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alle toLocaleTimeString/toLocaleDateString-Aufrufe und
getHours/getMinutes-Zugriffe verwenden jetzt fix die
Zeitzone Europe/Berlin statt der Browser-Zeitzone.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ALLE Timestamps einheitlich Europe/Berlin (kein UTC mehr)
- DB-Migration: 1704 bestehende Timestamps von UTC nach Berlin konvertiert
- Auto-Refresh Timer Fix: ORDER BY id DESC statt completed_at DESC
(verhindert falsche Sortierung bei gemischten Timestamp-Formaten)
- started_at statt completed_at fuer Timer-Vergleich (konsistenter)
- Manuelle Refreshes werden bei Intervall-Pruefung beruecksichtigt
- Debug-Logging fuer Auto-Refresh Entscheidungen
- astimezone() fuer Timestamps mit Offset-Info
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Korrektur: Alle DB-Timestamps (refresh_log, created_at, updated_at,
auth, notifications) bleiben UTC fuer korrekte Timer-Vergleiche.
Europe/Berlin nur fuer angezeigte Werte (Exporte, Prompts, API).
Verhindert zu fruehes Ausloesen des Auto-Refresh-Timers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Inkonsistenz behoben: Manche Timestamps wurden in UTC, andere in
Berlin-Zeit gespeichert. Das fuehrte zu Fehlern beim Auto-Refresh
und Faktencheck, da Zeitvergleiche falsche Ergebnisse lieferten.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- delete_source/update_source: Quellen mit tenant_id=NULL geschützt
- block/unblock_domain: Nur tenant-spezifische Quellen betroffen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Klick auf Email öffnet Dropdown mit Organisation und Lizenzinfo
- Org-Name und Lizenz-Badge nicht mehr direkt sichtbar im Header
- Dropdown schliesst bei Klick ausserhalb
- Barrierefreie ARIA-Attribute
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- rss_researcher liefert jetzt Keywords zurück, die direkt für RSS-Suche genutzt werden
- Neue _clean_search_words() filtert rein-numerische Begriffe (Jahreszahlen etc.)
- Matching-Schwelle aufgerundet: bei 3 Keywords müssen mindestens 2 matchen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CSS zoom statt font-size auf Root, da alle Schriftgrößen in px definiert
sind und font-size:115% auf :root keine Wirkung hatte.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Frontend-Dateien auf Zustand vor i18n zurückgesetzt.
lang.js entfernt, CSP bereinigt. Backend-Umlaut-Fix bleibt erhalten.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>