Der Recherchebericht der EU-Fassung enthielt seit zwei Laeufen nur noch den
Abschnitt ZUSAMMENFASSUNG, 1513 statt der ueblichen mehreren tausend Zeichen.
Die Abschnitte HINTERGRUND, AKTEURE, AKTUELLE LAGE, EINSCHAETZUNG und
QUELLENQUALITAET fehlten vollstaendig.
Ursache. Das Modell lieferte zuerst ein knappes JSON, bemerkte den Fehler
selbst ("Wait, I need to include the full briefing content in the summary
field. Let me redo this properly with all sections") und haengte danach eine
zweite, vollstaendige Fassung an. Unsere Auswertung nahm das erste Objekt und
verwarf alles danach. Der Bericht war also da, wir haben ihn weggeworfen.
Behoben. json_utils bekommt extract_json_objects und extract_json_arrays, die
alle vollstaendigen Bloecke einer Antwort liefern statt nur den ersten. Der
Analyzer waehlt daraus den Bericht mit dem laengsten summary, der Faktencheck
die Liste mit den meisten Fakten. Beide protokollieren, wenn mehrere Fassungen
auftauchen, damit der Fall sichtbar bleibt. Die bisherigen Einzelabfragen
extract_json_object und extract_json_array bleiben unveraendert, damit sich an
den uebrigen Aufrufstellen nichts aendert.
Gegenprobe an der echten Antwort aus Lauf 50. Vorher 1513 Zeichen mit einem
Abschnitt, jetzt 8189 Zeichen mit allen sechs.
Neu sind 16 Pruefungen, insgesamt laufen 96 ohne Netzzugriff und ohne Kosten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
428 Zeilen
24 KiB
Markdown
428 Zeilen
24 KiB
Markdown
# AegisSight-Monitor
|
|
|
|
> OSINT-Lagemonitoring mit KI-gestützter Nachrichtenanalyse
|
|
|
|
## Übersicht
|
|
|
|
```yaml
|
|
projekt: AegisSight-Monitor
|
|
url: https://monitor.aegis-sight.de
|
|
server: ssh monitor (46.225.141.13, User: claude-dev)
|
|
pfad: /home/claude-dev/AegisSight-Monitor
|
|
quellcode: /home/claude-dev/AegisSight-Monitor/src/
|
|
datenbank: /home/claude-dev/osint-data/osint.db (SQLite WAL, geteilt mit Verwaltungsportal + Globe; data/ im Projekt ist ein Symlink darauf)
|
|
gitea: https://gitea-undso.aegis-sight.de/AegisSight/AegisSight-Monitor
|
|
service: aegis-monitor.service (systemd, Port 8891, Nginx Reverse Proxy, EIN uvicorn-Prozess - Orchestrator und WebSockets halten Zustand im Speicher, niemals --workers setzen)
|
|
venv: /home/claude-dev/.venvs/osint/ (Python 3.12)
|
|
```
|
|
|
|
## Technologie-Stack
|
|
|
|
```yaml
|
|
backend:
|
|
framework: FastAPI + Uvicorn
|
|
datenbank: SQLite WAL (aiosqlite, async)
|
|
auth: Magic-Link-Login per E-Mail (JWT HS256, 24h)
|
|
scheduler: APScheduler (PDF-Ingest 1min, Auto-Refresh 1min, Cleanup 1h, Health-Check taeglich 04:00, Telegram-Status taeglich 04:30)
|
|
websocket: FastAPI native (Echtzeit-Updates an Clients)
|
|
ki: Claude CLI als Subprocess (WebSearch + WebFetch Tools)
|
|
ki_backend_eu: |
|
|
EU-Umbau Phase 1 (seit 2026-07-29): zweiter Modellweg ueber AWS Bedrock
|
|
(EU-Inferenzprofile Frankfurt, agents/bedrock_client.py). Umschaltbar je
|
|
Lage (incidents.ai_backend) > Organisation (org_setting 'ai_backend') >
|
|
global (ENV AI_BACKEND, Default 'cli'). Aufloesung je Refresh im
|
|
Orchestrator via ContextVar _ai_backend_var (gemeinsame Aufloesung mit der
|
|
Lane-Wahl, siehe _resolve_ai_backend). Seit Phase 2 (2026-07-30) laeuft im
|
|
EU-Modus auch die RECHERCHE europaeisch: agents/eu_researcher.py steuert
|
|
eine Schleife aus Bedrock-Planung und staan-Suchen (services/staan_client.py)
|
|
und liefert dasselbe JSON wie die CLI-WebSearch. Werkzeuglose Aufrufe gehen
|
|
direkt ueber bedrock_client. Seit Phase 3 (2026-07-30) laufen auch
|
|
Faktencheck und Lagebild im EU-Modus komplett ueber Bedrock: der
|
|
Faktenchecker bekommt vorab eine staan-Stuetzsuche (eu_call_with_search in
|
|
eu_researcher.py, Haiku plant Verifikations-Queries, Treffer als
|
|
Kontextblock im Prompt), das Lagebild arbeitet rein auf dem
|
|
Meldungsbestand. Im EU-Modus gibt es damit KEINE CLI-Aufrufe mehr.
|
|
Doppelspur: eine Orchestrator-Lane je
|
|
(Organisation, Backend) — CLI- und EU-Lauf derselben Org laufen gleichzeitig,
|
|
gleiche Backends seriell. Kosten aus Token x BEDROCK_PRICING plus
|
|
STAAN_COST_PER_QUERY_USD, Credits-System unveraendert. AWS-Zugang +
|
|
STAAN_API_KEY liegen in der Staging-.env. boto3 muss im venv installiert
|
|
sein (beim Promote nach Live auch dort nachziehen!).
|
|
ki_modelle:
|
|
schnell: CLAUDE_MODEL_FAST (Haiku) — Feed-Selektion, Topic-Filter, Geoparsing, Uebersetzung, Chat, QC
|
|
mittel: CLAUDE_MODEL_MEDIUM (Sonnet) — nur Netzwerkanalyse (entity_extractor hat aktuell keinen Aufrufer in der App)
|
|
standard: CLAUDE_MODEL_STANDARD (Opus) — Recherche, Lagebild, Faktencheck
|
|
email: aiosmtplib (smtp.ionos.de:587 TLS)
|
|
|
|
frontend:
|
|
typ: Vanilla JS (kein Framework, kein Build-Step)
|
|
design: AegisSight Dark/Light Theme (Navy/Gold)
|
|
fonts: Poppins (Titel), Inter (Body)
|
|
layout: Reiter-Ansicht je Lage (layout.js; gridstack wurde abgeloest, nur Legacy-Stubs uebrig)
|
|
karte: Leaflet + MarkerCluster (lokal in vendor/, Kacheln von tile.openstreetmap.de)
|
|
echtzeit: WebSocket mit Auto-Reconnect und Ping/Pong
|
|
```
|
|
|
|
## Projektstruktur
|
|
|
|
```yaml
|
|
src/:
|
|
main.py: "FastAPI App, WebSocketManager, Scheduler, Lifespan, statische Routen"
|
|
config.py: "Konfiguration (JWT, Claude-Modelle, SMTP, RSS-Feeds, Zeitzone)"
|
|
auth.py: "JWT erstellen/verifizieren, Magic-Link/Code, get_current_user Dependency"
|
|
database.py: "SQLite Schema (25+ Tabellen), Migrationen, init_db(), get_db()"
|
|
models.py: "Pydantic Request/Response-Schemas"
|
|
source_rules.py: "Domain-Kategorisierung, RSS-Feed-Discovery, Claude-Feed-Bewertung"
|
|
report_generator.py: "PDF (WeasyPrint) + DOCX (python-docx) Export"
|
|
|
|
routers/:
|
|
auth.py: "Magic-Link-Login, Token-Verify, /api/auth/me"
|
|
incidents.py: "CRUD Lagen, Refresh, Artikel, Snapshots, Faktenchecks, Export, E-Mail-Abos, Refresh-Log, Beschreibung generieren (Prompt Enhancement)"
|
|
sources.py: "CRUD Quellen, Discovery (Single/Multi), Domain sperren, Telegram-Validierung"
|
|
chat.py: "KI-Assistent (Haiku), Injection-Schutz, Tech-Leak-Filter"
|
|
public_api.py: "API-Key Auth, Globe-Feed (GeoJSON), Globe-Ingest, Snapshot-Abruf"
|
|
notifications.py: "CRUD Benachrichtigungen, Unread-Count, Mark-Read"
|
|
feedback.py: "E-Mail-Feedback mit Bild-Anhaengen"
|
|
tutorial.py: "Tutorial-Fortschritt pro User"
|
|
|
|
routes/:
|
|
version_router.py: "GET /api/version + /api/release-notes (OHNE Auth, fuer das Update-Fenster im Frontend). Historischer Zweitordner neben routers/"
|
|
|
|
agents/:
|
|
orchestrator.py: "Queue-basierte Refresh-Steuerung (eine Lane je Organisation), Research Multi-Pass (3 Durchlaeufe), Retry, Cancel, Credits-Buchung. _run_refresh ist ~1450 Zeilen, Aenderungen dort nur mit Vorsicht"
|
|
stage_runners.py: "Studio-Bausteine: analyze/factcheck einzeln auf vorhandenem Datenbestand, bewusst NEBEN _run_refresh gebaut"
|
|
researcher.py: "WebSearch-Recherche (Standard + 4-Phasen-Tiefenrecherche), Feed-/Kanal-/Account-Selektion, Keyword-Extraktion, Google-News-Suchfeeds je Sprache"
|
|
analyzer.py: "Analyse-Agent (Lagebild/Briefing, Erst- + inkrementell, Inline-Zitate, Topic-Filter, Neueste Entwicklungen, Stimmungsbild)"
|
|
factchecker.py: "Faktencheck (Erst/Inkrementell/Zwei-Phasen mit Haiku-Triage ab 25 Fakten), Claim-Matching, Dedup, Schutz gegen Massen-Downgrades"
|
|
geoparsing.py: "Haiku-basierte Ortsextraktion, Geocoding offline via geonamescache"
|
|
entity_extractor.py: "Netzwerkanalyse (Sonnet). ACHTUNG: aktuell ohne Aufrufer in der App, nur regenerate_relations.py im Repo-Root nutzt es"
|
|
translator.py: "Haiku-Uebersetzung in Batches a 5 (groessere Batches rissen den JSON-Output ab)"
|
|
claude_client.py: "Shared Claude CLI Client, Usage-Tracking (Token, Kosten), Rate-Limit-Erkennung, Cancel via ContextVar. Routet je nach _ai_backend_var werkzeuglose Aufrufe zu bedrock_client"
|
|
bedrock_client.py: "EU-Modellweg ueber AWS Bedrock Converse (nur eu.-Inferenzprofile, Token-zu-USD-Umrechnung ueber BEDROCK_PRICING, gleiche Fehlerkategorien wie das CLI). EU-Umbau Phase 1"
|
|
eu_researcher.py: "EU-Recherche-Schleife (Phase 2): Bedrock-Modell schlaegt Suchanfragen vor, Code fragt staan, Modell entscheidet weiter/fertig. Bildet die 4-Phasen-Tiefenrecherche nach, liefert denselben JSON-Array-Text wie die CLI-WebSearch (Einstieg in researcher.search), akzeptiert NUR URLs aus echten staan-Treffern"
|
|
|
|
feeds/:
|
|
rss_parser.py: "RSS-Feed-Parsing (feedparser + httpx), adaptive Keyword-Schwelle, Frische-Bonus, Domain-Cap"
|
|
telegram_parser.py: "Telethon-basierter Telegram-Parser (eine gemeinsame Session), Kanal-Validierung"
|
|
x_parser.py: "X/Twitter via twscrape (Account-Store ~/.x-scraper/accounts.db, optional Mobilfunk-Proxy)"
|
|
podcast_parser.py: "Podcast-Feeds inkl. Transkript-Extraktoren (transcript_extractors/)"
|
|
|
|
services/:
|
|
pipeline_tracker.py: "Die 11 Pipeline-Schritte (DE/EN, Laien-Tooltips), schreibt refresh_pipeline_steps + WebSocket-Events"
|
|
post_refresh_qc.py: "Post-Refresh Quality Check: Faktencheck-Duplikate, Location-Korrektur, Umlaut-Normalisierung"
|
|
fact_consolidation.py: "Periodisches Haiku-Clustering. ACHTUNG: als 6h-Job dokumentiert, aber NICHT im Scheduler eingeplant"
|
|
source_health.py: "Quellen-Health-Checks (Erreichbarkeit, Feed-Validitaet, Stale, fetch_strategy-Logik)"
|
|
source_suggester.py: "KI-Quellen-Vorschlaege via Haiku + Karteileichen-Heuristik"
|
|
pdf_ingest.py: "Minutenjob: hochgeladene PDFs einlesen (pdfplumber + OCR-Fallback), uebersetzen, als Pool-Artikel ablegen"
|
|
org_settings.py: "Key-Value-Einstellungen je Organisation (output_language etc.) mit 60s-Cache"
|
|
staan_client.py: "staan.ai Such-Client (EU-Umbau Phase 2): Suche + Volltexte (full_content=markdown) ueber den europaeischen Index, Pflicht-Domain-Ausschlussliste je Anfrage, max 10 Ausschluss-Domains"
|
|
license_service.py: "Lizenz-Pruefung, Credits-Buchung (charge_usage_to_tenant), Periodenwechsel, Budget-Warnung. expire_licenses() existiert, hat aber KEINEN Scheduler-Job"
|
|
|
|
middleware/:
|
|
license_check.py: "Dependencies: require_active_license, require_writable_license"
|
|
|
|
email_utils/:
|
|
sender.py: "Async SMTP Versand"
|
|
templates.py: "HTML-Templates (Magic-Link, Benachrichtigungen)"
|
|
rate_limiter.py: "Rate-Limiting Magic-Links"
|
|
|
|
migration/:
|
|
migrate_to_multitenancy.py: "Einmal-Migration Single->Multi-Tenant"
|
|
|
|
report_templates/:
|
|
report.html: "HTML-Template fuer PDF/DOCX-Export"
|
|
|
|
static/:
|
|
index.html: "Login-Seite (Magic-Link), JS inline"
|
|
dashboard.html: "Hauptdashboard (Sidebar + Reiter-Ansicht + 8 Modals + Chat-Widget)"
|
|
studio.html: "Studio (3-Spalten-Werkstatt, online nur fuer info@ sichtbar - Gating rein clientseitig)"
|
|
css/:
|
|
style.css: "AegisSight Design System (Dark/Light Theme, alle Komponenten)"
|
|
studio.css: "Studio-spezifische Styles"
|
|
js/:
|
|
api.js: "REST-API-Client (fetch, Auth-Header, 30s Timeout, 403 -> Nur-Lese-Modus)"
|
|
app.js: "Hauptlogik: ThemeManager, NotificationCenter, App-Objekt (181 KB)"
|
|
components.js: "UI-Rendering: Sidebar, Faktenchecks, Toasts, Progress, Karte (geteilt mit Studio)"
|
|
studio.js: "Kompletter Studio-Controller (109 KB)"
|
|
chat.js: "Chat-Assistent Widget (Bedienfragen)"
|
|
pipeline.js: "Grafische Analysepipeline (11 Schritte, Live-Animation)"
|
|
layout.js: "Reiter-Umschalter je Lage (merkt letzten Reiter; enthaelt noch gridstack-Legacy-Stubs)"
|
|
tutorial.js: "32-Schritte-Rundgang (140 KB). AKTUELL DEAKTIVIERT, alle Einstiege auskommentiert"
|
|
a11y.js: "Barrierefreiheits-Panel (identische Datei wie im Verwaltungsportal)"
|
|
update-system.js: "Was-ist-neu-Modal aus RELEASES.json + Update-Banner"
|
|
ai-disclaimer.js: "KI-Haftungshinweis beim ersten Besuch"
|
|
i18n.js: "Mini-Uebersetzung de/en (nur teilweise verdrahtet, Studio/Login komplett deutsch)"
|
|
ws.js: "WebSocket-Client (Reconnect, Ping/Pong)"
|
|
vendor/:
|
|
leaflet.js: "Karten-Bibliothek"
|
|
leaflet.markercluster.js: "Marker-Clustering"
|
|
|
|
tests/:
|
|
hinweis: "Laufen ohne Netzzugriff und ohne Kosten, Modell, Suche und Datenbank sind durch Testdoubles ersetzt. Aufruf aus dem Projektstamm, zum Beispiel venv/bin/python tests/test_eu_factcheck.py"
|
|
test_eu_factcheck.py: "EU-Faktencheck, Nachhak-Runde, Quellenzuordnung, plus Regressionsschutz fuer den Anthropic-Weg"
|
|
test_eu_belegsuche.py: "Gezielte Belegsuche ueber staan, Planung, Grenzen, Entdopplung, Ausfallverhalten"
|
|
test_qc_und_runden.py: "Absicherung der Duplikatpruefung und Abbruch der Suchrunden bei erreichter Treffergrenze"
|
|
test_mehrfachantwort.py: "Antworten, in denen sich das Modell selbst korrigiert und mehrere Fassungen liefert, die ausfuehrlichste muss gewinnen"
|
|
```
|
|
|
|
## Architektur
|
|
|
|
```yaml
|
|
incident_typen:
|
|
adhoc:
|
|
label: "Live-Monitoring"
|
|
quellen: "RSS + WebSearch + optional Telegram"
|
|
analyse: "Fliesstext-Lagebild"
|
|
faktencheck_status: "confirmed/unconfirmed/contradicted/developing"
|
|
refresh: "Manuell oder automatisch (Intervall konfigurierbar)"
|
|
research:
|
|
label: "Recherche"
|
|
quellen: "Nur WebSearch 4-Phasen-Tiefenrecherche (kein RSS)"
|
|
analyse: "Strukturiertes Briefing (Ueberblick, Hintergrund, Akteure, Lage, Einschaetzung, Quellenqualitaet)"
|
|
faktencheck_status: "established/unverified/disputed/developing"
|
|
refresh: "Immer manuell, erster Refresh automatisch 3 Durchlaeufe (Multi-Pass)"
|
|
multi_pass:
|
|
durchlaeufe: 3
|
|
labels: ["Breite Erfassung", "Vertiefung", "Konsolidierung"]
|
|
bedingung: "Nur beim ersten Refresh (kein Summary vorhanden)"
|
|
cancel: "Zwischen und innerhalb der Durchlaeufe moeglich"
|
|
|
|
refresh_pipeline:
|
|
hinweis: "Die 11 nutzersichtbaren Schritte definiert services/pipeline_tracker.py. Interner Ablauf in _run_refresh:"
|
|
1: "Feed-/Kanal-/Account-Selektion (Haiku) + dynamische Keywords je Sprache"
|
|
2: "Parallel sammeln: RSS + Google-News-Suchfeeds + WebSearch (Opus) + optional Telegram + X + Podcasts (nur adhoc)"
|
|
3: "URL-Verifizierung (HEAD-Requests, tote URLs werden zu site:-Suchlinks repariert)"
|
|
4: "Duplikaterkennung (URL + Headline, dann gegen DB-Bestand)"
|
|
5: "Relevanz-Scoring + semantischer Topic-Filter (Haiku)"
|
|
6: "Geoparsing (Haiku + geonamescache offline)"
|
|
7: "Faktencheck ZUERST (liefert Faktenkontext), DANN Lagebild/Briefing (Opus). Optional Stimmungsbild aus Foren-Quellen"
|
|
8: "Uebersetzung fehlender DE-Texte (Haiku, nur wenn TRANSLATOR_ENABLED) + Neueste Entwicklungen (nur adhoc)"
|
|
9: "Post-Refresh QC (Fakten-Dubletten, Karten-Kategorien, Umlaute)"
|
|
10: "Notifications (DB + E-Mail + WebSocket), Credits-Buchung (flat: adhoc 45 / research 40 je Durchlauf)"
|
|
11: "Background: Source-Discovery + Executive Summary"
|
|
|
|
multi_tenancy: |
|
|
Mandantentrennung ueber tenant_id-Filter je Abfrage (keine Middleware). Bei Lagen zentral
|
|
ueber _check_incident_access. ACHTUNG, nicht alle Tabellen haben tenant_id
|
|
(source_health_checks, source_suggestions, incident_subscriptions, billing_tariff),
|
|
und der WebSocket-Broadcast filtert Stand 07/2026 NICHT nach Mandant.
|
|
|
|
lage_reiter:
|
|
- "Neueste Entwicklungen (research: Zusammenfassung)"
|
|
- "Lagebild (research: Recherchebericht, Markdown + Inline-Zitate)"
|
|
- "Ereignis-Timeline (horizontale Achse, Bucketing, Filter)"
|
|
- "Geografische Verteilung (Leaflet, Kategorie-Marker, Legende)"
|
|
- "Faktencheck (Status-Icons, Evidence, Filter)"
|
|
- "Oeffentliche Stimmung (nur bei Foren-Quellen)"
|
|
- "Analysepipeline (grafisch, 11 Schritte)"
|
|
- "Quellenuebersicht (nach Domain gruppiert)"
|
|
```
|
|
|
|
## Datenbank (30+ Tabellen)
|
|
|
|
```yaml
|
|
kern: "organizations, licenses, users, magic_links, organization_settings, portal_admins (gehoert dem Portal)"
|
|
lagen: "incidents, articles, incident_snapshots, fact_checks, incident_events, fact_check_runs"
|
|
pipeline: "refresh_log, refresh_pipeline_steps"
|
|
quellen: "sources, source_alignments, source_health_checks, source_suggestions, user_excluded_domains, podcast_transcripts"
|
|
geo: "article_locations"
|
|
netzwerk: "network_analyses, network_analysis_incidents, network_entities, network_entity_mentions, network_relations, network_generation_log (alle leer, kein Endpoint im Monitor)"
|
|
abrechnung: "token_usage_monthly, billing_tariff, user_activity_days"
|
|
system: "notifications, incident_subscriptions, system_status"
|
|
hinweise:
|
|
- "Es gibt KEINE feedback-Tabelle, Feedback geht direkt per E-Mail raus"
|
|
- "Portal-Tabellen (portal_audit_log, portal_magic_links, source_health_history u.a.) liegen in derselben Live-DB, werden aber nur vom Verwaltungsportal angelegt/genutzt"
|
|
- "users.is_global_admin/globe_access/network_access legt NUR das Portal an. Eine frisch per init_db erzeugte Monitor-DB kann daher keinen Login (no such column)"
|
|
```
|
|
|
|
## Verwandte Projekte (gleicher Server)
|
|
|
|
```yaml
|
|
verwaltungsportal:
|
|
pfad: /home/claude-dev/AegisSight-Monitor-Verwaltung
|
|
url: https://monitor-verwaltung.aegis-sight.de
|
|
service: verwaltungsportal.service (Port 8892)
|
|
geteilte_db: ja
|
|
|
|
globe:
|
|
pfad: /home/claude-dev/AegisSight-Globe
|
|
url: https://globe.aegis-sight.de
|
|
service: globe.service (Port 8890)
|
|
geteilte_db: ja
|
|
|
|
netzwerkanalyse:
|
|
pfad: /home/claude-dev/AegisSight-Netzwerkanalyse
|
|
url: https://netzwerkanalyse.aegis-sight.de
|
|
service: netzwerkanalyse.service (Port 8893)
|
|
```
|
|
|
|
## Regeln
|
|
|
|
```yaml
|
|
regeln:
|
|
- "Jede Aenderung MUSS sofort committed und nach Gitea gepusht werden"
|
|
- "Echte Umlaute in UI-Texten (ue, ae, oe, ss), keine Umschreibungen"
|
|
- "Keine Passwoerter oder Secrets in den Code committen"
|
|
- "Service nach Backend-Aenderungen: sudo systemctl restart aegis-monitor (Staging startet der Auto-Deploy selbst neu)"
|
|
- "Frontend-Aenderungen (HTML/JS/CSS) brauchen keinen Neustart"
|
|
- "Backup-Dateien (.bak) nicht committen, vor Push loeschen"
|
|
```
|
|
|
|
## UI-Sync mit dem Lokal-Fork (verbindlich)
|
|
|
|
> Seit 2026-07-25. Die Oberflächen von Online-Monitor und Lokal-Fork bleiben angeglichen.
|
|
|
|
```yaml
|
|
ui_sync:
|
|
regel: "Jede Änderung unter src/static wird noch in derselben Sitzung ins jeweils andere Repo portiert."
|
|
lokal_repo: "AegisSight/AegisSight-Monitor-Local (Branch main, läuft auf dem Windows-Rechner des Nutzers)"
|
|
portieren:
|
|
lokal_nach_online: |
|
|
In einem temporären Klon dieses Repos (Branch develop) den Lokal-Fork als Remote
|
|
hinzufügen, fetchen, git cherry-pick <sha> (gemeinsame Historie, Drei-Wege-Merge
|
|
funktioniert), dann push origin develop. NIE auf main pushen, Live nur per Promote-UI.
|
|
online_nach_lokal: "Im Lokal-Fork: git fetch online && git cherry-pick <sha> (Remote 'online' ist dort eingerichtet, fetch-only)."
|
|
drift_check: "Im Lokal-Fork: bash scripts/ui-drift-check.sh (vergleicht src/static beider Repos, Zeilenenden ignoriert)"
|
|
wortlaut: "Die Verbrauchseinheit heißt in BEIDEN Monitoren 'Credits' (Entscheidung Nutzer 2026-07-25). Nicht Guthaben, nicht Einheiten."
|
|
gewollte_unterschiede:
|
|
- "Online: Studio nur für info@aegis-sight.de freigegeben (Gating in studio.js init, Studio-Link im Dashboard-Header versteckt). Lokal ohne Gating, Knopf immer sichtbar."
|
|
- "Lokal: X-Zugänge-Oberfläche (twscrape) in Sidebar/Modal/Quellenübersicht. Online bewusst nicht vorhanden (kein x-Router im Online-Backend)."
|
|
- "Lokal: Auto-Login über /api/auth/dev-login (Demo-Modus). Online ausschließlich Magic-Link."
|
|
- "Lokal: Kostenvorschau im Anlege-Dialog (updateIntervalCostHint, Fork-Commit 5b0b578). Online noch nicht portiert."
|
|
- "Online: Umschalter 'KI-Verarbeitung' im Anlege-/Bearbeiten-Dialog (Auswahl inc-ai-backend: Standard/Anthropic/EU) plus EU-Kennzeichen in der Lagen-Kopfzeile (incident-eu-badge). Bewusst NICHT im Lokal-Fork, dort gibt es kein Bedrock-Backend und das Feld waere funktionslos (Stand 2026-07-30)."
|
|
bekannter_drift_stand_2026_07_26:
|
|
- "Die Takt-Untergrenze ist inzwischen AUCH online (dort _getMinIntervalMinutes, 30 Min; lokal _intervalMinMinutes mit Vorgabe 12 Std). Ältere Angaben, sie fehle online, sind überholt."
|
|
- "Online-only, noch nicht in den Fork portiert: Reiter 'Öffentliche Stimmung' (renderPublicMood) und die Fall-Chat-Rückfrage /clarify."
|
|
- "Echter Inhalts-Drift in rund 11 Dateien (app.js, components.js, api.js, studio.js, style.css u.a.), weitere ~7 Dateien unterscheiden sich nur durch Umlaute in Kommentaren."
|
|
stolperfalle_zeilenenden: |
|
|
Die Frontend-Dateien (src/static) sind CRLF, die Python-Dateien dieses Repos sind LF
|
|
(im Lokal-Fork teils anders). Beim Portieren keine Werkzeuge einsetzen, die Zeilenenden
|
|
pauschal umschreiben (z.B. sed -i unter Git Bash), und den Diff vor dem Commit auf
|
|
Plausibilität prüfen. Ein Riesen-Diff ist fast immer ein Zeilenenden-Unfall.
|
|
```
|
|
|
|
## Staging-Umgebung
|
|
|
|
```yaml
|
|
staging:
|
|
url: https://staging.monitor.aegis-sight.de
|
|
server: 46.225.141.13 (gleicher Host wie Live)
|
|
pfad: /home/claude-dev/AegisSight-Monitor-staging
|
|
branch: develop
|
|
port: 18891 (Live: 8891)
|
|
service: aegis-monitor-staging.service (systemd)
|
|
venv: /home/claude-dev/AegisSight-Monitor-staging/venv (eigenes venv)
|
|
zugriff: Magic-Link-Login an info@aegis-sight.de (Cookie 30 Tage)
|
|
|
|
datenbank:
|
|
pfad: /home/claude-dev/osint-data-staging/osint.db (per DB_PATH in .env gesetzt)
|
|
achtung: "~/AegisSight-Monitor-staging/data/osint.db ist eine UNBENUTZTE Altkopie"
|
|
initial: einmalige Kopie der Live-DB
|
|
drift: gewollt - Aenderungen in Staging beeinflussen Live nicht
|
|
reseed_von_live: |
|
|
sudo systemctl stop aegis-monitor-staging
|
|
cp /home/claude-dev/osint-data/osint.db /home/claude-dev/osint-data-staging/osint.db
|
|
sudo systemctl start aegis-monitor-staging
|
|
|
|
besonderheiten_env:
|
|
JWT_SECRET: eigener fuer Staging (nicht Live-JWT)
|
|
MAGIC_LINK_BASE_URL: https://staging.monitor.aegis-sight.de (sonst leitet App zu Live)
|
|
DB_PATH: /home/claude-dev/osint-data-staging/osint.db (Live setzt KEIN DB_PATH, dort greift der Default data/ = Symlink auf ~/osint-data)
|
|
STAGING_MODE: 1 (unlimited_budget, kein Credits-Hard-Stop)
|
|
TRANSLATOR_ENABLED: false
|
|
TELEGRAM_SESSION_PATH: ~/.telegram-staging/ (eigene Session, dort ist NIEMAND eingeloggt - Telegram-Recherche auf Staging liefert nichts, die Status-Karte im Portal zeigt das ehrlich an)
|
|
AI_BACKEND: "(optional) 'cli' oder 'bedrock', globaler Default fuer den EU-Modellweg. Ohne Eintrag gilt 'cli'"
|
|
AWS_ACCESS_KEY_ID_usw: "AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION=eu-central-1 und STAAN_API_KEY liegen seit 2026-07-29 in der Staging-.env (IAM-Benutzer nur fuer Bedrock, staan-Suchschluessel fuer Phase 2)"
|
|
|
|
auth_service:
|
|
pfad: /opt/aegis-staging-auth
|
|
service: aegis-monitor-staging-auth.service
|
|
port: 127.0.0.1:8095
|
|
cookie_domain: staging.monitor.aegis-sight.de
|
|
cookie_name: aegis_monitor_staging_auth
|
|
code_quelle: identisch zum Service auf 46.225.225.49 (eigene Konfig)
|
|
```
|
|
|
|
### Workflow Staging -> Live
|
|
|
|
Der gueltige Ablauf steht unten unter "Vollstaendiger Workflow": develop pushen,
|
|
Auto-Deploy aktualisiert Staging von selbst, auf Staging pruefen, Promote ueber
|
|
https://deploy.aegis-sight.de, Live-Check. Manuelles git pull auf dem Server ist
|
|
NICHT noetig und sollte unterbleiben (der Deploy-Listener macht git reset --hard,
|
|
lokale Aenderungen in den Server-Verzeichnissen gehen dabei verloren).
|
|
|
|
Stolperfalle bei der Warteschlangen-Pruefung: das Staging-Verzeichnis fetcht per
|
|
Fetch-Regel NUR develop. Fuer "wie viele Commits warten auf Promote" immer erst
|
|
git fetch origin main ausfuehren, sonst zeigt main..develop veraltete Zahlen.
|
|
|
|
### Bekannte Baustellen (Stand 2026-07-26)
|
|
|
|
- WebSocket-Broadcast filtert nicht nach Mandant (main.py broadcast_for_incident bekommt tenant_id, nutzt ihn nicht)
|
|
- POST /api/public/globe-ingest schreibt ohne Eigentuemer-Pruefung in beliebige Lagen, Artikel ohne tenant_id
|
|
- fact_consolidation und expire_licenses existieren, haben aber keinen Scheduler-Job
|
|
- entity_extractor/Netzwerkanalyse ohne Aufrufer in der App (nur regenerate_relations.py)
|
|
- tutorial.js deaktiviert (Einstiege auskommentiert), laedt aber weiter bei jedem Login
|
|
- dashboard.html laedt nicht existierende cluster-data.js (404) und ungenutztes d3.js vom CDN
|
|
- Reiter "Oeffentliche Stimmung" fehlt in layout.js TAB_ORDER und ist dadurch nicht anklickbar
|
|
- X-Schalter im Anlege-Dialog hat online keine Funktion (kein X-Backend online)
|
|
- i18n unvollstaendig (Studio und Login nur deutsch), Begriffs-Mix Fall/Lage/Vorfall, zweimal "Token-Budget" statt "Credits" in app.js
|
|
- Unter 768px verschwindet die Sidebar ersatzlos (mobil unbenutzbar)
|
|
- Budget-Warnung geht nur in die Glocke, nicht per E-Mail (siehe docs/ABRECHNUNG.md)
|
|
|
|
## Auto-Deploy + Promote-UI
|
|
|
|
```yaml
|
|
auto_deploy:
|
|
listener_service:
|
|
pfad: /opt/aegis-staging-deploy
|
|
service: aegis-staging-deploy.service
|
|
port: 127.0.0.1:8096
|
|
deployments:
|
|
staging: develop -> ~/AegisSight-Monitor-staging (restartet aegis-monitor-staging)
|
|
live: main -> ~/AegisSight-Monitor (restartet aegis-monitor)
|
|
endpoints:
|
|
"POST /__deploy": staging via Gitea-Webhook (HMAC)
|
|
"POST /__deploy/live": live via Promote-UI (HMAC)
|
|
secrets: /opt/aegis-staging-deploy/.env (nicht im Repo)
|
|
|
|
gitea_webhook:
|
|
repo: AegisSight/AegisSight-Monitor
|
|
url: https://staging.monitor.aegis-sight.de/__deploy
|
|
branch_filter: develop
|
|
|
|
live_systemd:
|
|
service: aegis-monitor.service
|
|
hinweis: |
|
|
Live-Monitor laeuft seit 2026-04-26 als systemd-Service (vorher loser
|
|
uvicorn-Prozess). Manueller Restart bei Backend-Aenderungen:
|
|
sudo systemctl restart aegis-monitor
|
|
Beim Promote via UI passiert das automatisch.
|
|
|
|
promote_ui:
|
|
url: https://deploy.aegis-sight.de
|
|
laeuft_auf: 46.225.225.49 (zentral fuer alle Services)
|
|
zugriff: Magic-Link-Login an info@aegis-sight.de
|
|
funktion: |
|
|
Live- vs. Staging-Stand pro Service inkl. Liste der ausstehenden Commits.
|
|
Promote-Knopf -> Gitea-PR develop->main wird auto-gemerged + Live-Listener
|
|
pullt main + restartet aegis-monitor.
|
|
```
|
|
|
|
### Vollstaendiger Workflow (Aenderung am Monitor)
|
|
|
|
1. **Entwickeln in develop**:
|
|
```bash
|
|
cd ~/AegisSight-Monitor-staging
|
|
git checkout develop
|
|
# Aenderung
|
|
git add . && git commit -m "..." && git push origin develop
|
|
# Auto-Deploy pullt automatisch + restartet aegis-monitor-staging
|
|
```
|
|
|
|
2. **Auf https://staging.monitor.aegis-sight.de pruefen**
|
|
|
|
3. **Promoten via https://deploy.aegis-sight.de** (Klick auf Monitor-Karte)
|
|
→ Gitea merged develop→main → Listener pullt main → `systemctl restart aegis-monitor`
|
|
|
|
4. **Live-Check auf https://monitor.aegis-sight.de**
|