'use client'

export default function DocumentationTab() {
  return (
    <div className="bg-white rounded-xl border border-slate-200 p-6 overflow-auto max-h-[calc(100vh-200px)]">
      <div className="prose prose-slate max-w-none prose-headings:font-semibold prose-h1:text-2xl prose-h2:text-xl prose-h3:text-lg prose-pre:bg-slate-900 prose-pre:text-slate-100">
        {/* Header */}
        <div className="not-prose mb-8 pb-6 border-b border-slate-200">
          <h1 className="text-2xl font-bold text-slate-900">BreakPilot Alerts Agent</h1>
          <p className="text-sm text-slate-500 mt-1">Version: 1.0.0 | Stand: Januar 2026 | Autor: BreakPilot Development Team</p>
        </div>

        {/* Audit Box */}
        <div className="not-prose bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
          <h3 className="font-semibold text-blue-900 mb-2">Audit-Relevante Informationen</h3>
          <p className="text-sm text-blue-800">
            Dieses Dokument dient als technische Dokumentation fuer das Alert-Monitoring-System der BreakPilot Plattform.
            Es ist fuer Audits durch Bildungstraeger und Datenschutzbeauftragte konzipiert.
          </p>
        </div>

        {/* Ziel des Systems */}
        <h2>Ziel des Alert-Systems</h2>
        <p>Das System ermoeglicht automatisierte Ueberwachung von Bildungsthemen mit:</p>
        <ul>
          <li><strong>Google Alerts Integration</strong>: RSS-Feeds von Google Alerts automatisch abrufen</li>
          <li><strong>RSS/Atom Feeds</strong>: Beliebige Nachrichtenquellen einbinden</li>
          <li><strong>KI-Relevanzpruefung</strong>: Automatische Bewertung der Relevanz durch LLM</li>
          <li><strong>Regelbasierte Filterung</strong>: Flexible Regeln fuer automatische Sortierung</li>
          <li><strong>Multi-Channel Actions</strong>: E-Mail, Webhook, Slack Benachrichtigungen</li>
          <li><strong>Few-Shot Learning</strong>: Profil verbessert sich durch Nutzerfeedback</li>
        </ul>

        {/* Datenschutz Compliance */}
        <h2>Datenschutz-Compliance</h2>
        <DocTable
          headers={['Massnahme', 'Umsetzung', 'Wirkung']}
          rows={[
            ['100% Self-Hosted', 'Alle Dienste auf eigenen Servern', 'Keine Cloud-Abhaengigkeit'],
            ['Lokale KI', 'Ollama/vLLM on-premise', 'Keine Daten an OpenAI etc.'],
            ['URL-Deduplizierung', 'SHA256-Hash, Tracking entfernt', 'Minimale Datenspeicherung'],
            ['Soft-Delete', 'Archivierung statt Loeschung', 'Audit-Trail erhalten'],
            ['RBAC', 'Rollenbasierte Zugriffskontrolle', 'Nur autorisierter Zugriff'],
          ]}
        />

        {/* Architektur */}
        <h2>1. Systemarchitektur</h2>
        <h3>Gesamtarchitektur</h3>
        <pre className="text-xs leading-tight overflow-x-auto">{ARCHITECTURE_DIAGRAM}</pre>

        {/* Datenfluss */}
        <h3>Datenfluss bei Alert-Verarbeitung</h3>
        <pre className="text-xs leading-tight overflow-x-auto">{DATAFLOW_DIAGRAM}</pre>

        {/* Feed Ingestion */}
        <h2>2. Feed Ingestion</h2>
        <h3>RSS Fetcher</h3>
        <DocTable
          headers={['Eigenschaft', 'Wert', 'Beschreibung']}
          rows={[
            ['Parser', 'feedparser 6.x', 'Standard RSS/Atom Parser'],
            ['HTTP Client', 'httpx (async)', 'Non-blocking Fetches'],
            ['Timeout', '30 Sekunden', 'Konfigurierbar'],
            ['Parallelitaet', 'Ja (asyncio.gather)', 'Mehrere Feeds gleichzeitig'],
          ]}
        />

        <h3>Deduplizierung</h3>
        <p>Die Deduplizierung verhindert doppelte Alerts durch:</p>
        <ol>
          <li><strong>URL-Normalisierung</strong>: Tracking-Parameter entfernen (utm_*, fbclid, gclid), Hostname lowercase, Trailing Slash entfernen</li>
          <li><strong>URL-Hash</strong>: SHA256 der normalisierten URL, erste 16 Zeichen als Index</li>
        </ol>

        {/* Rule Engine */}
        <h2>3. Rule Engine</h2>
        <h3>Unterstuetzte Operatoren</h3>
        <DocTable
          headers={['Operator', 'Beschreibung', 'Beispiel']}
          rows={[
            ['contains', 'Text enthaelt', 'title contains "Inklusion"'],
            ['not_contains', 'Text enthaelt nicht', 'title not_contains "Werbung"'],
            ['equals', 'Exakte Uebereinstimmung', 'status equals "new"'],
            ['regex', 'Regulaerer Ausdruck', 'title regex "\\d{4}"'],
            ['gt / lt', 'Groesser/Kleiner', 'relevance_score gt 0.8'],
            ['in', 'In Liste enthalten', 'title in ["KI", "AI"]'],
          ]}
          monoFirstCol
        />

        <h3>Verfuegbare Felder</h3>
        <DocTable
          headers={['Feld', 'Typ', 'Beschreibung']}
          rows={[
            ['title', 'String', 'Alert-Titel'],
            ['snippet', 'String', 'Textausschnitt'],
            ['url', 'String', 'Artikel-URL'],
            ['source', 'Enum', 'google_alerts_rss, rss_feed, manual'],
            ['relevance_score', 'Float', '0.0 - 1.0'],
            ['relevance_decision', 'Enum', 'KEEP, DROP, REVIEW'],
          ]}
          monoFirstCol
        />

        <h3>Aktionen</h3>
        <DocTable
          headers={['Aktion', 'Beschreibung', 'Konfiguration']}
          rows={[
            ['keep', 'Als relevant markieren', '-'],
            ['drop', 'Archivieren', '-'],
            ['tag', 'Tags hinzufuegen', '{"tags": ["wichtig"]}'],
            ['email', 'E-Mail senden', '{"to": "x@y.de"}'],
            ['webhook', 'HTTP POST', '{"url": "https://..."}'],
            ['slack', 'Slack-Nachricht', '{"webhook_url": "..."}'],
          ]}
          monoFirstCol
        />

        {/* KI Relevanzpruefung */}
        <h2>4. KI-Relevanzpruefung</h2>
        <h3>LLM Scorer</h3>
        <DocTable
          headers={['Eigenschaft', 'Wert', 'Beschreibung']}
          rows={[
            ['Gateway URL', 'http://localhost:8000/llm', 'LLM Gateway Endpoint'],
            ['Modell', 'breakpilot-teacher-8b', 'Fein-getuntes Llama 3.1'],
            ['Temperatur', '0.3', 'Niedrig fuer Konsistenz'],
            ['Max Tokens', '500', 'Response-Limit'],
          ]}
        />

        <h3>Bewertungskriterien</h3>
        <div className="not-prose overflow-x-auto">
          <table className="min-w-full text-sm">
            <thead className="bg-slate-50">
              <tr>
                <th className="px-4 py-2 text-left font-semibold">Entscheidung</th>
                <th className="px-4 py-2 text-left font-semibold">Score-Bereich</th>
                <th className="px-4 py-2 text-left font-semibold">Bedeutung</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-200">
              <tr className="bg-green-50"><td className="px-4 py-2 font-semibold text-green-800">KEEP</td><td className="px-4 py-2">0.7 - 1.0</td><td className="px-4 py-2">Klar relevant, in Inbox anzeigen</td></tr>
              <tr className="bg-amber-50"><td className="px-4 py-2 font-semibold text-amber-800">REVIEW</td><td className="px-4 py-2">0.4 - 0.7</td><td className="px-4 py-2">Unsicher, Nutzer entscheidet</td></tr>
              <tr className="bg-red-50"><td className="px-4 py-2 font-semibold text-red-800">DROP</td><td className="px-4 py-2">0.0 - 0.4</td><td className="px-4 py-2">Irrelevant, automatisch archivieren</td></tr>
            </tbody>
          </table>
        </div>

        <h3>Few-Shot Learning</h3>
        <p>Das Profil verbessert sich durch Nutzerfeedback:</p>
        <ol>
          <li>Nutzer markiert Alert als relevant/irrelevant</li>
          <li>Alert wird als positives/negatives Beispiel gespeichert</li>
          <li>Beispiele werden in den Prompt eingefuegt (max. 5 pro Kategorie)</li>
          <li>LLM lernt aus konkreten Beispielen des Nutzers</li>
        </ol>

        {/* Relevanz Profile */}
        <h2>5. Relevanz-Profile</h2>
        <h3>Standard-Bildungsprofil</h3>
        <DocTable
          headers={['Prioritaet', 'Gewicht', 'Keywords']}
          rows={[
            ['Inklusion', '0.9', 'inklusiv, Foerderbedarf, Behinderung'],
            ['Datenschutz Schule', '0.85', 'DSGVO, Schuelerfotos, Einwilligung'],
            ['Schulrecht Bayern', '0.8', 'BayEUG, Schulordnung, KM'],
            ['Digitalisierung Schule', '0.7', 'DigitalPakt, Tablet-Klasse'],
          ]}
        />

        <h3>Standard-Ausschluesse</h3>
        <ul>
          <li>Stellenanzeige</li>
          <li>Praktikum gesucht</li>
          <li>Werbung</li>
          <li>Pressemitteilung</li>
        </ul>

        {/* API Endpoints */}
        <h2>6. API Endpoints</h2>
        <h3>Alerts API</h3>
        <DocTable
          headers={['Endpoint', 'Methode', 'Beschreibung']}
          rows={[
            ['/api/alerts/inbox', 'GET', 'Inbox Items abrufen'],
            ['/api/alerts/ingest', 'POST', 'Manuell Alert importieren'],
            ['/api/alerts/run', 'POST', 'Scoring-Pipeline starten'],
            ['/api/alerts/feedback', 'POST', 'Relevanz-Feedback geben'],
            ['/api/alerts/stats', 'GET', 'Statistiken abrufen'],
          ]}
          monoFirstCol
        />

        <h3>Topics API</h3>
        <DocTable
          headers={['Endpoint', 'Methode', 'Beschreibung']}
          rows={[
            ['/api/alerts/topics', 'GET', 'Topics auflisten'],
            ['/api/alerts/topics', 'POST', 'Neues Topic erstellen'],
            ['/api/alerts/topics/{id}', 'PUT', 'Topic aktualisieren'],
            ['/api/alerts/topics/{id}', 'DELETE', 'Topic loeschen (CASCADE)'],
            ['/api/alerts/topics/{id}/fetch', 'POST', 'Manueller Feed-Abruf'],
          ]}
          monoFirstCol
        />

        <h3>Rules & Profile API</h3>
        <DocTable
          headers={['Endpoint', 'Methode', 'Beschreibung']}
          rows={[
            ['/api/alerts/rules', 'GET/POST', 'Regeln verwalten'],
            ['/api/alerts/rules/{id}', 'PUT/DELETE', 'Regel bearbeiten/loeschen'],
            ['/api/alerts/profile', 'GET', 'Profil abrufen'],
            ['/api/alerts/profile', 'PUT', 'Profil aktualisieren'],
            ['/api/alerts/scheduler/status', 'GET', 'Scheduler-Status'],
          ]}
          monoFirstCol
        />

        {/* Datenbank Schema */}
        <h2>7. Datenbank-Schema</h2>
        <h3>Tabellen</h3>
        <DocTable
          headers={['Tabelle', 'Beschreibung', 'Wichtige Felder']}
          rows={[
            ['alert_topics', 'Feed-Quellen', 'name, feed_url, feed_type, is_active, fetch_interval'],
            ['alert_items', 'Einzelne Alerts', 'title, url, url_hash, relevance_score, relevance_decision'],
            ['alert_rules', 'Filterregeln', 'name, conditions (JSON), action_type, priority'],
            ['alert_profiles', 'Nutzer-Profile', 'priorities, exclusions, positive/negative_examples'],
          ]}
          monoFirstCol
        />

        {/* DSGVO */}
        <h2>8. DSGVO-Konformitaet</h2>
        <h3>Rechtsgrundlage (Art. 6 DSGVO)</h3>
        <DocTable
          headers={['Verarbeitung', 'Rechtsgrundlage', 'Umsetzung']}
          rows={[
            ['Feed-Abruf', 'Art. 6(1)(f) - Berechtigtes Interesse', 'Informationsbeschaffung'],
            ['Alert-Speicherung', 'Art. 6(1)(f) - Berechtigtes Interesse', 'Nur oeffentliche Informationen'],
            ['LLM-Scoring', 'Art. 6(1)(f) - Berechtigtes Interesse', 'On-Premise, keine PII'],
            ['Profil-Learning', 'Art. 6(1)(a) - Einwilligung', 'Opt-in durch Nutzung'],
          ]}
        />

        <h3>Technische Datenschutz-Massnahmen</h3>
        <ul>
          <li><strong>Datenminimierung</strong>: Nur Titel, URL, Snippet - keine personenbezogenen Daten</li>
          <li><strong>Lokale Verarbeitung</strong>: Ollama/vLLM on-premise - kein Datenabfluss an Cloud</li>
          <li><strong>Pseudonymisierung</strong>: UUIDs statt Namen</li>
          <li><strong>Automatische Loeschung</strong>: 90 Tage Retention fuer archivierte Alerts</li>
          <li><strong>Audit-Logging</strong>: Stats und Match-Counts fuer Nachvollziehbarkeit</li>
        </ul>

        {/* Open Source */}
        <h2>9. Open Source Lizenzen (SBOM)</h2>
        <h3>Python Dependencies</h3>
        <DocTable
          headers={['Komponente', 'Lizenz', 'Kommerziell']}
          rows={[
            ['FastAPI', 'MIT', 'Ja'],
            ['SQLAlchemy', 'MIT', 'Ja'],
            ['httpx', 'BSD-3-Clause', 'Ja'],
            ['feedparser', 'BSD-2-Clause', 'Ja'],
            ['APScheduler', 'MIT', 'Ja'],
          ]}
          greenLastCol
        />

        <h3>KI-Komponenten</h3>
        <DocTable
          headers={['Komponente', 'Lizenz', 'Kommerziell']}
          rows={[
            ['Ollama', 'MIT', 'Ja'],
            ['Llama 3.1', 'Meta Llama 3', 'Ja*'],
            ['vLLM', 'Apache-2.0', 'Ja'],
          ]}
          greenLastCol
        />

        {/* Kontakt */}
        <h2>10. Kontakt & Support</h2>
        <DocTable
          headers={['Kontakt', 'Adresse']}
          rows={[
            ['Technischer Support', 'support@breakpilot.de'],
            ['Datenschutzbeauftragter', 'dsb@breakpilot.de'],
            ['Dokumentation', 'docs.breakpilot.de'],
            ['GitHub', 'github.com/breakpilot'],
          ]}
        />

        {/* Footer */}
        <div className="not-prose mt-8 pt-6 border-t border-slate-200 text-sm text-slate-500">
          <p>Dokumentation erstellt: Januar 2026 | Version: 1.0.0</p>
        </div>
      </div>
    </div>
  )
}

