{
  "id": "eK7cRijwJVWZ0Bjq",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "HR Compliance Monitor",
  "tags": [],
  "nodes": [
    {
      "id": "79353565-a2a4-4581-8011-c219e67e2831",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2192,
        -128
      ],
      "parameters": {
        "color": 4,
        "width": 540,
        "height": 1044,
        "content": "## HR Compliance Monitor \u2014 US Dept of Labor RSS + GPT-4o-mini + Google Sheets\n\nFor HR teams who want to automatically monitor government employment law releases and identify which updates require action \u2014 without manually reading every DOL news release. Every hour this workflow polls the US Department of Labor RSS feed. A Code node filters items for HR-relevant keywords \u2014 labor, employment, wage, safety, discrimination, overtime, FMLA, and others \u2014 while dropping settlement verdicts and back-pay awards. Each matching article is processed one at a time through SplitInBatches. GPT-4o-mini analyzes each article and returns a structured JSON object: whether it is actionable, a 2-sentence summary, priority level, a specific action checklist, owner team, and due timeline. A Code node parses and cleans the JSON. An IF node routes actionable items to Google Sheets and non-actionable items directly to a 30-second wait. The Wait node loops back to SplitInBatches to process the next article \u2014 protecting against API rate limits.\n\n## How it works\n- **1. RSS \u2014 US Dept of Labor Feed** polls the DOL RSS feed every hour\n- **2. Code \u2014 Filter HR Relevant Articles** keeps only articles matching HR keyword list \u2014 drops settlements and back-pay items\n- **3. Split \u2014 Process One by One** processes each filtered article individually in sequence\n- **4. GPT-4o-mini \u2014 Analyze Compliance Update** returns a strict JSON object: actionable flag, reason, summary, priority, checklist, owner team, and due timeline\n- **OpenAI \u2014 GPT-4o-mini Model** language model attached to the AI Agent\n- **5. Code \u2014 Parse GPT Response** strips markdown fences, parses JSON, formats checklist as bullet points, handles parse errors gracefully\n- **6. IF \u2014 Actionable?** \u2014 TRUE: saves to Sheets | FALSE: skips to Wait\n- **7. Sheets \u2014 Save to Compliance Tracker** appends 11 columns to the Compliance Tracker sheet\n- **8. Wait \u2014 30s Before Next Article** rate-limit buffer \u2014 both TRUE and FALSE paths merge here, then loops back to SplitInBatches\n\n## Set up steps\n1. In **OpenAI \u2014 GPT-4o-mini Model** \u2014 connect your OpenAI API credential\n2. In **7. Sheets \u2014 Save to Compliance Tracker** \u2014 connect your Google Sheets OAuth2 credential and replace `YOUR_GOOGLE_SHEET_ID`. Create a sheet tab named Compliance Tracker with columns: Date Added, Source, Title, Link, Summary, Action Required, Priority, Checklist, Owner Team, Due Timeline, Status\n3. In **1. RSS \u2014 US Dept of Labor Feed** \u2014 change `feedUrl` to any compliance RSS feed. OSHA: https://www.osha.gov/news/newsreleases/national/rss.xml | EEOC: https://www.eeoc.gov/rss.xml | NLRB: https://www.nlrb.gov/news-outreach/rss"
      },
      "typeVersion": 1
    },
    {
      "id": "8fdc2206-89ae-4a2f-8268-30907d2a4b64",
      "name": "Section \u2014 RSS Feed Poll and HR Keyword Filter",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1600,
        208
      ],
      "parameters": {
        "color": 5,
        "width": 468,
        "height": 340,
        "content": "## RSS Feed Poll and HR Keyword Filter\nPolls US Dept of Labor RSS every hour. Code node filters for HR-relevant articles by keyword \u2014 keeps labor, employment, wage, safety, overtime, FMLA, regulation, and compliance. Drops settlement verdicts and back-pay awards."
      },
      "typeVersion": 1
    },
    {
      "id": "14e96cb6-6141-4e72-b93c-8ff39d5015a1",
      "name": "Section \u2014 Batch Split and GPT-4o-mini Compliance Analysis",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1088,
        176
      ],
      "parameters": {
        "color": 6,
        "width": 612,
        "height": 596,
        "content": "## Batch Split and GPT-4o-mini Compliance Analysis\nSplitInBatches processes one article at a time. GPT-4o-mini returns a strict JSON object with actionable flag, reason, 2-sentence summary, priority, checklist, owner team, and due timeline."
      },
      "typeVersion": 1
    },
    {
      "id": "db7c5741-2e54-4fd8-ae57-cc3488078d3b",
      "name": "Section \u2014 JSON Parse, Actionability Check, Sheets Save, and Rate Limit Wait",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        128
      ],
      "parameters": {
        "color": 4,
        "width": 820,
        "height": 644,
        "content": "## JSON Parse, Actionability Check, Sheets Save, and Rate Limit Wait\nCode node parses GPT JSON and formats checklist. IF routes actionable items to Sheets and non-actionable to Wait. Both paths merge at Wait \u2014 30-second rate-limit buffer loops back to SplitInBatches."
      },
      "typeVersion": 1
    },
    {
      "id": "a880f083-f635-4fbc-9ff0-6d3163f47679",
      "name": "1. RSS \u2014 US Dept of Labor Feed",
      "type": "n8n-nodes-base.rssFeedReadTrigger",
      "position": [
        -1520,
        352
      ],
      "parameters": {
        "feedUrl": "https://www.dol.gov/rss/releases.xml",
        "pollTimes": {
          "item": [
            {
              "mode": "everyHour"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "11e377a9-3ae4-485a-8cd4-90e21e4c6962",
      "name": "2. Code \u2014 Filter HR Relevant Articles",
      "type": "n8n-nodes-base.code",
      "position": [
        -1280,
        352
      ],
      "parameters": {
        "jsCode": "// Filter RSS items for HR compliance relevance\nconst items = $input.all();\n\nconst includeKeywords = [\n  'labor', 'employment', 'workplace', 'wage',\n  'worker', 'safety', 'discrimination', 'harassment',\n  'minimum wage', 'overtime', 'leave', 'fmla',\n  'hiring', 'firing', 'regulation', 'rule',\n  'penalty', 'enforcement', 'compliance', 'union'\n];\n\nconst excludeKeywords = [\n  'settlement', 'verdict', 'jury awards',\n  'back pay to', 'judgment'\n];\n\nreturn items.filter(item => {\n  const text = ((item.json.title || '') + ' ' + (item.json.contentSnippet || '')).toLowerCase();\n  const hasInclude = includeKeywords.some(kw => text.includes(kw));\n  const hasExclude = excludeKeywords.some(kw => text.includes(kw));\n  return hasInclude && !hasExclude;\n}).map(item => ({\n  json: {\n    title: item.json.title || '',\n    link: item.json.link || '',\n    guid: item.json.guid || item.json.link || '',\n    pubDate: item.json.isoDate || item.json.pubDate || '',\n    description: item.json.contentSnippet || item.json.summary || ''\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "b37f9501-ad35-4e5b-9fc7-9d6b3033e867",
      "name": "3. Split \u2014 Process One by One",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -1040,
        352
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "6ef85855-c792-4c81-ba58-621d59ceeeef",
      "name": "4. GPT-4o-mini \u2014 Analyze Compliance Update",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -800,
        352
      ],
      "parameters": {
        "text": "=Analyze this employment law update:\n\nTitle: {{ $json.title }}\nPublished: {{ $json.pubDate }}\nContent: {{ $json.description }}\nLink: {{ $json.link }}\n\nReturn ONLY valid JSON. No markdown. No explanation.",
        "options": {
          "systemMessage": "You are an HR compliance analyst. Analyze employment law updates and return only valid JSON.\n\nIf NOT actionable for an HR team return:\n{\"actionable\":\"No\",\"summary\":\"one sentence\",\"priority\":\"Low\",\"checklist\":[],\"owner_team\":\"Monitor\",\"due_timeline\":\"monitor\"}\n\nIf actionable return:\n{\"actionable\":\"Yes\",\"reason\":\"why HR must act\",\"summary\":\"2 sentence summary of the change\",\"priority\":\"High or Medium or Low\",\"checklist\":[\"action 1\",\"action 2\",\"action 3\"],\"owner_team\":\"HR or Legal or Finance or IT\",\"due_timeline\":\"immediate or 7 days or 30 days or 90 days\"}\n\nRules: Only mark actionable if it requires a real HR policy or process change. Checklist must be specific to this update. Return only valid JSON."
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "617b9e4c-7d23-47fc-83e9-f736284179a7",
      "name": "OpenAI \u2014 GPT-4o-mini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -800,
        544
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "c2934f41-cdb2-42e0-9ff0-d966c6e496eb",
      "name": "5. Code \u2014 Parse GPT Response",
      "type": "n8n-nodes-base.code",
      "position": [
        -384,
        352
      ],
      "parameters": {
        "jsCode": "// Parse GPT JSON response\nconst output = $input.first().json.output || '';\nconst article = $('3. Split \u2014 Process One by One').item.json;\n\nlet parsed;\ntry {\n  const cleaned = output.replace(/```json/gi, '').replace(/```/g, '').trim();\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = {\n    actionable: 'No',\n    summary: 'Parse error',\n    priority: 'Low',\n    checklist: [],\n    owner_team: 'Monitor',\n    due_timeline: 'monitor'\n  };\n}\n\nreturn [{\n  json: {\n    title: article.title,\n    link: article.link,\n    pubDate: article.pubDate,\n    actionable: parsed.actionable || 'No',\n    reason: parsed.reason || '',\n    summary: parsed.summary || '',\n    priority: parsed.priority || 'Low',\n    checklist: Array.isArray(parsed.checklist)\n      ? parsed.checklist.map(i => '\u2022 ' + i).join('\\n')\n      : '',\n    owner_team: parsed.owner_team || 'Monitor',\n    due_timeline: parsed.due_timeline || 'monitor',\n    dateAdded: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "332a0f9b-c146-4bf4-bc53-915b3ba8a3b8",
      "name": "6. IF \u2014 Actionable?",
      "type": "n8n-nodes-base.if",
      "position": [
        -144,
        352
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-actionable",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.actionable.toLowerCase() }}",
              "rightValue": "yes"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "374c9727-4268-44fe-9469-ed54924e040f",
      "name": "7. Sheets \u2014 Save to Compliance Tracker",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        96,
        240
      ],
      "parameters": {
        "columns": {
          "value": {
            "Link": "={{ $json.link }}",
            "Title": "={{ $json.title }}",
            "Source": "=US Dept of Labor",
            "Status": "New",
            "Summary": "={{ $json.summary }}",
            "Priority": "={{ $json.priority }}",
            "Checklist": "={{ $json.checklist }}",
            "Date Added": "={{ $json.dateAdded }}",
            "Owner Team": "={{ $json.owner_team }}",
            "Due Timeline": "={{ $json.due_timeline }}",
            "Action Required": "={{ $json.reason }}"
          },
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Compliance Tracker"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "bf7786c9-0250-4a9e-8895-d3e969c87997",
      "name": "8. Wait \u2014 30s Before Next Article",
      "type": "n8n-nodes-base.wait",
      "position": [
        176,
        544
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "517faf49-b613-429a-8722-3f4381e9d15f",
  "connections": {
    "6. IF \u2014 Actionable?": {
      "main": [
        [
          {
            "node": "7. Sheets \u2014 Save to Compliance Tracker",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "8. Wait \u2014 30s Before Next Article",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI \u2014 GPT-4o-mini Model": {
      "ai_languageModel": [
        [
          {
            "node": "4. GPT-4o-mini \u2014 Analyze Compliance Update",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "5. Code \u2014 Parse GPT Response": {
      "main": [
        [
          {
            "node": "6. IF \u2014 Actionable?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Split \u2014 Process One by One": {
      "main": [
        [],
        [
          {
            "node": "4. GPT-4o-mini \u2014 Analyze Compliance Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. RSS \u2014 US Dept of Labor Feed": {
      "main": [
        [
          {
            "node": "2. Code \u2014 Filter HR Relevant Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. Wait \u2014 30s Before Next Article": {
      "main": [
        [
          {
            "node": "3. Split \u2014 Process One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Code \u2014 Filter HR Relevant Articles": {
      "main": [
        [
          {
            "node": "3. Split \u2014 Process One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7. Sheets \u2014 Save to Compliance Tracker": {
      "main": [
        [
          {
            "node": "8. Wait \u2014 30s Before Next Article",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. GPT-4o-mini \u2014 Analyze Compliance Update": {
      "main": [
        [
          {
            "node": "5. Code \u2014 Parse GPT Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}