{
  "id": "AVlmcAwuhhZs5AFw",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Monitor overtime against Japanese labour-law limits with Gemini, Sheets and Slack",
  "tags": [],
  "nodes": [
    {
      "id": "74992b71-6542-498d-b223-b78f9fca9548",
      "name": "Schedule Weekly Check",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        48,
        48
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 7
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "b23c5d49-5521-42b2-81b0-31d23764c9cc",
      "name": "Set Legal Limits",
      "type": "n8n-nodes-base.set",
      "position": [
        272,
        48
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "m",
              "name": "monthlyLimit",
              "type": "number",
              "value": 45
            },
            {
              "id": "w",
              "name": "warningThreshold",
              "type": "number",
              "value": 36
            },
            {
              "id": "s",
              "name": "singleMonthMax",
              "type": "number",
              "value": 100
            },
            {
              "id": "y",
              "name": "annualLimit",
              "type": "number",
              "value": 720
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "8e2cadb7-4f2d-47e1-a14b-3a5c98023ce4",
      "name": "Get Attendance Records",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        480,
        48
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Attendance"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "a046f64b-5d56-4e19-8ae7-3b0dfc7976f8",
      "name": "Aggregate Overtime by Employee",
      "type": "n8n-nodes-base.code",
      "position": [
        848,
        48
      ],
      "parameters": {
        "jsCode": "const rows = $input.all().map(function (i) { return i.json; });\nconst map = {};\nfor (const r of rows) {\n  const name = r.Employee || r.employee || r.Name || '';\n  if (!name) continue;\n  const month = String(r.Month || r.month || String(r.Date || '').slice(0, 7));\n  const key = name + '|' + month;\n  const ot = Number(r['Overtime Hours'] || r.overtimeHours || r.Overtime || 0) || 0;\n  if (!map[key]) { map[key] = { recordKey: key, employee: name, month: month, overtimeHours: 0, entries: 0 }; }\n  map[key].overtimeHours += ot;\n  map[key].entries += 1;\n}\nreturn Object.keys(map).map(function (k) { return { json: map[k] }; });"
      },
      "typeVersion": 2
    },
    {
      "id": "a647f3c4-04c4-4875-bf7e-196aaaa762d0",
      "name": "Assess Overtime Risk with Gemini",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "onError": "continueErrorOutput",
      "position": [
        1168,
        48
      ],
      "parameters": {
        "text": "=You are a Japanese labour-compliance adviser. Under the Labour Standards Act and a 36 agreement, overtime is capped at {{ $(\"Set Legal Limits\").first().json.monthlyLimit }} hours per month, must never exceed {{ $(\"Set Legal Limits\").first().json.singleMonthMax }} hours in a single month, and {{ $(\"Set Legal Limits\").first().json.annualLimit }} hours per year.\n\nSet risk_level to \"over\" when the monthly cap is already exceeded, \"approaching\" when it is at or above {{ $(\"Set Legal Limits\").first().json.warningThreshold }} hours but still under the cap, and \"ok\" otherwise. Give a short summary and concrete recommended actions for the manager.\n\nEmployee: {{ $json.employee }}\nMonth: {{ $json.month }}\nOvertime hours this month: {{ $json.overtimeHours }}",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "2f02a3f9-249e-47cd-8b86-84b9ab1dd08b",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1136,
        240
      ],
      "parameters": {
        "options": {
          "temperature": 0.1
        },
        "modelName": "models/gemini-3.1-flash-lite"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "f089da35-5794-42a9-bf98-1b0c04af53da",
      "name": "Overtime Risk Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1392,
        240
      ],
      "parameters": {
        "jsonSchemaExample": "{\"risk_level\":\"over\",\"summary\":\"48h exceeds the 45h monthly cap\",\"recommended_actions\":[\"Redistribute workload\",\"Record the special-clause reason\"]}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "119c050c-4ec5-430b-a0b3-a39431e56491",
      "name": "Parse Overtime Risk",
      "type": "n8n-nodes-base.code",
      "position": [
        1664,
        32
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const src = $json.output || $json;\nconst a = $('Aggregate Overtime by Employee').item.json;\nconst arr = function (x) { return Array.isArray(x) ? x.join('; ') : (x || ''); };\nreturn {\n  recordKey: a.recordKey,\n  employee: a.employee,\n  month: a.month,\n  overtimeHours: a.overtimeHours,\n  riskLevel: String(src.risk_level || 'ok').toLowerCase(),\n  summary: src.summary || '',\n  recommendedActions: arr(src.recommended_actions)\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "d5b7ba08-e000-4183-ba5c-6fad306c3dfd",
      "name": "Update Overtime Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2032,
        32
      ],
      "parameters": {
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Overtime Status"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "4d1ce4ca-2006-4bbf-bb4a-64f87fecc5e2",
      "name": "Route by Risk Level",
      "type": "n8n-nodes-base.switch",
      "position": [
        2240,
        0
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Overtime Risk\").item.json.riskLevel }}",
                    "rightValue": "over"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Overtime Risk\").item.json.riskLevel }}",
                    "rightValue": "approaching"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Overtime Risk\").item.json.riskLevel }}",
                    "rightValue": "ok"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Other"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "2cdb69ce-3421-4967-9d91-e413819c39ac",
      "name": "Alert HR Immediately",
      "type": "n8n-nodes-base.slack",
      "position": [
        2528,
        -16
      ],
      "parameters": {
        "text": "=*:rotating_light: Overtime cap exceeded*\n*Employee:* {{ $(\"Parse Overtime Risk\").item.json.employee }}\n*Month:* {{ $(\"Parse Overtime Risk\").item.json.month }}\n*Overtime:* {{ $(\"Parse Overtime Risk\").item.json.overtimeHours }}h\n*Summary:* {{ $(\"Parse Overtime Risk\").item.json.summary }}\n*Actions:* {{ $(\"Parse Overtime Risk\").item.json.recommendedActions }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "#hr"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "e5fc08e8-7f79-47d1-bdbc-a5b139f09017",
      "name": "Draft Manager Notice",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2752,
        -16
      ],
      "parameters": {
        "message": "={{ \"The following employee has exceeded the monthly overtime cap.\\n\\nEmployee: \" + $(\"Parse Overtime Risk\").item.json.employee + \"\\nMonth: \" + $(\"Parse Overtime Risk\").item.json.month + \"\\nOvertime hours: \" + $(\"Parse Overtime Risk\").item.json.overtimeHours + \"\\n\\n\" + $(\"Parse Overtime Risk\").item.json.summary + \"\\n\\nRecommended actions:\\n\" + $(\"Parse Overtime Risk\").item.json.recommendedActions }}",
        "options": {},
        "subject": "={{ \"Overtime cap exceeded - \" + $(\"Parse Overtime Risk\").item.json.employee }}",
        "resource": "draft"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "728b87a9-4b3e-49df-a85f-7600cdda57ee",
      "name": "Warn Manager Early",
      "type": "n8n-nodes-base.slack",
      "position": [
        2528,
        144
      ],
      "parameters": {
        "text": "=*:warning: Overtime approaching the legal cap*\n*Employee:* {{ $(\"Parse Overtime Risk\").item.json.employee }}\n*Overtime so far:* {{ $(\"Parse Overtime Risk\").item.json.overtimeHours }}h in {{ $(\"Parse Overtime Risk\").item.json.month }}\n*Actions:* {{ $(\"Parse Overtime Risk\").item.json.recommendedActions }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "#hr"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "89bc09b3-0026-44a9-8f60-9ed5d4a1c329",
      "name": "Flag Unclear Result",
      "type": "n8n-nodes-base.slack",
      "position": [
        2528,
        304
      ],
      "parameters": {
        "text": "=*:mag: Overtime risk could not be classified*\n*Employee:* {{ $(\"Parse Overtime Risk\").item.json.employee }}\nPlease review manually.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "#hr"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "734deb31-76dc-4c38-b288-eb35cdae1fc6",
      "name": "Report Assessment Failure",
      "type": "n8n-nodes-base.slack",
      "position": [
        1664,
        208
      ],
      "parameters": {
        "text": "=*:x: Overtime assessment failed*\n*Employee:* {{ $(\"Aggregate Overtime by Employee\").item.json.employee }}\nPlease review the hours manually.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "#hr"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "db7040ac-c2d9-455f-ab2b-3ed2fc12516b",
      "name": "Overview Sticky",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -464,
        -288
      ],
      "parameters": {
        "width": 440,
        "height": 824,
        "content": "## Monitor overtime against Japanese labour-law limits with Gemini, Sheets and Slack\n\n### How it works\nUnder Japan's Labour Standards Act and a 36 agreement, overtime is capped at 45 hours a month and 720 a year, and breaching it is a real legal risk. Every week this template reads raw attendance rows from Google Sheets, aggregates overtime per employee and month, and sends each total to a Basic LLM Chain with Google Gemini together with your configured limits. Gemini classifies the record as over, approaching or ok and returns concrete actions for the manager. Results are upserted into a status sheet keyed by employee and month so repeated runs never duplicate, then a Switch escalates: over the cap raises an HR alert plus a manager email draft, approaching sends an early warning, ok is logged only.\n\n### Setup\n1. Connect Google Sheets, Google Gemini (PaLM) API, Gmail and Slack.\n2. Provide an Attendance sheet with Employee, Month and Overtime Hours columns.\n3. Adjust the caps in **Set Legal Limits** and pick your HR Slack channel.\n\n### Customization tips\nSwitch to daily runs, or add the 2-6 month average check."
      },
      "typeVersion": 1
    },
    {
      "id": "09f5fecf-5fef-4057-a3c8-93f9e782557d",
      "name": "S1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 760,
        "content": "## 1. Schedule, limits & fetch\nRun weekly, set the statutory overtime caps, and read the raw attendance rows."
      },
      "typeVersion": 1
    },
    {
      "id": "46a61812-3b9d-48a3-8530-e4340be2e527",
      "name": "S2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 760,
        "content": "## 2. Aggregate per employee\nTotal overtime hours by employee and month."
      },
      "typeVersion": 1
    },
    {
      "id": "3d3069df-8f27-4718-ae94-71cad61291a6",
      "name": "S3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1072,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 832,
        "height": 760,
        "content": "## 3. AI risk assessment (Basic LLM Chain)\nGemini classifies each total as over, approaching or ok against the caps and suggests actions. Failures are reported to Slack."
      },
      "typeVersion": 1
    },
    {
      "id": "e812b4c8-168d-448b-b71c-c237c05ebb1f",
      "name": "S4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1920,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 1056,
        "height": 760,
        "content": "## 4. Persist & escalate\nUpsert by employee and month so runs never duplicate, then route: over the cap alerts HR and drafts a manager notice, approaching warns early, ok is logged only."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "0eab4327-037f-4016-a0bc-ed126269b8c1",
  "nodeGroups": [],
  "connections": {
    "Set Legal Limits": {
      "main": [
        [
          {
            "node": "Get Attendance Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Overtime Risk": {
      "main": [
        [
          {
            "node": "Update Overtime Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Risk Level": {
      "main": [
        [
          {
            "node": "Alert HR Immediately",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Warn Manager Early",
            "type": "main",
            "index": 0
          }
        ],
        [],
        [
          {
            "node": "Flag Unclear Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert HR Immediately": {
      "main": [
        [
          {
            "node": "Draft Manager Notice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Overtime Risk Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Assess Overtime Risk with Gemini",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Weekly Check": {
      "main": [
        [
          {
            "node": "Set Legal Limits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Attendance Records": {
      "main": [
        [
          {
            "node": "Aggregate Overtime by Employee",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Overtime Status": {
      "main": [
        [
          {
            "node": "Route by Risk Level",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Assess Overtime Risk with Gemini",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Overtime by Employee": {
      "main": [
        [
          {
            "node": "Assess Overtime Risk with Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assess Overtime Risk with Gemini": {
      "main": [
        [
          {
            "node": "Parse Overtime Risk",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Report Assessment Failure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}