{
  "id": "mhlC8SexrER2bYOk",
  "name": "Supplier Lifecycle Compliance Tracker",
  "tags": [],
  "nodes": [
    {
      "id": "3a33f79d-0a83-4a2a-a7aa-7d17f7ef50be",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        736
      ],
      "parameters": {
        "color": 7,
        "width": 896,
        "height": 496,
        "content": "## 1. Data Ingestion & Tracking\nFetches all active supplier records from the Notion database, calculating compliance expiry deadlines, assigning urgency brackets, and filtering out recently alerted vendors."
      },
      "typeVersion": 1
    },
    {
      "id": "412cba1f-83c2-418a-902d-bd95cd10a3a0",
      "name": "Fetch Supplier Database",
      "type": "n8n-nodes-base.notion",
      "position": [
        288,
        928
      ],
      "parameters": {
        "options": {},
        "resource": "databasePage",
        "operation": "getAll",
        "returnAll": true,
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "38731eba-a729-8029-a300-c2fc6ad2d476",
          "cachedResultUrl": "https://app.notion.com/p/38731ebaa7298029a300c2fc6ad2d476",
          "cachedResultName": "supplier_compliance_data"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3780b7be-ea4d-406d-8ef7-29bb42989607",
      "name": "Calculate Expiry Timelines",
      "type": "n8n-nodes-base.code",
      "position": [
        512,
        928
      ],
      "parameters": {
        "jsCode": "// Get all items passed from the Notion trigger node\nconst items = $input.all();\nconst output = [];\n\n// Get today's date (at midnight to keep date math precise)\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\n\nfor (let item of items) {\n  const data = item.json;\n  \n  const supplierName = data[\"property_supplier_name\"] || data[\"name\"];\n  const status = data[\"property_status\"];\n  const contactEmail = data[\"property_contact_email\"];\n  const certType = data[\"property_certification_type\"];\n  \n  // Extracting from Notion's nested object format safely\n  const expiryObj = data[\"property_certification_expiry\"];\n  const expiryStr = expiryObj && typeof expiryObj === 'object' ? expiryObj.start : expiryObj;\n  \n  const lastAlertObj = data[\"property_last_compliance_alert\"];\n  const lastAlertStr = lastAlertObj && typeof lastAlertObj === 'object' ? lastAlertObj.start : lastAlertObj;\n\n  // 1. Skip if supplier is explicitly deactivated or manually handled\n  if (status === 'Offboarded' || status === 'In Requalification') {\n    continue;\n  }\n\n  // 2. Edge Case Guard: Handle truly missing expiry dates\n  if (!expiryStr) {\n    output.push({\n      json: {\n        ...data,\n        daysRemaining: null,\n        actionRequired: \"ESCALATE_MISSING_DATA\",\n        reason: `Supplier ${supplierName} is active but has no recorded expiry date.`\n      }\n    });\n    continue;\n  }\n\n  const expiryDate = new Date(expiryStr);\n  expiryDate.setHours(0, 0, 0, 0);\n\n  // Calculate the difference in days\n  const timeDiff = expiryDate.getTime() - today.getTime();\n  const daysRemaining = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));\n\n  let actionRequired = \"IGNORE_COMPLIANT\"; \n  let reason = \"Supplier is fully compliant.\";\n\n  // Anti-Spam Guard: Check if we alerted them within the last 14 days\n  let recentlyAlerted = false;\n  if (lastAlertStr) {\n    const lastAlertDate = new Date(lastAlertStr);\n    const alertAgeDiff = today.getTime() - lastAlertDate.getTime();\n    const daysSinceAlert = Math.floor(alertAgeDiff / (1000 * 60 * 60 * 24));\n    if (daysSinceAlert <= 14) {\n      recentlyAlerted = true;\n    }\n  }\n\n  // 3. Bracket Assignment & Logic Rules\n  if (daysRemaining < 0) {\n    if (recentlyAlerted) {\n      actionRequired = \"IGNORE_ALREADY_NOTIFIED\";\n      reason = `Expired (${Math.abs(daysRemaining)} days ago), but an alert was sent recently. Anti-spam engaged.`;\n    } else {\n      actionRequired = \"CRITICAL_BREACH\";\n      reason = `CRITICAL: Certification expired ${Math.abs(daysRemaining)} days ago. Escalation required.`;\n    }\n  } else if (daysRemaining <= 14) {\n    if (recentlyAlerted) {\n      actionRequired = \"IGNORE_ALREADY_NOTIFIED\";\n      reason = `Expiring soon (${daysRemaining} days remaining), but already alerted recently.`;\n    } else {\n      actionRequired = \"ALERT_14_DAYS\";\n      reason = `URGENT: Certification expires in ${daysRemaining} days. Needs high-priority alert.`;\n    }\n  } else if (daysRemaining <= 30) {\n    if (recentlyAlerted) {\n      actionRequired = \"IGNORE_ALREADY_NOTIFIED\";\n      reason = `Expiring in 30-day window, but already alerted recently.`;\n    } else {\n      actionRequired = \"ALERT_30_DAYS\";\n      reason = `WARNING: Compliance routine renewal window open (${daysRemaining} days remaining).`;\n    }\n  }\n\n  // Filter out the non-actionable elements to prevent unnecessary node executions down the line\n  if (actionRequired !== \"IGNORE_COMPLIANT\" && actionRequired !== \"IGNORE_ALREADY_NOTIFIED\") {\n    output.push({\n      json: {\n        ...data,\n        daysRemaining: daysRemaining,\n        actionRequired: actionRequired,\n        reason: reason\n      }\n    });\n  }\n}\n\nreturn output;"
      },
      "typeVersion": 2
    },
    {
      "id": "556356f4-53e8-4c1c-9d82-710365e7bf7e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        768
      ],
      "parameters": {
        "color": 7,
        "width": 1664,
        "height": 688,
        "content": "## 2. AI Content Generation & Loop Closure\nIterates through records, sets initial variables, stamps the database to prevent duplicate alerts, generates AI communications, buffers API rates, and formats the output."
      },
      "typeVersion": 1
    },
    {
      "id": "ef888e18-4190-453f-9a44-29aa3f3e84b8",
      "name": "Loop Supplier Records",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        992,
        928
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f9d2ead9-17a6-499e-87bc-264cf6269dd1",
      "name": "Prepare AI Prompt Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1280,
        1056
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b324552a-27ed-4e27-827d-ea08e4065c3e",
              "name": "id",
              "type": "string",
              "value": "={{ $json.id.split(\"-\").join(\"\") }}"
            },
            {
              "id": "82e4a41b-553f-47d2-92a9-f6b0917ec127",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "bbe54f2a-0a23-4629-ba4a-d16e00fb127f",
              "name": "property_contact_email",
              "type": "string",
              "value": "={{ $json.property_contact_email }}"
            },
            {
              "id": "2a095290-b979-4826-80da-23e012f8379f",
              "name": "property_certification_type",
              "type": "string",
              "value": "={{ $json.property_certification_type }}"
            },
            {
              "id": "4a8867e6-4b19-440f-a110-9400e47495b9",
              "name": "reason",
              "type": "string",
              "value": "={{ $json.reason }}"
            },
            {
              "id": "6538b6ad-38aa-4117-b62e-088862cda377",
              "name": "actionRequired",
              "type": "string",
              "value": "={{ $json.actionRequired }}"
            },
            {
              "id": "886e2905-9539-460b-85d2-d9c6a90c3451",
              "name": "property_certification_expiry",
              "type": "string",
              "value": "={{ $json.property_certification_expiry }}"
            },
            {
              "id": "ac76fb9f-f444-4a22-863c-c49b9a950cac",
              "name": "daysRemaining",
              "type": "string",
              "value": "={{ $json.daysRemaining }}"
            },
            {
              "id": "0e51a6d3-b3cc-44c2-9253-a69e19266d18",
              "name": "property_status",
              "type": "string",
              "value": "={{ $json.property_status }}"
            },
            {
              "id": "3efa478a-8909-4d95-800d-8a9d4fba87de",
              "name": "property_notes_context",
              "type": "string",
              "value": "={{ $json.property_notes_context }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "b7e355d9-6ce9-4219-b085-6721c45f3fa5",
      "name": "Stamp Last Alert Date",
      "type": "n8n-nodes-base.notion",
      "position": [
        1472,
        1056
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "simple": "=",
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Last Compliance Alert|date",
              "date": "={{ $now.format('MM-DD') }}",
              "timezone": "Asia/Kolkata"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "76b1a8d4-2c24-498d-a08c-578892d52784",
      "name": "Generate Communications",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1648,
        1056
      ],
      "parameters": {
        "text": "=Please generate the required communications for the following supplier:\n\n- Supplier Name: {{ $('Prepare AI Prompt Data').item.json.name }}\n- Contact Email: {{ $('Prepare AI Prompt Data').item.json.property_contact_email }}\n- Certificate Type Missing/Expiring: {{ $('Prepare AI Prompt Data').item.json.property_certification_expiry }}\n- Days Remaining until/since expiry: {{ $('Prepare AI Prompt Data').item.json.daysRemaining }} days\n- Current System Urgency Bracket: {{ $('Prepare AI Prompt Data').item.json.actionRequired }}\n- System Reason: {{ $('Prepare AI Prompt Data').item.json.reason }}\n- id: {{ $json.id }}\n\nRemember, return your response strictly as a JSON object matching this structure:\n{\n  \"emailBody\": \"...\",\n  \"slackMessage\": \"...\",\n  \"email\":\"...\",\n  \"id\":\"...\"\n}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "You are an automated Supplier Compliance Watchdog for our Procurement Team.  Your job is to look at a supplier's compliance status and generate two specific messaging outputs based on how close they are to their certification expiration deadline.  You must ALWAYS output your response as a valid JSON object with exactly three keys: 1. \"emailBody\": A well-structured, professional, markdown-formatted email to be sent to the supplier contact. 2. \"slackMessage\": A short, urgent, block-style text notice for internal procurement staff.  Tone Guidelines: - If actionRequired is ALERT_30_DAYS: Keep the email helpful, professional, and routine. - If actionRequired is ALERT_14_DAYS: Make the email urgent, emphasizing that disruptions to procurement may occur if documentation is missed. - If actionRequired is CRITICAL_BREACH: The email should be highly urgent, noting that compliance is past due.  Do not include markdown code block formatting (like ```json) inside your text response; output raw JSON text directly, 3. \"email\": supplier's email, \"id\": supplier's id."
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "6999dfa7-934b-41c1-b301-26d96c0b6985",
      "name": "Groq Llama 3.3 Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "position": [
        1648,
        1280
      ],
      "parameters": {
        "model": "llama-3.3-70b-versatile",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "4085610c-b00c-4409-b883-5e4d991e74dd",
      "name": "JSON Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "onError": "continueRegularOutput",
      "position": [
        1792,
        1280
      ],
      "parameters": {
        "autoFix": true,
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"emailBody\": {\n      \"type\": \"string\",\n      \"description\": \"A well-structured, professional, markdown-formatted email text to be sent to the supplier contact. Tone varies based on urgency.\"\n    },\n    \"slackMessage\": {\n      \"type\": \"string\",\n      \"description\": \"A short, urgent, block-style text notice for the internal procurement staff channel.\"\n    },\n    \"email\": {\n      \"type\": \"string\",\n      \"description\": \"The supplier's contact email address.\"\n    },\n  \"id\": {\n      \"type\": \"string\",\n      \"description\": \"The supplier's id\"\n    }\n  },\n  \"required\": [\n    \"emailBody\",\n    \"slackMessage\",\n    \"email\",\n    \"id\"\n  ]\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "eeb0a48a-3143-4af3-880a-1aa4d168b4af",
      "name": "API Rate Limit Buffer",
      "type": "n8n-nodes-base.wait",
      "position": [
        1968,
        1056
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "f0ea48e9-d00f-4438-881b-68646392ea96",
      "name": "Format Loop Output",
      "type": "n8n-nodes-base.set",
      "position": [
        2176,
        1056
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "593e1fc7-4826-4054-9ca4-d4f09810a3a3",
              "name": "id",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.id }}"
            },
            {
              "id": "eb6acb92-d740-4ebc-9c7f-e73bb517bfa3",
              "name": "name",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.name }}"
            },
            {
              "id": "a7b299f6-669a-4306-a220-6853fe038135",
              "name": "property_certification_expiry",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.property_certification_expiry }}"
            },
            {
              "id": "b52dcaa0-0c7e-4b1c-a313-826cfa063546",
              "name": "property_status",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.property_status }}"
            },
            {
              "id": "097f76c6-5775-4ec8-b74a-4809f172cd05",
              "name": "property_contact_email",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.property_contact_email }}"
            },
            {
              "id": "d71dcf81-e5bf-470d-bf8a-e47cd391c7ed",
              "name": "property_certification_type",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.property_certification_type }}"
            },
            {
              "id": "0a824c23-4706-4ca0-8cd6-06ba4373c4f8",
              "name": "daysRemaining",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.daysRemaining }}"
            },
            {
              "id": "11f76bff-bf19-4a6c-bb17-4605134e9c52",
              "name": "property_notes_context",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.property_notes_context }}"
            },
            {
              "id": "5c1249fb-9a1c-4e7a-927e-5b77f2942423",
              "name": "actionRequired",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.actionRequired }}"
            },
            {
              "id": "ae860cf7-e557-4f6b-bd91-823564d98173",
              "name": "reason",
              "type": "string",
              "value": "={{ $('Prepare AI Prompt Data').item.json.reason }}"
            },
            {
              "id": "360c507c-b75b-4d4b-9267-d8756b89e6c3",
              "name": "emailBody",
              "type": "string",
              "value": "={{ $json.output.emailBody }}"
            },
            {
              "id": "d780e2cf-b444-4681-97ca-692df51a7080",
              "name": "slackMessage",
              "type": "string",
              "value": "={{ $json.output.slackMessage }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "707a85c3-0a87-416c-af4c-b479414ea484",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1200,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 1040,
        "height": 560,
        "content": "## 3. Routing & Standard Notifications\nFormats the parsed AI data and routes suppliers based on urgency, dispatching standard email reminders and internal Slack updates for upcoming expirations."
      },
      "typeVersion": 1
    },
    {
      "id": "09dc6097-8efa-47f1-9f5c-b00a4b9d5aef",
      "name": "Format Routing Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1360,
        304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f1abcff2-4c2a-4410-b8bb-12006360deed",
              "name": "emailBody",
              "type": "string",
              "value": "={{ $json.emailBody }}"
            },
            {
              "id": "aef6ceba-7563-4e2f-8160-f65557a41f86",
              "name": "slackMessage",
              "type": "string",
              "value": "={{ $json.slackMessage }}"
            },
            {
              "id": "91672978-1ea4-42f3-b7a4-65525882fffa",
              "name": "email",
              "type": "string",
              "value": "={{ $json.property_contact_email }}"
            },
            {
              "id": "694b7e22-1818-43b7-994a-abfdb863d010",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "041348bc-02e6-4f05-bb39-2b1fac531a9e",
              "name": "id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "672ae281-9d25-4eca-9eb9-1473ae0afb8c",
              "name": "property_certification_expiry",
              "type": "string",
              "value": "={{ $json.property_certification_expiry }}"
            },
            {
              "id": "77fad5c4-950d-4d0a-88bc-37ea2d84b9c1",
              "name": "property_status",
              "type": "string",
              "value": "={{ $json.property_status }}"
            },
            {
              "id": "744a6aa0-8207-4dee-9916-d21c47e92b83",
              "name": "property_certification_type",
              "type": "string",
              "value": "={{ $json.property_certification_type }}"
            },
            {
              "id": "7f36623c-450e-4bf0-a3cd-28df01d7eae6",
              "name": "daysRemaining",
              "type": "string",
              "value": "={{ $json.daysRemaining }}"
            },
            {
              "id": "7a859766-8b2e-49ec-bc25-2f652afa1b0a",
              "name": "property_notes_context",
              "type": "string",
              "value": "={{ $json.property_notes_context }}"
            },
            {
              "id": "e10a7203-20e3-4+1234567890f15078f1f",
              "name": "actionRequired",
              "type": "string",
              "value": "={{ $json.actionRequired }}"
            },
            {
              "id": "8a6d707e-a8a4-4061-8267-f0b782e07598",
              "name": "reason",
              "type": "string",
              "value": "={{ $json.reason }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8e616854-5779-4b7a-bd02-19e1ea020735",
      "name": "Urgency Routing Engine",
      "type": "n8n-nodes-base.switch",
      "position": [
        1616,
        272
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e30c173e-cd75-440d-bf3c-31cb4381e2b6",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.actionRequired }}",
                    "rightValue": "ALERT_30_DAYS"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "9700f607-1261-4564-b54e-b530a9d455d7",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.actionRequired }}",
                    "rightValue": "ALERT_14_DAYS"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "3da4a91a-3116-4ca6-846c-c1a7c8e0e041",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.actionRequired }}",
                    "rightValue": "CRITICAL_BREACH"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "a07ea22e-c930-4084-a7c0-2af710098f32",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.actionRequired }}",
                    "rightValue": "ESCALATE_MISSING_DATA"
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "f6865f52-5889-467d-bdbe-b1a9f0219e39",
      "name": "Standard Renewal Notice",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1936,
        208
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <style>\n    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background-color: #f4f6f8; color: #333333; margin: 0; padding: 0; }\n    .email-container { max-width: 600px; margin: 20px auto; background: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.05); border: 1px solid #e1e4e8; }\n    \n    /* DYNAMIC BANNER BACKGROUND COLOR */\n    .alert-banner { \n      background-color:{{ $json.actionRequired === 'CRITICAL_BREACH' ? '#b52b27' : ($json.actionRequired === 'ALERT_14_DAYS' ? '#e65100' : ($json.actionRequired === 'ALERT_30_DAYS' ? '#2f55d4' : '#6a1b9a')) }}; \n      color: #ffffff; padding: 16px 24px; font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em; \n    }\n    \n    .email-body { padding: 32px 24px; }\n    .status-card { background-color: #f8f9fa; border-left: 4px solid {{ $json.actionRequired === 'CRITICAL_BREACH' ? '#b52b27' : ($json.actionRequired === 'ALERT_14_DAYS' ? '#e65100' : ($json.actionRequired === 'ALERT_30_DAYS' ? '#2f55d4' : '#6a1b9a')) }}; padding: 16px; margin-bottom: 24px; border-radius: 0 4px 4px 0; }\n    .status-row { margin-bottom: 8px; font-size: 14px; }\n    .status-label { font-weight: 600; color: #666666; display: inline-block; width: 140px; }\n    .status-value { color: #1a1a1a; font-weight: 500; }\n    p { font-size: 15px; line-height: 1.6; color: #4a4a4a; margin-top: 0; margin-bottom: 16px; }\n    .email-footer { background-color: #f8f9fa; padding: 24px; text-align: center; font-size: 12px; color: #888888; border-top: 1px solid #e1e4e8; }\n  </style>\n</head>\n<body>\n\n  <div class=\"email-container\">\n    <!-- DYNAMIC BANNER TEXT -->\n    <div class=\"alert-banner\">\n      {{ $json.actionRequired === 'CRITICAL_BREACH' ? ' CRITICAL COMPLIANCE BREACH NOTICE' : ($json.actionRequired === 'ALERT_14_DAYS' ? ' URGENT: REQUALIFICATION COUNTDOWN' : ($json.actionRequired === 'ALERT_30_DAYS' ? ' ROUTINE RENEWAL REMINDER' : ' ACTION REQUIRED: PROFILE UPDATE')) }}\n    </div>\n\n    <div class=\"email-body\">\n      <!-- MAIN BODY TEXT (Converts OpenAI text newlines to HTML paragraphs cleanly) -->\n      <p>{{ $('Format Routing Data').item.json.emailBody.replace(/\\n/g, '<br>') }}</p>\n\n      <!-- AUTOMATED METADATA CARD -->\n      <div class=\"status-card\">\n        <div class=\"status-row\">\n          <span class=\"status-label\">Supplier Name:</span>\n          <span class=\"status-value\">{{ $('Format Routing Data').item.json.name }}</span>\n        </div>\n        <div class=\"status-row\">\n          <span class=\"status-label\">Requirement:</span>\n          <span class=\"status-value\">{{ $json.property_certification_type }}</span>\n        </div>\n        <div class=\"status-row\">\n          <span class=\"status-label\">Current Status:</span>\n          <span class=\"status-value\"><strong>{{ $json.reason }}</strong></span>\n        </div>\n      </div>\n      \n      <p>If you have any questions regarding this assessment or believe our core registry metadata is outdated, please reply directly to this thread to connect with our operations team.</p>\n    </div>\n\n    <div class=\"email-footer\">\n      This is an automated tracking notification managed by our Global Procurement Operations Framework.<br>\n      To submit documents directly, please utilize your designated supplier portal asset link.\n    </div>\n  </div>\n\n</body>\n</html>",
        "options": {},
        "subject": "=Action Required: {{ $json.property_certification_type }} Compliance for {{ $json.name }}"
      },
      "typeVersion": 2.2
    },
    {
      "id": "c7420c06-c747-4667-ab2f-09292dee36cb",
      "name": "Routine Internal Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        1936,
        400
      ],
      "parameters": {
        "text": "={{ $json.slackMessage }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0AQS47TGQ0",
          "cachedResultName": "all-dropbox-note-sync"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.4
    },
    {
      "id": "d0a72600-6fec-47e0-839f-b48aee6ef700",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2384,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 736,
        "content": "## 4. Critical Breach Escalation \nHandles severe compliance breaches by formatting escalation data, automatically suspending the vendor in Notion, and sending urgent warnings to all stakeholders."
      },
      "typeVersion": 1
    },
    {
      "id": "8aa76361-667f-40b4-b4d4-8ab338e9d56b",
      "name": "Prepare Escalation Data",
      "type": "n8n-nodes-base.set",
      "position": [
        2576,
        320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bdd5ac98-429f-4da8-b4b5-f3ad838ebd6e",
              "name": "emailBody",
              "type": "string",
              "value": "={{ $json.emailBody }}"
            },
            {
              "id": "bdc772ca-54a9-42e5-a266-f120238b26dd",
              "name": "slackMessage",
              "type": "string",
              "value": "={{ $json.slackMessage }}"
            },
            {
              "id": "f3fc6a74-b6aa-45c8-8653-baa3f0bbe33c",
              "name": "email",
              "type": "string",
              "value": "={{ $json.email }}"
            },
            {
              "id": "59b91b91-f8a5-45db-a637-b56a551e894c",
              "name": "id",
              "type": "string",
              "value": "={{ $json.id.split(\"-\").join(\"\") }}"
            },
            {
              "id": "fb6b3ec1-661b-4b11-8b7f-318d8bbad170",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "2057c5ae-d902-4dca-84f3-b9d7be3ba892",
      "name": "Final Suspension Warning",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2896,
        144
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=<!DOCTYPE html>\n<html>\n<body style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background-color: #f4f6f8; padding: 20px;\">\n\n  <div style=\"max-width: 600px; margin: 0 auto; background: #ffffff; border-radius: 8px; border: 1px solid #e1e4e8; overflow: hidden;\">\n    \n    <div style=\"background-color: #b52b27; color: #ffffff; padding: 16px 24px; font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;\">\n       ACCOUNT SUSPENSION NOTICE\n    </div>\n\n    <div style=\"padding: 32px 24px; color: #333333;\">\n      <p style=\"font-size: 16px; margin-top: 0;\">Dear <strong>{{ $json.name }}</strong> Team,</p>\n      \n      <p style=\"font-size: 15px; line-height: 1.6;\">This is an official automated notice that your active supplier status has been temporarily suspended due to a critical compliance breach.</p>\n\n      <div style=\"background-color: #fdf2f2; border-left: 4px solid #b52b27; padding: 16px; margin: 24px 0; border-radius: 0 4px 4px 0;\">\n        <p style=\"margin: 0 0 8px 0; font-size: 14px;\"><strong>Missing Requirement:</strong> {{ $json.property_certification_type }}</p>\n        <p style=\"margin: 0; font-size: 14px; color: #b52b27;\"><strong>Status:</strong> Expired {{ Math.abs($json.daysRemaining) }} days ago.</p>\n      </div>\n\n      <p style=\"font-size: 15px; line-height: 1.6;\"><strong>What this means:</strong> Until this documentation is updated and verified, we cannot process new purchase orders, issue payments, or continue standard procurement operations with your company.</p>\n      \n      <div style=\"text-align: center; margin: 32px 0;\">\n        <a href=\"[INSERT YOUR SECURE UPLOAD LINK HERE]\" style=\"background-color: #b52b27; color: #ffffff; text-decoration: none; padding: 12px 28px; font-size: 15px; font-weight: bold; border-radius: 4px; display: inline-block;\">Upload Renewed Documentation</a>\n      </div>\n\n      <p style=\"font-size: 14px; color: #666666; margin-bottom: 0;\">If you believe this is an error or have already initiated the audit process, please reply directly to this email to sync with our Risk Operations team.</p>\n    </div>\n  </div>\n\n</body>\n</html>",
        "options": {},
        "subject": "=URGENT NOTICE OF SUSPENSION: {{ $json.property_certification_type }} Expired"
      },
      "typeVersion": 2.2
    },
    {
      "id": "5900551d-d1d9-4d50-99f6-700172d78771",
      "name": "Risk Team Escalation",
      "type": "n8n-nodes-base.slack",
      "position": [
        2896,
        512
      ],
      "parameters": {
        "text": "=*VENDOR SUSPENDED: CRITICAL COMPLIANCE BREACH*\n<!here> \n*Supplier:* {{ $json.name }}\n*Missing Requirement:* {{ $json.property_certification_type }}\n*Severity:* Expired {{ Math.abs($json.daysRemaining) }} days ago.\n\n*Action Taken:* The automated watchdog has shifted their Notion status to 'In Requalification' and dispatched a final warning email requesting an immediate document upload.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0AQS47TGQ0",
          "cachedResultName": "all-dropbox-note-sync"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.4
    },
    {
      "id": "434c9262-7356-4a23-9e1f-5dc4229c9cc8",
      "name": "Suspend Vendor Status",
      "type": "n8n-nodes-base.notion",
      "position": [
        2896,
        320
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|select",
              "selectValue": "In Requalification"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b66fa0de-c4b2-4c8b-9f58-1e6efe2bfc91",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -256,
        -176
      ],
      "parameters": {
        "width": 1296,
        "height": 800,
        "content": "## Workflow Overview: Supplier Lifecycle Compliance Tracker\n\nThis workflow acts as an automated **Compliance Watchdog** for the procurement process. It monitors supplier lifecycle events by analyzing certification expiry dates stored in a Notion master database. By automatically calculating urgency brackets, predicting upcoming gaps, generating AI-tailored communications, and executing a \"kill switch\" for non-compliant vendors, it ensures your supply chain remains uninterrupted and strictly aligned with regulatory standards.\n\n## How it works\n\nThis workflow acts as an automated **Compliance Watchdog** for your risk and procurement departments. It runs entirely hands-free on a daily schedule, fetching active supplier records and mathematically calculating how close each vendor is to their certification expiration deadline.\nIf a supplier is approaching a 14-day or 30-day renewal window, the system uses an LLM to draft and send highly personalized, context-aware reminder emails while logging the alert. If a critical breach is detected (an expired certificate), the workflow acts as a fail-safe: it instantly suspends the vendor in Notion to block new purchase orders, alerts your internal risk team via Slack, and emails the supplier a final rejection notice demanding immediate document upload.\n\n## Setup Steps\n\n**Daily Schedule Trigger** \u2014 Start the workflow automatically every morning to audit the database.\n**Fetch Supplier Database** \u2014 Retrieve all active supplier profiles and certification timelines from Notion.\n**Calculate Expiry Timelines** \u2014 Execute custom code to categorize suppliers into urgency brackets and filter out recently alerted vendors to prevent email spam.\n**Prepare AI Prompt Data** \u2014 Format the expiring supplier data into a clean structure for the language model.\n**Stamp Last Alert Date** \u2014 Update the vendor's Notion profile with today's date to engage the anti-spam lock and close the loop.\n**AI Communications Generator** \u2014 Use a Groq-powered LLM to dynamically draft personalized, markdown-formatted emails and internal Slack updates.\n**Format & Route Data** \u2014 Parse the AI's JSON output and route the supplier down one of four specific action paths based on their urgency level.\n**Routine Renewal Notices** \u2014 Dispatch standard 14-day and 30-day warning emails via Gmail and notify the procurement Slack channel.\n**Suspend Vendor Status** \u2014 Automatically flip the vendor's Notion status to 'In Requalification' if a critical historical breach is detected.\n**Critical Escalation Alerts** \u2014 Send a final suspension warning to the vendor and a high-priority @here alert to the internal risk team."
      },
      "typeVersion": 1
    },
    {
      "id": "5265ad6d-7566-406d-a8d6-eb52da50d261",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        48,
        928
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "f4a49a5d-d204-455d-ac63-0faffe496a6b",
  "nodeGroups": [],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Fetch Supplier Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Loop Output": {
      "main": [
        [
          {
            "node": "Loop Supplier Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JSON Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Generate Communications",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Format Routing Data": {
      "main": [
        [
          {
            "node": "Urgency Routing Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Llama 3.3 Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Communications",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "JSON Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "API Rate Limit Buffer": {
      "main": [
        [
          {
            "node": "Format Loop Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Supplier Records": {
      "main": [
        [
          {
            "node": "Format Routing Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare AI Prompt Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stamp Last Alert Date": {
      "main": [
        [
          {
            "node": "Generate Communications",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare AI Prompt Data": {
      "main": [
        [
          {
            "node": "Stamp Last Alert Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Urgency Routing Engine": {
      "main": [
        [
          {
            "node": "Standard Renewal Notice",
            "type": "main",
            "index": 0
          },
          {
            "node": "Routine Internal Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Standard Renewal Notice",
            "type": "main",
            "index": 0
          },
          {
            "node": "Routine Internal Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Routine Internal Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prepare Escalation Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Routine Internal Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Supplier Database": {
      "main": [
        [
          {
            "node": "Calculate Expiry Timelines",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Communications": {
      "main": [
        [
          {
            "node": "API Rate Limit Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Escalation Data": {
      "main": [
        [
          {
            "node": "Suspend Vendor Status",
            "type": "main",
            "index": 0
          },
          {
            "node": "Risk Team Escalation",
            "type": "main",
            "index": 0
          },
          {
            "node": "Final Suspension Warning",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Expiry Timelines": {
      "main": [
        [
          {
            "node": "Loop Supplier Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}