{
  "name": "PF \u2013 WF-03 Social Media Post v5",
  "nodes": [
    {
      "parameters": {
        "content": "## PF \u2013 WF-03 Social Media Auto-Post v4\n\n**Ablauf:**\nSharePoint (Status=Freigegeben)\n\u2192 Felder aufbereiten\n\u2192 Claude API + Canva MCP:\n   \u2022 Template DAHJW-GJz68 duplizieren\n   \u2022 [THEMA] ersetzen\n   \u2022 Als JPG exportieren\n   \u2022 URL zur\u00fcckgeben\n\u2192 Instagram: Media Container + Ver\u00f6ffentlichen\n\u2192 Facebook: Beitrag\n\u2192 SharePoint: Status = Ver\u00f6ffentlicht\n\u2192 Teams: Erfolgsmeldung\n\n**Judith muss NUR:**\n1. Thema + Caption in SharePoint eintragen\n2. Status auf Freigegeben setzen\n\u2192 Alles andere l\u00e4uft automatisch!\n\n**Environment Variables:**\nANTHROPIC_API_KEY = sk-ant-...\nSHAREPOINT_SITE_ID = ...\nSHAREPOINT_LIST_ID = ...\nFB_PAGE_ID = ...\nTEAMS_TEAM_ID = ...\nTEAMS_CHANNEL_ID = ...",
        "height": 300,
        "width": 1060,
        "color": 5
      },
      "id": "sticky-main",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "content": "**Changelog:**\n\nv4 \u2013 2026-05-11\n\u2022 Claude API + Canva MCP\n\u2022 Template DAHJW-GJz68\n\u2022 Vollautomatisch!\n\u2022 Kein manueller Export\n\nv3 \u2013 2026-05-11\n\u2022 Manueller Export n\u00f6tig\n\u2022 Medienbruch\n\nv2 \u2013 2026-05-11\n\u2022 Canva OAuth Problem\n\nv1 \u2013 2026-05-11\n\u2022 Autofill (Enterprise)",
        "width": 220,
        "color": 6
      },
      "id": "sticky-changelog",
      "name": "Changelog v4",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2600,
        260
      ]
    },
    {
      "parameters": {
        "content": "**\u26a0\ufe0f Canva Template vorbereiten:**\n\n1. Design DAHJW-GJz68 in Canva \u00f6ffnen\n2. Text-Element f\u00fcr das Thema\n   exakt so beschriften: [THEMA]\n3. Design auf PUBLIC stellen\n   (Teilen \u2192 \u00d6ffentlich)\n\nClaude ersetzt [THEMA] automatisch\nmit dem Wert aus field_1 (Thema).",
        "width": 280,
        "color": 3
      },
      "id": "sticky-canva-prep",
      "name": "Canva Vorbereitung",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1120,
        0
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "daysInterval": 1,
              "triggerAtHour": 9,
              "triggerAtMinute": 0
            }
          ]
        }
      },
      "id": "trigger-schedule",
      "name": "Trigger: t\u00e4glich 9:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        240,
        400
      ]
    },
    {
      "parameters": {
        "resource": "item",
        "site": {
          "__rl": true,
          "value": "physiofuchs889.sharepoint.com,c74040a2-0d6b-4385-b514-fbd9830a56ac,7a7842d6-ea6c-440d-aeed-580bdd2a091c",
          "mode": "list",
          "cachedResultName": "Physio Fuchs Administration"
        },
        "list": {
          "__rl": true,
          "value": "d17a6a6f-e6ef-457d-a2a9-4c30ea56120f",
          "mode": "list",
          "cachedResultName": "PF-Content-Kalender-2026"
        },
        "filter": "=",
        "options": {
          "fields": [
            "fields"
          ]
        },
        "simplify": false,
        "requestOptions": {}
      },
      "id": "sp-get-items",
      "name": "SharePoint: Freigegebene Posts",
      "type": "n8n-nodes-base.microsoftSharePoint",
      "typeVersion": 1,
      "position": [
        460,
        400
      ],
      "credentials": {
        "microsoftSharePointOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// WF-03 v5 Filter: nur Items, die wirklich gepostet werden sollen\n// Returns gefilterte Items, plus auf jedem Item ein 'debug'-Feld.\n\nconst POOL_OK_STATUSES = ['Freigegeben'];\n\nconst todayIso = new Date().toISOString().slice(0,10);\n\nconst result = [];\nconst skipped = [];\n\nfor (const item of $input.all()) {\n  const j = item.json;\n  const f = j.Felder ?? j.fields ?? {};\n  const status      = f.field_6;\n  const thema       = f.field_1;\n  const caption     = f.field_10;\n  const hashtags    = f.field_7 ?? '';\n  const canvaTplId  = f.field_9;\n  const datumRaw    = f.Ver_x00f6_ffentlichungsdatum;\n  const uhrzeit     = f.field_5 ?? '09:00';\n  const itemId      = j.id ?? j.Ausweis ?? f.AUSWEIS;\n  const post_typ    = f.field_2 ?? 'Standard';\n\n  const reasons = [];\n  if (!POOL_OK_STATUSES.includes(status)) reasons.push(`status=${status}`);\n  if (!thema) reasons.push('thema_leer');\n  if (!caption) reasons.push('caption_leer');\n  if (!datumRaw) reasons.push('datum_leer');\n  else {\n    const datumIso = new Date(datumRaw).toISOString().slice(0,10);\n    if (datumIso > todayIso) reasons.push(`datum_zukunft (${datumIso} > ${todayIso})`);\n  }\n\n  if (reasons.length > 0) {\n    skipped.push({ id: itemId, title: f.Titel ?? f.Title, reasons });\n    continue;\n  }\n\n  // Item passiert den Filter \u2014 mit aufbereiteten Top-Level-Feldern weitergeben\n  result.push({ json: {\n    item_id: itemId,\n    thema,\n    caption,\n    hashtags,\n    caption_with_hashtags: caption + (hashtags ? ('\\n\\n' + hashtags) : ''),\n    canva_template_id: canvaTplId ?? 'DAHJW-GJz68',\n    datum: datumRaw,\n    uhrzeit,\n    post_typ,\n    debug_passed: true\n  }});\n}\n\nif (result.length === 0) {\n  // Diagnose-Item zur\u00fcckgeben damit man sieht warum nichts durchgeht\n  return [{ json: {\n    info: 'Kein Item bereit zum Posten',\n    today: todayIso,\n    total_items: $input.all().length,\n    skipped_first_10: skipped.slice(0,10)\n  }}];\n}\n\nreturn result;\n"
      },
      "id": "00000000-0000-0000-0000-0000000a0030",
      "name": "Filter: Bereit zum Posten",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        680,
        400
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": []
        },
        "options": {}
      },
      "id": "00000000-0000-0000-0000-0000000a0031",
      "name": "Felder aufbereiten",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        900,
        280
      ],
      "notes": "Pass-through. Filter-Node hat alle Felder bereits flach gemacht (item_id, thema, caption, hashtags, caption_with_hashtags, canva_template_id, datum, uhrzeit, post_typ)."
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $env.ANTHROPIC_API_KEY }}"
            },
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "anthropic-beta",
              "value": "mcp-client-2025-04-04"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyContentType": "json",
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"claude-sonnet-4-6\",\n  \"max_tokens\": 1024,\n  \"system\": \"Du bist ein Canva-Automatisierungsassistent f\u00fcr Physio Fuchs. F\u00fchre exakt die angeforderten Canva-Aktionen aus. Gib am Ende NUR die Export-Download-URL zur\u00fcck \u2013 keinen anderen Text, keine Erkl\u00e4rungen, nur die URL.\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"F\u00fchre folgende Schritte f\u00fcr Physio Fuchs Instagram-Post aus:\\n\\n1. \u00d6ffne das Design mit ID: {{ $(\"Felder aufbereiten\").item.json.canva_template_id }}\\n2. Starte eine Editing-Transaktion\\n3. Ersetze den Text [THEMA] durch: {{ $(\"Felder aufbereiten\").item.json.thema }}\\n4. Ersetze den Text [DATUM] durch: {{ $(\"Felder aufbereiten\").item.json.datum ? new Date($(\"Felder aufbereiten\").item.json.datum).toLocaleDateString(\"de-DE\") : \"\" }}\\n5. Committe die Transaktion\\n6. Exportiere das Design als JPG (h\u00f6chste Qualit\u00e4t)\\n7. Gib NUR die Download-URL zur\u00fcck\\n\\nNur die URL, kein anderer Text.\"\n    }\n  ],\n  \"mcp_servers\": [\n    {\n      \"type\": \"url\",\n      \"url\": \"https://mcp.canva.com/mcp\",\n      \"name\": \"canva\",\n      \"authorization_token\": \"{{ $json.access_token }}\"\n    }\n  ]\n}",
        "options": {}
      },
      "id": "claude-canva-export",
      "name": "Claude + Canva: Design exportieren",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1120,
        280
      ]
    },
    {
      "parameters": {
        "jsCode": "// Claude API Response verarbeiten\nconst response = $input.item.json;\n\nlet imageUrl = '';\nif (response.content && Array.isArray(response.content)) {\n  for (const block of response.content) {\n    if (block.type === 'text' && block.text) {\n      const text = block.text.trim();\n      const urlMatch = text.match(/https:\\/\\/[^\\s]+/);\n      if (urlMatch) { imageUrl = urlMatch[0]; break; }\n    }\n  }\n}\nif (!imageUrl) throw new Error('Keine Bild-URL in Claude Response: ' + JSON.stringify(response.content));\n\nconst prev = $('Felder aufbereiten').item.json;\nreturn {\n  image_url: imageUrl,\n  caption: prev.caption,\n  caption_with_hashtags: prev.caption_with_hashtags,\n  hashtags: prev.hashtags,\n  thema: prev.thema,\n  post_typ: prev.post_typ,\n  item_id: prev.item_id\n};"
      },
      "id": "url-extrahieren",
      "name": "Bild-URL extrahieren",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        280
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://graph.facebook.com/v25.0/17841461169626096/media",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "facebookGraphApi",
        "sendBody": true,
        "bodyContentType": "json",
        "specifyBody": "fieldsBelow",
        "bodyParameters": {
          "parameters": [
            {
              "name": "image_url",
              "value": "={{ $json.image_url }}"
            },
            {
              "name": "caption",
              "value": "={{ $json.caption_with_hashtags }}"
            }
          ]
        },
        "options": {}
      },
      "id": "ig-media-container",
      "name": "Instagram: Media Container erstellen",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1560,
        280
      ],
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "amount": 15,
        "unit": "seconds"
      },
      "id": "warten-ig",
      "name": "Warten 15s (Instagram Processing)",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        1780,
        280
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://graph.facebook.com/v25.0/17841461169626096/media_publish",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "facebookGraphApi",
        "sendBody": true,
        "bodyContentType": "json",
        "specifyBody": "fieldsBelow",
        "bodyParameters": {
          "parameters": [
            {
              "name": "creation_id",
              "value": "={{ $('Instagram: Media Container erstellen').item.json.id }}"
            }
          ]
        },
        "options": {}
      },
      "id": "ig-publish",
      "name": "Instagram: Post ver\u00f6ffentlichen",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2000,
        200
      ],
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v25.0/{{ $env.FB_PAGE_ID }}/photos",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "facebookGraphApi",
        "sendBody": true,
        "bodyContentType": "json",
        "specifyBody": "fieldsBelow",
        "bodyParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $(\"Bild-URL extrahieren\").item.json.image_url }}"
            },
            {
              "name": "message",
              "value": "={{ $(\"Bild-URL extrahieren\").item.json.caption_with_hashtags }}"
            }
          ]
        },
        "options": {}
      },
      "id": "fb-publish",
      "name": "Facebook: Beitrag ver\u00f6ffentlichen",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2000,
        360
      ],
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://physiofuchs889.sharepoint.com/sites/PhysioFuchsTW/_api/web/lists(guid'd17a6a6f-e6ef-457d-a2a9-4c30ea56120f')/items({{ $('Bild-URL extrahieren').item.json.item_id }})",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "microsoftSharePointOAuth2Api",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "X-HTTP-Method",
              "value": "MERGE"
            },
            {
              "name": "IF-MATCH",
              "value": "*"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "field_6",
              "value": "Ver\u00f6ffentlicht"
            },
            {
              "name": "field_12",
              "value": "=IG:{{ $('Instagram: Post ver\u00f6ffentlichen').item.json.id }} | FB:{{ $('Facebook: Beitrag ver\u00f6ffentlichen').item.json.id }}"
            }
          ]
        },
        "options": {}
      },
      "id": "sp-update-status",
      "name": "SharePoint: Status Ver\u00f6ffentlicht",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2220,
        280
      ],
      "credentials": {
        "microsoftSharePointOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "create",
        "teamId": "={{ $env.TEAMS_TEAM_ID }}",
        "channelId": "={{ $env.TEAMS_CHANNEL_ID }}",
        "content": "=\u2705 **Post ver\u00f6ffentlicht!**\n\n\ud83d\udccc **Thema:** {{ $('Bild-URL extrahieren').item.json.thema }}\n\ud83d\udcf8 **Instagram:** {{ $('Instagram: Post ver\u00f6ffentlichen').item.json.id }}\n\ud83d\udcd8 **Facebook:** {{ $('Facebook: Beitrag ver\u00f6ffentlichen').item.json.id }}\n\ud83d\udd50 {{ $now.format('DD.MM.YYYY') }} um {{ $now.format('HH:mm') }} Uhr\n\n_Automatisch via PF Social Media Auto-Post_"
      },
      "id": "teams-success",
      "name": "Teams: Erfolgsbenachrichtigung",
      "type": "n8n-nodes-base.microsoftTeams",
      "typeVersion": 2,
      "position": [
        2440,
        280
      ],
      "credentials": {
        "microsoftTeamsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://n8n.srv1099163.hstgr.cloud/webhook/canva-token-current",
        "options": {}
      },
      "id": "00000000-0000-0000-0000-0000000c1000",
      "name": "Canva-Token: aus WF-08 holen",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        380,
        320
      ]
    }
  ],
  "connections": {
    "Trigger: Mo/Mi/Fr 9:00 Uhr": {
      "main": [
        [
          {
            "node": "SharePoint: Freigegebene Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SharePoint: Freigegebene Posts": {
      "main": [
        [
          {
            "node": "Filter: Bereit zum Posten",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Felder aufbereiten": {
      "main": [
        [
          {
            "node": "Canva-Token: aus WF-08 holen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude + Canva: Design exportieren": {
      "main": [
        [
          {
            "node": "Bild-URL extrahieren",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bild-URL extrahieren": {
      "main": [
        [
          {
            "node": "Instagram: Media Container erstellen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Instagram: Media Container erstellen": {
      "main": [
        [
          {
            "node": "Warten 15s (Instagram Processing)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Warten 15s (Instagram Processing)": {
      "main": [
        [
          {
            "node": "Instagram: Post ver\u00f6ffentlichen",
            "type": "main",
            "index": 0
          },
          {
            "node": "Facebook: Beitrag ver\u00f6ffentlichen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Instagram: Post ver\u00f6ffentlichen": {
      "main": [
        [
          {
            "node": "SharePoint: Status Ver\u00f6ffentlicht",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Facebook: Beitrag ver\u00f6ffentlichen": {
      "main": [
        [
          {
            "node": "SharePoint: Status Ver\u00f6ffentlicht",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SharePoint: Status Ver\u00f6ffentlicht": {
      "main": [
        [
          {
            "node": "Teams: Erfolgsbenachrichtigung",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter: Bereit zum Posten": {
      "main": [
        [
          {
            "node": "Felder aufbereiten",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Canva-Token: aus WF-08 holen": {
      "main": [
        [
          {
            "node": "Claude + Canva: Design exportieren",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "v5.2-canva-token-fixed-2026-05-15",
  "id": "PF-WF03-v4",
  "tags": [
    "physio-fuchs",
    "social-media",
    "canva",
    "claude-api"
  ]
}