diff --git a/CLAUDE.md b/CLAUDE.md index 46dd724..4df5b74 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -54,7 +54,8 @@ src/: token_usage.py: "Token-Verbrauch pro Org/Monat, Credits-Stellwerte je Lizenz (PUT /budget). Laufzeitfelder (credits_used-Reset, credits_carried, credits_period_start, budget_warning_sent) verwaltet der MONITOR, das Portal setzt nur Stellwerte" pricing.py: "Preis-Empfehlung aus Ist-Kosten (GET /cost-basis) und pflegbare Preistabelle billing_tariff (GET/PUT /tariff). Die Tabelle ist die Quelle der Buchung im Monitor, der Rechner kann sie speichern" statistik.py: "Betriebsstatistik (GET /api/statistik?months=N). Kosten/Marge je Monat und Org, Betrieb, Fehler-Ranking, MAU/DAU aus user_activity_days, Wachstum. Aggregation als pure Funktionen (unit-testbar)" - audit.py: "Audit-Log-Abfrage, Filter" + audit.py: "Audit-Log-Abfrage, Filter (action/resource_type/admin_id akzeptieren kommagetrennte Mehrfachwerte)" + x_scraper.py: "Recherche-Zugänge: twscrape-X-Konten (eigener Store, X_ACCOUNTS_DB_PATH) + GET /telegram-status (liest system_status, gemeldet vom Monitor)" email_utils/: sender.py: "Async SMTP Versand" @@ -70,12 +71,14 @@ src/: a11y.js: "Barrierefreiheits-Panel (Kontrast, Focus, Schrift, Animationen). IDENTISCHE Datei wie im Monitor-Repo, bei Aenderungen dort mitziehen" statistik.js: "Statistik-Tab, selbst-injizierend wie rechner.js. Inline-SVG-Charts (keine Bibliothek), Serienfarben mit dem dataviz-Validator gegen beide Themes geprüft" sources.js: "Vereinte Quellenliste (Grund- + Kundenquellen, Herkunfts-Filter, Health-Ausklapp mit Deaktivieren, Bulk-Promote, Modal, Discovery, PDF-Upload)" - aufgaben.js: "Aufgaben-Posteingang (Health-Vorschläge + Klassifikations-Review + Verlauf, Badge via GET /tasks/summary)" + aufgaben.js: "Aufgaben-Posteingang (Health-Vorschläge + Klassifikations-Review + Verlauf, Badge via GET /tasks/summary, Sammel-Bearbeitung via PUT /suggestions/bulk)" + x-scraper.js: "Recherche-Zugänge (X-Konten-Pool + Telegram-Session-Status-Karte)" audit.js: "Audit-Log Tab" migrations/: einmal_migrationen: "Backfill-Skripte (DE-Übersetzungen, Umlaute, HTML-Strip etc.)" 2026-07-25_user_activity.py: "Tabelle user_activity_days anlegen (MAU/DAU). Nötig für die Portal-Staging-DB, auf Live legt sie der Monitor an." + 2026-07-25_system_status.py: "Tabelle system_status anlegen (Key-Value, u.a. Telegram-Session-Status). Nötig für die Portal-Staging-DB, auf Live legt sie der Monitor an. Reihenfolge: Monitor VOR Portal promoten." 2026-07-25_billing_tariff.py: "Preistabelle billing_tariff anlegen und mit den beschlossenen Sätzen befüllen (idempotent, überschreibt nichts). Nötig für die Portal-Staging-DB, auf Live legt sie der Monitor an." 2026-07-25_credits_period.py: "Credits-Perioden-Spalten in licenses (idempotent, identisch zur Monitor-Migration). Nötig für die Portal-Staging-DB, auf Live legt sie normalerweise der Monitor an. Reihenfolge: Monitor VOR Portal promoten." ``` diff --git a/migrations/2026-07-25_system_status.py b/migrations/2026-07-25_system_status.py new file mode 100644 index 0000000..2e96c40 --- /dev/null +++ b/migrations/2026-07-25_system_status.py @@ -0,0 +1,46 @@ +"""Migration 2026-07-25: Tabelle system_status anlegen (Telegram-Session-Status). + +Der Monitor legt die Tabelle beim Start selbst an und meldet dort u.a. den +Status seiner Telegram-Session (Key telegram_session). Die +Portal-Staging-Umgebung nutzt eine EIGENE Datenbank ohne laufenden Monitor, +deshalb dieses Skript. Idempotent (CREATE TABLE IF NOT EXISTS), es werden +keine Daten eingefügt. + +Ausführung: + DB_PATH=/home/claude-dev/AegisSight-Monitor-staging/data/osint.db python3 migrations/2026-07-25_system_status.py + DB_PATH=/home/claude-dev/osint-data/osint.db python3 migrations/2026-07-25_system_status.py +""" +import os +import sqlite3 +import sys + + +def main(db_path: str) -> int: + if not os.path.exists(db_path): + print(f"FEHLER: DB nicht gefunden: {db_path}", file=sys.stderr) + return 1 + + conn = sqlite3.connect(db_path, timeout=60) + conn.execute("PRAGMA busy_timeout = 60000") + conn.execute("PRAGMA journal_mode = WAL") + + print(f"Migration auf {db_path}") + + conn.execute(""" + CREATE TABLE IF NOT EXISTS system_status ( + key TEXT PRIMARY KEY, + value TEXT, + updated_at TEXT DEFAULT CURRENT_TIMESTAMP + ) + """) + print(" + system_status angelegt (oder vorhanden)") + + conn.commit() + conn.close() + print("Migration abgeschlossen.") + return 0 + + +if __name__ == "__main__": + db_path = os.environ.get("DB_PATH", "/home/claude-dev/osint-data/osint.db") + sys.exit(main(db_path)) diff --git a/src/routers/x_scraper.py b/src/routers/x_scraper.py index a38887a..c0495ec 100644 --- a/src/routers/x_scraper.py +++ b/src/routers/x_scraper.py @@ -76,6 +76,38 @@ class XScraperActive(BaseModel): active: bool +@router.get("/telegram-status") +async def telegram_status( + admin: dict = Depends(get_current_admin), + db: aiosqlite.Connection = Depends(db_dependency), +): + """Status der Telegram-Session, gemeldet vom Monitor (system_status). + + Der Monitor prüft beim Start und täglich um 04:30 und schreibt das + Ergebnis in die geteilte DB. Das Portal liest nur an. Fehlt der + Eintrag (z.B. Portal-Staging mit eigener DB-Kopie), meldet der + Endpoint available=false statt eines Fehlers. + """ + import json as _json + + cur = await db.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='system_status'" + ) + if not await cur.fetchone(): + return {"available": False} + cur = await db.execute( + "SELECT value, updated_at FROM system_status WHERE key = 'telegram_session'" + ) + row = await cur.fetchone() + if not row: + return {"available": False} + try: + data = _json.loads(row["value"]) if row["value"] else {} + except Exception: + data = {} + return {"available": True, "updated_at": row["updated_at"], **data} + + @router.get("/accounts") async def list_accounts(admin: dict = Depends(get_current_admin)): """Alle X-Scraper-Konten auflisten (ohne Passwoerter/Cookies).""" diff --git a/src/static/dashboard.html b/src/static/dashboard.html index 21aa7d4..1a5dfde 100644 --- a/src/static/dashboard.html +++ b/src/static/dashboard.html @@ -287,7 +287,7 @@
@@ -355,8 +355,12 @@ - +