{
  "schema": "ldwf",
  "version": 1,
  "name": "Pressemitteilungs-Monitoring",
  "meta": {
    "exportedAt": "2025-11-16T16:51:49.414Z",
    "exporter": "client"
  },
  "graph": {
    "nodes": [
      {
        "type": "action",
        "data": {
          "comment": "📤 SCHRITT 7: Slack-Nachricht senden\n\nBESCHREIBUNG:\nSendet das formatierte News-Briefing an einen Slack-Channel Ihrer Wahl. Das Team erhält jeden Morgen automatisch die wichtigsten Branchen-News.\n\nSETUP:\n⚠️ ERFORDERLICH: Konfiguration anpassen!\n1. Slack-Verbindung: Wählen Sie Ihre Slack-Integration unter 'Connection'\n2. Channel: Ersetzen Sie '#news-briefing' durch Ihren gewünschten Channel\n   - Format: '#channel-name' oder '@username' für DMs\n   - Channel muss existieren und der Bot muss Mitglied sein\n\nCHANNEL-BEISPIELE:\n- #general - Haupt-Channel\n- #team-updates - Team-spezifisch\n- #executive-briefing - Führungskräfte\n- @max.mustermann - Direkte Nachricht an Person\n\nPERSONALISIERUNG:\n✏️ Mehrere Channels: Duplizieren Sie diesen Node, um an mehrere Channels zu senden\n✏️ Bedingtes Senden: Fügen Sie einen Condition-Node davor ein, um nur bei relevanten News zu senden (z.B. nur wenn total_count > 0)\n✏️ Alternative Plattformen: Ersetzen Sie durch Teams, Email oder andere Messaging-Actions\n✏️ Thread-Antworten: Konfigurieren Sie 'thread_ts' für Antworten in bestehenden Threads",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "sendSlackMessage",
          "actionId": "26a39d11-d5fe-4f46-b776-973dd20b8147",
          "config": {
            "connectionId": null,
            "requiresConfirmation": false,
            "modelId": "c968689a-c0d9-49de-aa76-b10ed15ebb0e",
            "fields": {
              "text": {
                "mode": "manual",
                "value": "{{formatBriefing.output.message}}",
                "prompt": null
              },
              "channelId": {
                "mode": "manual",
                "value": "#news-briefing",
                "prompt": null
              }
            }
          }
        },
        "id": "ddb764cf-f604-4aeb-9cb1-5959ca2a8f3d",
        "position": {
          "x": 3344,
          "y": 2300
        }
      },
      {
        "type": "trigger",
        "data": {
          "comment": "📅 SCHRITT 1: Zeitgesteuerter Trigger\n\nBESCHREIBUNG:\nDieser Trigger startet den Workflow automatisch jeden Morgen um 7:00 Uhr. Er ist der Startpunkt für die tägliche News-Aggregation.\n\nSETUP:\n- Cron-Ausdruck: '0 7 * * *' bedeutet täglich um 7:00 Uhr\n- Zeitzone: Server-Zeitzone (UTC)\n\nPERSONALISIERUNG:\n✏️ Zeitpunkt ändern: Passen Sie den Cron-Ausdruck an:\n  - '0 6 * * *' = 6:00 Uhr\n  - '0 9 * * 1-5' = 9:00 Uhr nur Montag-Freitag\n  - '0 */4 * * *' = Alle 4 Stunden\n  - '0 7 * * 1' = Jeden Montag um 7:00 Uhr",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "daily7amTrigger",
          "name": "Täglich 7:00 Uhr",
          "kind": "scheduled",
          "cron": "0 7 * * *"
        },
        "id": "d2215086-9b88-4c8a-9fde-c8d4ab06c47f",
        "position": {
          "x": 20,
          "y": 2300
        }
      },
      {
        "type": "http_request",
        "data": {
          "comment": "🌐 SCHRITT 2: RSS-Feeds abrufen\n\nBESCHREIBUNG:\nRuft die RSS/Atom-Feeds von Branchen-Nachrichtenquellen ab. Der Node macht einen HTTP GET-Request und liefert den XML-Inhalt zurück.\n\nSETUP:\n⚠️ ERFORDERLICH: Ersetzen Sie die Beispiel-URL durch echte RSS-Feed-URLs!\n\nBeispiele für RSS-Feeds:\n- TechCrunch: https://techcrunch.com/feed/\n- Heise: https://www.heise.de/rss/heise.rdf\n- Handelsblatt Tech: https://www.handelsblatt.com/technik/?rss\n- Branchenspezifische Feeds Ihrer Wahl\n\nPERSONALISIERUNG:\n✏️ Mehrere Feeds: Um mehrere Feeds zu verwenden, duplizieren Sie diesen Node oder verwenden Sie einen Code-Node, der mehrere URLs nacheinander abruft\n✏️ Authentifizierung: Falls der Feed geschützt ist, fügen Sie unter 'Headers' einen Authorization-Header hinzu\n✏️ Custom Headers: Fügen Sie User-Agent oder andere Headers hinzu, falls erforderlich",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "name": "RSS-Feeds abrufen",
          "slug": "fetchRssFeeds",
          "url": {
            "mode": "manual",
            "value": "https://example.com/rss-feed.xml"
          },
          "method": "GET",
          "body": {
            "mode": "manual",
            "value": ""
          },
          "queryParams": [],
          "headers": []
        },
        "id": "abf99d48-ad4b-4652-ae85-01286c59f38e",
        "position": {
          "x": 560,
          "y": 2300
        }
      },
      {
        "type": "code",
        "data": {
          "comment": "✨ SCHRITT 6: Briefing formatieren\n\nBESCHREIBUNG:\nFormatiert die kategorisierten Artikel in ein professionelles, lesbares Slack-Briefing mit Emojis, Struktur und Links. Erstellt eine fertige Nachricht, die direkt gepostet werden kann.\n\nSETUP:\nFunktioniert automatisch - keine Konfiguration erforderlich!\n\nAUSGABE-FORMAT:\n- Header mit Datum und Gesamtzahl relevanter Artikel\n- Kategorien mit Emojis (🎯, ⚖️, 🚀, 📈, 📄)\n- Nummerierte Artikel mit Titel, Zusammenfassung und Link\n- Footer mit Zeitstempel\n\nPERSONALISIERUNG:\n✏️ Sprache: Ändern Sie die deutschen Texte zu Englisch/anderen Sprachen\n✏️ Datumsformat: Passen Sie 'de-DE' zu 'en-US', 'fr-FR' etc. an\n✏️ Emojis: Ändern Sie die Kategorie-Emojis nach Ihrem Geschmack\n✏️ Struktur: Fügen Sie zusätzliche Abschnitte hinzu (z.B. Top-Story, Statistiken)\n✏️ Kategorien: Wenn Sie in Schritt 5 Kategorien geändert haben, passen Sie die formatCategory-Aufrufe entsprechend an\n✏️ Styling: Ändern Sie Slack-Formatierung (*bold*, _italic_, etc.)",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "name": "Briefing formatieren",
          "slug": "formatBriefing",
          "language": "javascript",
          "code": "// Format the final news briefing for Slack\nconst categorizedArticles = summarizeAndCategorize.output.structured;\nconst totalRelevant = filterRelevantArticles.output.structured.total_count;\n\n// Helper function to format articles in a category\nfunction formatCategory(categoryName, articles) {\n  if (!articles || articles.length === 0) return '';\n  \n  let section = `\\n\\n*${categoryName}*\\n`;\n  articles.forEach((article, index) => {\n    section += `${index + 1}. *${article.title || 'Kein Titel'}*\\n`;\n    section += `   ${article.summary || article.description || 'Keine Zusammenfassung verfügbar'}\\n`;\n    if (article.link) {\n      section += `   🔗 <${article.link}|Artikel lesen>\\n`;\n    }\n    section += `\\n`;\n  });\n  \n  return section;\n}\n\n// Build the briefing message\nconst today = new Date().toLocaleDateString('de-DE', { \n  weekday: 'long', \n  year: 'numeric', \n  month: 'long', \n  day: 'numeric' \n});\n\nlet briefing = `📰 *Tägliches News-Briefing - ${today}*\\n`;\nbriefing += `─────────────────────────\\n`;\nbriefing += `\\n📊 *${totalRelevant} relevante Meldungen* aus den letzten 24 Stunden\\n`;\n\n// Add each category\nbriefing += formatCategory('🎯 WETTBEWERB', categorizedArticles.wettbewerb);\nbriefing += formatCategory('⚖️ REGULIERUNG', categorizedArticles.regulierung);\nbriefing += formatCategory('🚀 TECHNOLOGIE', categorizedArticles.technologie);\nbriefing += formatCategory('📈 MARKTTRENDS', categorizedArticles.markttrends);\nbriefing += formatCategory('📄 SONSTIGES', categorizedArticles.sonstiges);\n\n// Add footer\nbriefing += `\\n─────────────────────────\\n`;\nbriefing += `_Automatisch generiert um ${new Date().toLocaleTimeString('de-DE')}_`;\n\nld.log(`Briefing created with ${totalRelevant} articles`);\n\nreturn {\n  message: briefing,\n  articleCount: totalRelevant\n};"
        },
        "id": "b1efbf2a-82c3-4895-8373-ace143eacd12",
        "position": {
          "x": 2800,
          "y": 2300
        }
      },
      {
        "type": "agent",
        "data": {
          "comment": "📚 SCHRITT 5: KI-Zusammenfassung & Kategorisierung\n\nBESCHREIBUNG:\nEin LLM erstellt prägnante Zusammenfassungen der relevanten Artikel und ordnet sie thematischen Kategorien zu. Das Ergebnis ist strukturiert und bereit für das Briefing-Format.\n\nSETUP:\nFunktioniert automatisch mit den gefilterten Artikeln aus Schritt 4.\n\nKATEGORIEN:\n1. 🎯 Wettbewerb - Aktivitäten von Konkurrenten\n2. ⚖️ Regulierung - Gesetzliche Änderungen, Compliance\n3. 🚀 Technologie - Neue Tech-Entwicklungen, Tools\n4. 📈 Markttrends - Branchenentwicklungen, Statistiken\n5. 📄 Sonstiges - Alle anderen relevanten Themen\n\nPERSONALISIERUNG:\n✏️ Kategorien anpassen: Ändern Sie die Liste im Prompt UND im Output-Schema:\n  - Beispiele: 'Produktneuheiten', 'Partnerschaften', 'Investitionen'\n  - Fügen Sie neue Felder im outputSchema hinzu/entfernen Sie bestehende\n✏️ Zusammenfassungslänge: Passen Sie \"max. 2-3 Sätze\" im Prompt an (z.B. \"1 Satz\", \"ausführlicher Absatz\")\n✏️ Sprache: Ändern Sie die Prompt-Sprache für englische Zusammenfassungen\n✏️ Zusatzinformationen: Erweitern Sie den Prompt um Sentiment-Analyse oder Impact-Bewertung",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "summarizeAndCategorize",
          "assistantId": null,
          "mode": "create",
          "name": "Zusammenfassung & Kategorisierung",
          "prompt": {
            "mode": "manual",
            "value": "Du bist ein Experte für die Erstellung prägnanter News-Briefings. Deine Aufgabe ist es, die relevanten Artikel zusammenzufassen und zu kategorisieren.\n\nHier sind die relevanten Artikel:\n{{filterRelevantArticles.output.structured.relevant_articles}}\n\nFür jeden Artikel:\n1. Erstelle eine kompakte Zusammenfassung (max. 2-3 Sätze)\n2. Kategorisiere ihn nach einem dieser Themengebiete:\n   - Wettbewerb\n   - Regulierung\n   - Technologie\n   - Markttrends\n   - Sonstiges\n\nStrukturiere das Ergebnis so, dass es direkt als News-Briefing verwendet werden kann. Gruppiere die Artikel nach Kategorien."
          },
          "attachmentIds": [],
          "output": "structured",
          "connectionOverrides": {},
          "outputSchema": [
            {
              "id": "ce8bf2aa-182d-404a-8d09-77d10b941e36",
              "name": "wettbewerb",
              "description": "Artikel zur Kategorie Wettbewerb",
              "type": "array",
              "required": false
            },
            {
              "id": "ef6385aa-bc45-44f7-b2c9-336ca711fa08",
              "name": "regulierung",
              "description": "Artikel zur Kategorie Regulierung",
              "type": "array",
              "required": false
            },
            {
              "id": "cdd87c06-eb8c-42a7-a9b8-25ac0513b82e",
              "name": "technologie",
              "description": "Artikel zur Kategorie Technologie",
              "type": "array",
              "required": false
            },
            {
              "id": "fcdeb139-fc02-4d10-a872-7e1afbe04c8e",
              "name": "markttrends",
              "description": "Artikel zur Kategorie Markttrends",
              "type": "array",
              "required": false
            },
            {
              "id": "1b3fd3a1-f6f8-4b08-b547-ce96ccd9b0a3",
              "name": "sonstiges",
              "description": "Artikel zur Kategorie Sonstiges",
              "type": "array",
              "required": false
            }
          ],
          "modelId": "c968689a-c0d9-49de-aa76-b10ed15ebb0e",
          "tools": [],
          "maxSteps": 25
        },
        "id": "c6f604f3-fd10-4af9-80aa-a2cda25684ed",
        "position": {
          "x": 2240,
          "y": 2300
        }
      },
      {
        "type": "agent",
        "data": {
          "comment": "🎯 SCHRITT 4: KI-Relevanzfilter\n\nBESCHREIBUNG:\nEin LLM analysiert alle gesammelten Artikel und filtert nur die für Ihr Unternehmen relevanten Meldungen heraus. Verwendet Keywords, Themengebiete und einen Relevanz-Score zur Bewertung.\n\nSETUP:\n⚠️ ERFORDERLICH: Passen Sie die Keywords im Prompt an!\nErsetzen Sie '[HIER KEYWORDS EINFÜGEN...]' durch Ihre spezifischen Keywords.\n\nBeispiel-Keywords:\n- Branchenbegriffe: \"SaaS\", \"Cloud Computing\", \"Enterprise Software\"\n- Wettbewerber: \"Salesforce\", \"Microsoft\", \"SAP\"\n- Technologien: \"Künstliche Intelligenz\", \"Machine Learning\", \"API\"\n- Produkte: \"CRM\", \"ERP\", \"Analytics\"\n\nPERSONALISIERUNG:\n✏️ Filterkriterien: Ändern Sie die Themengebiete im Prompt (aktuell: Technologie-Trends, Regulierung, Wettbewerb, Marktentwicklungen)\n✏️ Relevanz-Schwelle: Passen Sie an, ob nur hohe Relevanz oder auch mittlere/niedrige Relevanz akzeptiert wird\n✏️ Ausgabeformat: Das Output-Schema kann erweitert werden (z.B. zusätzliche Felder wie 'priority' oder 'sentiment')\n✏️ Modell: Wechseln Sie zu einem anderen LLM-Modell für bessere/schnellere Ergebnisse",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "filterRelevantArticles",
          "assistantId": null,
          "mode": "create",
          "name": "Relevanz-Filter",
          "prompt": {
            "mode": "manual",
            "value": "Du bist ein Experte für die Analyse von Branchen-Nachrichten. Deine Aufgabe ist es, aus einer Liste von News-Artikeln nur die für unser Unternehmen relevanten Meldungen herauszufiltern.\n\nHier sind die Artikel der letzten 24 Stunden:\n{{parseRssFeed.output.articles}}\n\nFilterkriterien:\n- Keywords: [HIER KEYWORDS EINFÜGEN - z.B. \"KI\", \"Machine Learning\", \"Automation\", \"Wettbewerber-Namen\"]\n- Themengebiete: Technologie-Trends, Regulierung, Wettbewerb, Marktentwicklungen\n- Relevanz-Score: Nur Artikel mit hoher oder mittlerer Relevanz für unser Geschäft\n\nBewerte jeden Artikel und gib nur die relevanten zurük. Für jeden relevanten Artikel gib an:\n- Titel\n- Link\n- Kurze Begründung der Relevanz\n- Relevanz-Score (1-10)"
          },
          "attachmentIds": [],
          "output": "structured",
          "connectionOverrides": {},
          "outputSchema": [
            {
              "id": "456c0de9-5881-46a7-b7d4-40f5cfc3f4dc",
              "name": "relevant_articles",
              "description": "Liste der relevanten Artikel",
              "type": "array",
              "required": true
            },
            {
              "id": "53a2786b-976f-45db-8bdf-4ca6eeabe06a",
              "name": "total_count",
              "description": "Anzahl der relevanten Artikel",
              "type": "number",
              "required": true
            }
          ],
          "modelId": "c968689a-c0d9-49de-aa76-b10ed15ebb0e",
          "tools": [],
          "maxSteps": 25
        },
        "id": "d20dc3da-92a4-470f-b4c8-ee83d79a0a36",
        "position": {
          "x": 1680,
          "y": 2300
        }
      },
      {
        "type": "code",
        "data": {
          "comment": "📋 SCHRITT 3: RSS-Feed parsen & Zeitfilter\n\nBESCHREIBUNG:\nParst den XML-Inhalt des RSS-Feeds und extrahiert alle Artikel. Filtert anschließend nur Artikel, die in den letzten 24 Stunden veröffentlicht wurden.\n\nSETUP:\nFunktioniert automatisch - keine Konfiguration erforderlich!\nUnterstützt sowohl RSS 2.0 (<item>) als auch Atom (<entry>) Feeds.\n\nWAS WIRD EXTRAHIERT:\n- Titel des Artikels\n- Link zum Artikel\n- Beschreibung/Zusammenfassung\n- Veröffentlichungsdatum\n\nPERSONALISIERUNG:\n✏️ Zeitfenster ändern: Ändern Sie '24 * 60 * 60 * 1000' zu:\n  - 12 Stunden: '12 * 60 * 60 * 1000'\n  - 48 Stunden: '48 * 60 * 60 * 1000'\n  - 7 Tage: '7 * 24 * 60 * 60 * 1000'\n✏️ Zusätzliche Felder: Erweitern Sie die Regex-Patterns um weitere XML-Tags (z.B. author, category)\n✏️ Mehrere Feeds: Wenn Sie mehrere Feeds kombinieren möchten, passen Sie den Code an, um Arrays zusammenzuführen",
          "executionId": null,
          "errorHandling": {
            "strategy": "stop"
          },
          "name": "RSS-Feed parsen",
          "slug": "parseRssFeed",
          "language": "javascript",
          "code": "// Parse RSS feed XML and extract articles from last 24 hours\nconst rssXml = fetchRssFeeds.output;\n\n// Simple XML parser for RSS feeds\nfunction parseRSS(xmlString) {\n  const items = [];\n  \n  // Extract all <item> or <entry> tags\n  const itemRegex = /<item[^>]*>([\\s\\S]*?)<\\/item>|<entry[^>]*>([\\s\\S]*?)<\\/entry>/gi;\n  const matches = xmlString.matchAll(itemRegex);\n  \n  for (const match of matches) {\n    const itemContent = match[1] || match[2];\n    \n    // Extract fields\n    const title = itemContent.match(/<title[^>]*><!\\[CDATA\\[([^\\]]+)\\]\\]><\\/title>|<title[^>]*>([^<]+)<\\/title>/i);\n    const link = itemContent.match(/<link[^>]*>([^<]+)<\\/link>/i);\n    const description = itemContent.match(/<description[^>]*><!\\[CDATA\\[([^\\]]+)\\]\\]><\\/description>|<description[^>]*>([^<]+)<\\/description>/i);\n    const pubDate = itemContent.match(/<pubDate[^>]*>([^<]+)<\\/pubDate>|<published[^>]*>([^<]+)<\\/published>/i);\n    \n    items.push({\n      title: title ? (title[1] || title[2] || '').trim() : '',\n      link: link ? link[1].trim() : '',\n      description: description ? (description[1] || description[2] || '').trim() : '',\n      pubDate: pubDate ? (pubDate[1] || pubDate[2] || '').trim() : ''\n    });\n  }\n  \n  return items;\n}\n\n// Parse the RSS feed\nconst allArticles = parseRSS(rssXml);\n\n// Filter articles from last 24 hours\nconst oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\nconst recentArticles = allArticles.filter(article => {\n  if (!article.pubDate) return false;\n  const articleDate = new Date(article.pubDate);\n  return articleDate > oneDayAgo;\n});\n\nld.log(`Found ${recentArticles.length} articles from the last 24 hours out of ${allArticles.length} total articles`);\n\nreturn {\n  articles: recentArticles,\n  count: recentArticles.length\n};"
        },
        "id": "ce6c5daa-7c44-4ec2-9a68-c48f1540a81f",
        "position": {
          "x": 1120,
          "y": 2300
        }
      }
    ],
    "edges": [
      {
        "id": "b8ae618d-08fb-4fb9-b571-0c0373fbf1f2",
        "source": "d2215086-9b88-4c8a-9fde-c8d4ab06c47f",
        "target": "abf99d48-ad4b-4652-ae85-01286c59f38e",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "531fceb4-c633-4fa2-b55d-46ee6de8b044",
        "source": "abf99d48-ad4b-4652-ae85-01286c59f38e",
        "target": "ce6c5daa-7c44-4ec2-9a68-c48f1540a81f",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "1dbea032-ceb7-415e-b41b-a6a99816b783",
        "source": "ce6c5daa-7c44-4ec2-9a68-c48f1540a81f",
        "target": "d20dc3da-92a4-470f-b4c8-ee83d79a0a36",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "f7ffd692-3f3e-4121-a262-ed049e380e61",
        "source": "d20dc3da-92a4-470f-b4c8-ee83d79a0a36",
        "target": "c6f604f3-fd10-4af9-80aa-a2cda25684ed",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "90033905-96d2-4009-88c5-622768d5cf5b",
        "source": "c6f604f3-fd10-4af9-80aa-a2cda25684ed",
        "target": "b1efbf2a-82c3-4895-8373-ace143eacd12",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "507737b7-8f12-483a-9d0c-7f7ae00c90e0",
        "source": "b1efbf2a-82c3-4895-8373-ace143eacd12",
        "target": "ddb764cf-f604-4aeb-9cb1-5959ca2a8f3d",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      }
    ]
  }
}