# 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: /mnt/gitea/osint-data/osint.db (SQLite WAL, geteilt mit Verwaltungsportal + Globe) gitea: https://gitea-undso.aegis-sight.de/AegisSight/AegisSight-Monitor service: osint-monitor.service (systemd, Port 8891, Nginx Reverse Proxy) 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 (Auto-Refresh 1min, Cleanup 1h, Health-Check taeglich 04:00) websocket: FastAPI native (Echtzeit-Updates an Clients) ki: Claude CLI als Subprocess (WebSearch + WebFetch Tools) ki_modelle: schnell: CLAUDE_MODEL_FAST (Haiku) — Feed-Selektion, Geoparsing, Chat, QC mittel: CLAUDE_MODEL_MEDIUM (Sonnet) — Entity-Extraktion, Netzwerkanalyse standard: CLI-Default (Opus) — Recherche, Analyse, 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: gridstack.js (Drag-and-Drop Dashboard-Kacheln) karte: Leaflet + MarkerCluster 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" agents/: orchestrator.py: "Queue-basierte Refresh-Steuerung, Research Multi-Pass (3 Durchlaeufe), Retry, Cancel, Credits-Tracking" researcher.py: "WebSearch-Recherche (Standard + 4-Phasen-Tiefenrecherche), Feed-Selektion, Keyword-Extraktion" analyzer.py: "Analyse-Agent (Lagebild/Briefing, Erst- + inkrementell, Inline-Zitate)" factchecker.py: "Faktencheck (Erst/Inkrementell/Zwei-Phasen mit Triage), Claim-Matching, Dedup" geoparsing.py: "Haiku-basierte Ortsextraktion, Geocoding via geonamescache" entity_extractor.py: "Netzwerkanalyse: Entity-Extraktion (Sonnet), Beziehungsanalyse, Dedup" claude_client.py: "Shared Claude CLI Client, Usage-Tracking (Token, Kosten), Rate-Limit-Erkennung" feeds/: rss_parser.py: "RSS-Feed-Parsing (feedparser + httpx), Keyword-Matching, Domain-Cap" telegram_parser.py: "Telethon-basierter Telegram-Parser, Kanal-Validierung" services/: post_refresh_qc.py: "Post-Refresh Quality Check: Faktencheck-Duplikate, Location-Korrektur" fact_consolidation.py: "Periodisches Haiku-Clustering, Auto-Resolve veralteter Fakten" source_health.py: "Quellen-Health-Checks (Erreichbarkeit, Feed-Validitaet, Stale)" source_suggester.py: "KI-Quellen-Vorschlaege via Haiku" license_service.py: "Lizenz-Pruefung (Org, Ablauf, Nutzer-Limit)" 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)" dashboard.html: "Hauptdashboard (Sidebar + GridStack + Modals)" css/: style.css: "AegisSight Design System (Dark/Light Theme, alle Komponenten)" js/: api.js: "REST-API-Client (fetch, Auth-Header, 30s Timeout)" app.js: "Hauptlogik: ThemeManager, NotificationCenter, App-Objekt" components.js: "UI-Rendering: Sidebar, Faktenchecks, Toasts, Progress-Bar, Karte" chat.js: "Chat-Assistent Widget" layout.js: "gridstack.js Wrapper (Drag/Resize, localStorage)" tutorial.js: "Interaktiver 32-Schritte Rundgang mit Animationen" ws.js: "WebSocket-Client (Reconnect, Ping/Pong)" vendor/: leaflet.js: "Karten-Bibliothek" leaflet.markercluster.js: "Marker-Clustering" ``` ## 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: 1: "Feed-Selektion (Haiku) + dynamische Keywords" 2: "Parallel: RSS + WebSearch + optional Telegram" 3: "URL-Verifizierung (HEAD-Requests)" 4: "Duplikaterkennung (URL + Headline)" 5: "Relevanz-Scoring + DB-Dedup" 6: "Geoparsing (Haiku + geonamescache)" 7: "Parallel: Analyse + Faktencheck" 8: "Post-Refresh QC" 9: "Notifications (DB + E-Mail + WebSocket)" 10: "Credits-Tracking (Token auf Lizenz buchen)" 11: "Background: Source-Discovery" multi_tenancy: "Volle Mandantentrennung (tenant_id auf allen Tabellen)" dashboard_kacheln: - "Lagebild (Markdown + Inline-Zitate)" - "Faktencheck (Status-Icons, Evidence, Filter)" - "Quellenübersicht (nach Domain gruppiert)" - "Timeline (horizontale Achse, Bucketing, Filter)" - "Karte (Leaflet, Kategorie-Marker, Legende)" ``` ## Datenbank (25+ Tabellen) ```yaml kern: "organizations, licenses, users, magic_links, portal_admins" lagen: "incidents, articles, incident_snapshots, fact_checks, refresh_log" quellen: "sources, source_health_checks, source_suggestions, user_excluded_domains" geo: "article_locations" netzwerk: "network_analyses, network_analysis_incidents, network_entities, network_entity_mentions, network_relations, network_generation_log" system: "notifications, incident_subscriptions, feedback, token_usage_monthly" ``` ## 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 osint-monitor" - "Frontend-Aenderungen (HTML/JS/CSS) brauchen keinen Neustart" - "Backup-Dateien (.bak) nicht committen, vor Push loeschen" ``` ## Changelog-Workflow Bei JEDER Aenderung am Monitor muessen zwei Dinge passieren: 1. **TaskMate Wissensdatenbank** (Kategorie: "Changelog Monitor", category_id=31): 2. **Git Commit + Push zu Gitea** Changelog-Kategorien in TaskMate: - 31 = Changelog Monitor - 32 = Changelog Globe - 33 = Changelog Netzwerkanalyse - 34 = Changelog Verwaltung - 35 = Changelog Website - 36 = Changelog TaskMate ## 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: ~/AegisSight-Monitor-staging/data/osint.db initial: einmalige Kopie der Live-DB drift: gewollt - Aenderungen in Staging beeinflussen Live nicht reseed_von_live: | sudo systemctl stop aegis-monitor-staging cp ~/AegisSight-Monitor/data/osint.db ~/AegisSight-Monitor-staging/data/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) TELEGRAM_API_ID: 0 # deaktiviert - verhindert Doppel-Login mit Live TELEGRAM_API_HASH: 0 DB-Pfad: relative aus config.py (nutzt automatisch ~/AegisSight-Monitor-staging/data/) 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 1. **Aenderung in develop machen** (im Staging-Verzeichnis): ```bash cd ~/AegisSight-Monitor-staging git checkout develop # Aenderung git add . && git commit -m ... && git push origin develop ``` 2. **Staging aktualisieren** (aktuell manuell): ```bash ssh claude-dev@46.225.141.13 'cd ~/AegisSight-Monitor-staging && git pull && sudo systemctl restart aegis-monitor-staging' ``` 3. **In https://staging.monitor.aegis-sight.de testen** 4. **Promote zu Live**: Pull Request develop -> main in Gitea, dann: ```bash ssh claude-dev@46.225.141.13 'cd ~/AegisSight-Monitor && git pull' # Live laeuft als loser uvicorn-Prozess (kein systemd) - manueller Restart # bei Backend-Aenderungen noetig ``` ### Offen (noch nicht implementiert) - Auto-Deploy bei Push auf develop (Webhook-Listener) - Promote-UI mit Ein-Klick-Button - Live-Monitor auf systemd umstellen (~10s Downtime einmalig) ## 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**