/* ------------------------------------------------------------------ */
/*  Helper component for repetitive doc tables                         */
/* ------------------------------------------------------------------ */

interface DocTableProps {
  headers: string[]
  rows: string[][]
  monoFirstCol?: boolean
  greenLastCol?: boolean
}

function DocTable({ headers, rows, monoFirstCol, greenLastCol }: DocTableProps) {
  return (
    <div className="not-prose overflow-x-auto">
      <table className="min-w-full text-sm">
        <thead className="bg-slate-50">
          <tr>
            {headers.map((h) => (
              <th key={h} className="px-4 py-2 text-left font-semibold">{h}</th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-slate-200">
          {rows.map((row, ri) => (
            <tr key={ri}>
              {row.map((cell, ci) => (
                <td
                  key={ci}
                  className={`px-4 py-2${ci === 0 && monoFirstCol ? ' font-mono text-xs' : ''}${ci === row.length - 1 && greenLastCol ? ' text-green-600' : ''}`}
                >
                  {cell}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

/* ------------------------------------------------------------------ */
/*  ASCII diagrams kept as constants to avoid JSX noise                */
/* ------------------------------------------------------------------ */

const ARCHITECTURE_DIAGRAM = `\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
\u2502                         BreakPilot Alerts Frontend                           \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502
\u2502  \u2502  Dashboard   \u2502  \u2502    Inbox     \u2502  \u2502   Topics     \u2502  \u2502   Profile    \u2502    \u2502
\u2502  \u2502  (Stats)     \u2502  \u2502  (Review)    \u2502  \u2502   (Feeds)    \u2502  \u2502  (Learning)  \u2502    \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
                                  \u2502
                                  v
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
\u2502                            Ingestion Layer                                   \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                 \u2502
\u2502  \u2502  RSS Fetcher   \u2502  \u2502  Email Parser  \u2502  \u2502  APScheduler   \u2502                 \u2502
\u2502  \u2502  (feedparser)  \u2502  \u2502  (geplant)     \u2502  \u2502  (AsyncIO)     \u2502                 \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                 \u2502
\u2502          \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                          \u2502
\u2502                              \u2502                                               \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510           \u2502
\u2502  \u2502              Deduplication (URL-Hash + SimHash)               \u2502           \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518           \u2502
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
                                  \u2502
                                  v
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
\u2502                           Processing Layer                                   \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510             \u2502
\u2502  \u2502                    Rule Engine                              \u2502             \u2502
\u2502  \u2502  Operatoren: contains, regex, gt/lt, in, starts_with        \u2502             \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518             \u2502
\u2502                              \u2502                                               \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510             \u2502
\u2502  \u2502                 LLM Relevance Scorer                        \u2502             \u2502
\u2502  \u2502  Output: { score, decision: KEEP/DROP/REVIEW, summary }    \u2502             \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518             \u2502
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
                                  \u2502
                                  v
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
\u2502                            Action Layer                                      \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                 \u2502
\u2502  \u2502  Email Action  \u2502  \u2502 Webhook Action \u2502  \u2502  Slack Action  \u2502                 \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                 \u2502
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
                                  \u2502
                                  v
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
\u2502                           Storage Layer                                      \u2502
\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                 \u2502
\u2502  \u2502   PostgreSQL   \u2502  \u2502     Valkey     \u2502  \u2502   LLM Gateway  \u2502                 \u2502
\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                 \u2502
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518`

const DATAFLOW_DIAGRAM = `1. APScheduler triggert Fetch (alle 60 Min. default)
           \u2502
           v
2. RSS Fetcher holt Feed von Google Alerts
           \u2502
           v
3. Deduplizierung prueft URL-Hash
           \u2502
           \u251c\u2500\u2500 URL bekannt \u2500\u2500> Uebersprungen
           \u2514\u2500\u2500 URL neu \u2500\u2500> Weiter
                   \u2502
                   v
4. Alert in Datenbank gespeichert (Status: NEW)
           \u2502
           v
5. Rule Engine evaluiert aktive Regeln
           \u2502
           \u251c\u2500\u2500 Regel matcht \u2500\u2500> Aktion ausfuehren
           \u2514\u2500\u2500 Keine Regel \u2500\u2500> LLM Scoring
                   \u2502
                   v
6. LLM Relevance Scorer
           \u2502
           \u251c\u2500\u2500 KEEP (>= 0.7) \u2500\u2500> Inbox
           \u251c\u2500\u2500 REVIEW (0.4-0.7) \u2500\u2500> Inbox (Pruefung)
           \u2514\u2500\u2500 DROP (< 0.4) \u2500\u2500> Archiviert
                   \u2502
                   v
7. Nutzer-Feedback \u2500\u2500> Profile aktualisieren`
