29 Stellen im Frontend lokalisiert (Toasts: Lage aktualisiert/geloescht/
archiviert/wiederhergestellt, Recherche abgebrochen, Daten aktualisiert,
Quelle hinzugefuegt/aktualisiert, Bericht heruntergeladen, kein RSS;
Confirms: Lage loeschen, Recherche abbrechen; Button-States: Wird
gestartet/abgebrochen/erstellt/gesendet, Suche Feeds, Quelle speichern;
Lizenz: abgelaufen/keine/Org-deaktiviert -- Nur Lesezugriff;
Notification-Center: Titel, Alle gelesen, Keine Benachrichtigungen;
Empty-States: Kein Vorfall ausgewaehlt; Map: Orte einlesen + Tooltip,
Keine Orte erkannt; Modal-Hint: Nur deutschsprachige Quellen). 30+
neue i18n-Keys. Cache-Buster app.js auf v=20260514c.
app.js:1037-1043 setzte den Text der notify-summary-Checkbox dynamisch
auf Neues Lagebild / Neuer Recherchebericht und damit das data-i18n-
Attribut zurueck. Jetzt ueber T() mit Forschungs-/Lagebild-Varianten.
Neuer Key modal.notify.summary_research.
LayoutManager.applyTypeLabels(layout.js:58-65) und App-Render
(app.js:1063,1081) ueberschreiben die Tab-Texte je nach Lage-Typ.
Beides nutzt jetzt T() mit DE-Fallback. Neue Keys tab.summary_short
und tab.summary_report. Cache-Buster layout.js + app.js gebumpt.
Bei Phase 6 wurde components.js und i18n.js gebumpt, app.js aber nicht.
Browser zogen die alte app.js ohne I18N-Init aus dem Cache, sodass
eng_demo-Nutzer eine deutsche Oberflaeche sahen.
STAGING_MODE deaktivierte bisher den Org-Switcher im Frontend, weil keine
Demo-Besucher zwischen Mandanten hoppen sollten. Mit eng_demo brauchen
wir aber bewussten Zugriff auf alle Sprach-Mandanten via Switcher. Der
Token-Budget-Schutz (license_service._staging_mode) bleibt unveraendert.
Backend:
- UserMeResponse um output_language (de | en) erweitert.
- /auth/me liefert die Org-Sprache aus organization_settings.
Frontend:
- Neu: static/js/i18n.js mit T(key)-Helper, I18N.load(lang) und
applyDom() ueber data-i18n + data-i18n-attr.
- Neu: static/i18n/de.json + en.json (sichtbare Bereiche: Sidebar,
Header, Modal-Titel, Faktencheck-Status, Refresh-Hinweise).
- dashboard.html: i18n.js Script-Tag vor api.js, data-i18n auf den
prominenten Strings (Abmelden, + Neuer Fall, Alle/Eigene, Sidebar-
Sektionen, Bericht exportieren, Faktencheck-Tab, Lage anlegen).
Tutorial.init() entfernt aus DOMContentLoaded.
- components.js: factCheckLabels/Tooltips/ChipLabels als Getter ueber
T() mit DE-Fallbacks.
- app.js: vor Setup wird I18N.load(user.output_language) aufgerufen und
applyDom() ausgefuehrt. Tutorial.init() laeuft nur bei lang === de.
Phase 6 von 8 (eng_demo / Org-Sprache).
- email_utils/templates.magic_link_login_email + incident_notification_email
nehmen jetzt lang Parameter (de | en).
- routers/auth.request_magic_link zieht Sprache aus der Org des Users und
uebergibt sie ans Template.
- agents/orchestrator._send_email_notifications_for_incident lokalisiert
ebenfalls und gibt lang an incident_notification_email durch.
- DB-Notification-Texte (refresh_summary, new_articles) sind in der
Pipeline org-sprach-relativ (englische Variante: "3 new articles", etc.).
Status-Change-Notifications: Codes (confirmed/contradicted) bleiben, FE
uebersetzt sie in Phase 6.
Phase 5 von 8 (eng_demo / Org-Sprache).
- Neue Spalte sources.primary_language (ISO-2-Code) mit Backfill aus dem
Freitext-Feld language (Erste Sprache vor /-Trennung). Edge-Cases wie
Iran Military Magazine (English) [Farsi/Arabisch] landen als fa und
koennen ueber das Verwaltungsportal manuell justiert werden.
- get_source_rules(tenant_id) bestimmt die Org-Sprache und bucketed Feeds
nach primary (=Org-Sprache) / international (=alle anderen) / behoerden
(Kategorie behoerde). Bei tenant_id=None oder Helper-Fehler default de.
- rss_parser.search_feeds unveraendert in Logik (international=False
laesst weiterhin alle ausser dem international-Bucket durch), Kommentare
generischer formuliert.
Phase 3 von 8 (eng_demo / Org-Sprache).
- OUTPUT_LANGUAGE Konstante aus config.py entfernt (jetzt pro Org in
organization_settings).
- Orchestrator laedt output_language einmal pro Refresh aus der Org-Sprache.
- researcher.search(), analyzer.analyze/.analyze_incremental/.generate_latest_developments,
factchecker.check/.check_incremental/.check_incremental_twophase bekommen
output_language als Parameter (Default Deutsch).
- LANG_INTERNATIONAL / LANG_GERMAN_ONLY (+ Deep-Varianten) sind Funktionen,
die je nach output_language die Sprachanweisung erzeugen (Deutsch | English
| Fallback).
- Sprachfilter in researcher.search ist org-relativ: bei nicht-international
werden Artikel mit Sprache != output_language_iso gefiltert.
Phase 2 von 8 (eng_demo / Org-Sprache). Bestandsorgs unveraendert, weil
Default-Setting weiterhin de (siehe Phase-1-Migration).
Neue Tabelle organization_settings (organization_id, key, value) als KV-Store
fuer Org-spezifische Konfiguration. Erster Use-Case: output_language (de|en).
Bestandsorgs werden per Migration auf de gesetzt.
Helper services/org_settings.py mit get_org_setting / set_org_setting /
get_org_language / language_display. In-Memory-Cache TTL 60s.
Phase 1 von 8 (eng_demo / Org-Sprache).
Beim Öffnen des Bearbeiten-Dialogs einer Recherche-Lage (type=research) hat
toggleTypeDefaults() den Aktualisierungs-Select hartcodiert auf manual gesetzt
und damit den tatsächlichen DB-Wert im UI verdeckt. User glaubte, manuell sei
gewählt, in der DB stand aber auto und die Lage lief weiter im Auto-Refresh.
Fix: toggleTypeDefaults erhält einen optionalen Parameter preserveMode.
handleEdit ruft mit preserveMode=true auf, damit der DB-Wert respektiert
wird; bei Typ-Wechsel und Neuanlage bleibt der Default-Reset auf manual
für research erhalten.
Cache-Buster app.js: 20260501h -> 20260512a.
Endpoints unter /api/sources/classification/* weg, Service-Module (source_classifier, external_reputation) gelöscht. Quellen-Modal verliert Tab Klassifikations-Review, Klassifikations-Section in der Edit-Form, alle Bulk-Buttons (Sync, Klassifikation starten, Bulk-Approve). API-Methoden in api.js entfernt, alignment-Helper raus, saveSource entschlackt.
Read-Only bleibt: Filter-Dropdowns über der Quellenliste (Politik, Medientyp, Reliability, Externe Reputation, Alignment) und Inline-Badges (_renderClassificationBadges + Label-Maps in components.js). Kunde sieht nur freigegebene Werte.
GET /api/sources liefert weiter Klassifikations-Felder + alignments für die Anzeige; SourceCreate/SourceUpdate akzeptieren keine Klassifikations-Felder mehr.
Bulk-Klassifikations-Skripte entfernt — Pflege läuft über Verwaltungs-UI.