AutomationFlowsSlack & Telegram › Wf Unified Legal Automation

Wf Unified Legal Automation

WF_UNIFIED_LEGAL_AUTOMATION. Uses googleSheets, httpRequest, telegram, telegramTrigger. Webhook trigger; 53 nodes.

Webhook trigger★★★★★ complexity53 nodesGoogle SheetsHTTP RequestTelegramTelegram Trigger
Slack & Telegram Trigger: Webhook Nodes: 53 Complexity: ★★★★★ Added:

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "WF_UNIFIED_LEGAL_AUTOMATION",
  "nodes": [
    {
      "parameters": {
        "path": "case/create",
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: Webhook Case Create",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        220,
        300
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u0434\u0435\u043b\u0430!A:G"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: GS Read Cases",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        460,
        300
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const raw = $items('Webhook Case Create')[0].json;\nconst body = (raw && typeof raw.body === 'object' && raw.body !== null) ? raw.body : raw;\nconst rows = items.map(i => i.json);\nconst code = String(body.case_code || '').trim();\nconst exists = rows.some(r => String(r['\u043a\u043e\u0434_\u0434\u0435\u043b\u0430'] || '').trim() === code);\nreturn [{ ...body, case_code: code, exists }];"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: Check Case Code",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.exists}}",
              "value2": true
            }
          ]
        }
      },
      "name": "CASE_CREATE_AND_FOLDERS :: IF Exists",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        920,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseCode": 409,
        "responseBody": "={\"error\":\"case_code already exists\"}"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: Respond 409",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1140,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "const code = $json.case_code; return [{...$json, incoming:`/Cases/${code}/01_Incoming`, outgoing:`/Cases/${code}/02_Outgoing`, evidence:`/Cases/${code}/03_Evidence`, created_at:new Date().toISOString()}];"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: Build Paths",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1140,
        380
      ]
    },
    {
      "parameters": {
        "url": "=http://158.160.191.139/remote.php/dav/files/Vardkes{{$json.incoming}}",
        "method": "MKCOL"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Incoming",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1360,
        320
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "=http://158.160.191.139/remote.php/dav/files/Vardkes{{$json.outgoing}}",
        "method": "MKCOL"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Outgoing",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1560,
        320
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "=http://158.160.191.139/remote.php/dav/files/Vardkes{{$json.evidence}}",
        "method": "MKCOL"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Evidence",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1760,
        320
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u0434\u0435\u043b\u0430!A:G",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "\u043a\u043e\u0434_\u0434\u0435\u043b\u0430": "={{$json.case_code}}",
            "\u043a\u043b\u0438\u0435\u043d\u0442_id": "={{$json.client_ref || \"\"}}",
            "\u044e\u0440\u0438\u0441\u0442_id": "={{$json.lawyer_ref || \"\"}}",
            "\u0442\u0438\u043f_\u0434\u0435\u043b\u0430": "={{$json.case_type || \"\"}}",
            "\u044e\u0440\u0438\u0441\u0434\u0438\u043a\u0446\u0438\u044f": "={{$json.jurisdiction || \"\"}}",
            "\u0441\u0442\u0430\u0442\u0443\u0441": "={{$json.status || \"new\"}}",
            "\u0441\u043e\u0437\u0434\u0430\u043d\u043e_\u0432": "={{$json.created_at}}"
          }
        }
      },
      "name": "CASE_CREATE_AND_FOLDERS :: GS Append Case",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1960,
        260
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u043f\u0430\u043f\u043a\u0438_\u0434\u0435\u043b!A:E",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "\u043a\u043e\u0434_\u0434\u0435\u043b\u0430": "={{$json.case_code}}",
            "\u043f\u0443\u0442\u044c_\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435": "={{$json.incoming}}",
            "\u043f\u0443\u0442\u044c_\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435": "={{$json.outgoing}}",
            "\u043f\u0443\u0442\u044c_\u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430": "={{$json.evidence}}",
            "\u0441\u043e\u0437\u0434\u0430\u043d\u043e_\u0432": "={{$json.created_at}}"
          }
        }
      },
      "name": "CASE_CREATE_AND_FOLDERS :: GS Append Folders",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        2160,
        260
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseCode": 201,
        "responseBody": "={\"status\":\"created\",\"case_code\":$json.case_code}"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: Respond 201",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        2360,
        260
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$env.YC_METADATA_MIRROR === '1' && !!$env.YC_METADATA_API_URL}}",
              "value2": true
            }
          ]
        }
      },
      "name": "CASE_CREATE_AND_FOLDERS :: IF YC Mirror Enabled",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2380,
        400
      ]
    },
    {
      "parameters": {
        "url": "={{$env.YC_METADATA_API_URL + '/cases/upsert'}}",
        "method": "POST",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { case_code: $json.case_code, client_ref: $json.client_ref, lawyer_ref: $json.lawyer_ref, case_type: $json.case_type, jurisdiction: $json.jurisdiction, status: $json.status || 'new', incoming_path: $json.incoming, outgoing_path: $json.outgoing, evidence_path: $json.evidence, created_at: $json.created_at } }}"
      },
      "name": "CASE_CREATE_AND_FOLDERS :: YC Mirror Case Upsert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2600,
        360
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "path": "case/event/create",
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "name": "CASE_EVENT_CREATE :: Webhook Event",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        220,
        1090
      ]
    },
    {
      "parameters": {
        "jsCode": "const raw = $json || {};\nconst b = (raw && typeof raw.body === 'object' && raw.body !== null) ? raw.body : raw;\nconst event_id = String(Date.now());\nconst event_type = b.event_type || 'court_hearing';\nconst timezone = b.timezone || 'Europe/Moscow';\nconst event_date = b.event_date || null;\nconst start_time = b.start_time || null;\nconst end_time = b.end_time || null;\nconst start_at = b.start_at || (event_date && start_time ? `${event_date}T${start_time}:00+03:00` : null);\nconst end_at = b.end_at || (event_date && end_time ? `${event_date}T${end_time}:00+03:00` : null);\nif (!start_at || !end_at) {\n  throw new Error('\u0414\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0443\u0436\u043d\u044b start_at \u0438 end_at (\u0438\u043b\u0438 event_date + start_time + end_time).');\n}\nreturn [{\n  ...b,\n  event_type,\n  event_id,\n  timezone,\n  event_date,\n  start_time,\n  end_time,\n  start_at,\n  end_at,\n  reminder_24h: b.reminder_24h !== false,\n  reminder_2h: b.reminder_2h !== false,\n  reminder_30m: b.reminder_30m === true,\n  custom_reminder_minutes: Number(b.custom_reminder_minutes || 0) || 0,\n  created_at: new Date().toISOString()\n}];"
      },
      "name": "CASE_EVENT_CREATE :: Prepare",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        1090
      ]
    },
    {
      "parameters": {
        "url": "=https://caldav.yandex.ru/calendars/astrarav%40yandex.ru/events-36560758/{{$json.event_id}}.ics",
        "method": "PUT",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "text/calendar; charset=utf-8"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "string",
        "body": "=BEGIN:VCALENDAR\\nVERSION:2.0\\nPRODID:-//n8n//Legal Workflow//RU\\nBEGIN:VEVENT\\nUID:{{$json.event_id}}\\nDTSTAMP:{{$now.toFormat(\"yyyyMMdd'T'HHmmss'Z'\")}}\\nSUMMARY:[{{$json.case_code}}] {{$json.event_type}}\\nDTSTART:{{DateTime.fromISO($json.start_at).toUTC().toFormat(\"yyyyMMdd'T'HHmmss'Z'\")}}\\nDTEND:{{DateTime.fromISO($json.end_at).toUTC().toFormat(\"yyyyMMdd'T'HHmmss'Z'\")}}\\nEND:VEVENT\\nEND:VCALENDAR"
      },
      "name": "CASE_EVENT_CREATE :: Calendar Create",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        700,
        1090
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u0441\u043e\u0431\u044b\u0442\u0438\u044f_\u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044f!A:G",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id_\u0441\u043e\u0431\u044b\u0442\u0438\u044f": "={{$json.event_id}}",
            "\u043a\u043e\u0434_\u0434\u0435\u043b\u0430": "={{$json.case_code}}",
            "\u0442\u0438\u043f_\u0441\u043e\u0431\u044b\u0442\u0438\u044f": "={{$json.event_type}}",
            "\u043d\u0430\u0447\u0430\u043b\u043e": "={{$json.start_at}}",
            "\u043a\u043e\u043d\u0435\u0446": "={{$json.end_at}}",
            "\u0432\u043d\u0435\u0448\u043d\u0438\u0439_id_\u0441\u043e\u0431\u044b\u0442\u0438\u044f": "={{$json.id}}",
            "\u0441\u043e\u0437\u0434\u0430\u043d\u043e_\u0432": "={{$json.created_at}}"
          }
        }
      },
      "name": "CASE_EVENT_CREATE :: GS Append Event",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        940,
        1090
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f!A:H",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f": "={{$json.event_id + \"-24h\"}}",
            "id_\u0441\u043e\u0431\u044b\u0442\u0438\u044f": "={{$json.event_id}}",
            "\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f": "lawyer",
            "telegram_chat_id": "={{$json.lawyer_chat_id}}",
            "\u0442\u0435\u043a\u0441\u0442_\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f": "={{\"\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435: \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u043e \u0434\u0435\u043b\u0443 \" + $json.case_code + \" \u0447\u0435\u0440\u0435\u0437 24 \u0447\u0430\u0441\u0430.\"}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c_\u0432": "={{DateTime.fromISO($json.start_at).minus({hours:24}).toISO()}}",
            "\u0441\u0442\u0430\u0442\u0443\u0441": "={{$json.reminder_24h === false ? 'cancelled' : 'pending'}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e_\u0432": ""
          }
        }
      },
      "name": "CASE_EVENT_CREATE :: GS Append Reminder 24h",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1180,
        1050
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f!A:H",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f": "={{$json.event_id + \"-2h\"}}",
            "id_\u0441\u043e\u0431\u044b\u0442\u0438\u044f": "={{$json.event_id}}",
            "\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f": "lawyer",
            "telegram_chat_id": "={{$json.lawyer_chat_id}}",
            "\u0442\u0435\u043a\u0441\u0442_\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f": "={{\"\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435: \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u043e \u0434\u0435\u043b\u0443 \" + $json.case_code + \" \u0447\u0435\u0440\u0435\u0437 2 \u0447\u0430\u0441\u0430.\"}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c_\u0432": "={{DateTime.fromISO($json.start_at).minus({hours:2}).toISO()}}",
            "\u0441\u0442\u0430\u0442\u0443\u0441": "={{$json.reminder_2h === false ? 'cancelled' : 'pending'}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e_\u0432": ""
          }
        }
      },
      "name": "CASE_EVENT_CREATE :: GS Append Reminder 2h",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1400,
        1050
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseCode": 201,
        "responseBody": "={\"status\":\"created\",\"event_id\":$json.event_id}"
      },
      "name": "CASE_EVENT_CREATE :: Respond 201",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1620,
        1090
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{Boolean(($json.client_chat_id && $json.payment_due_at) || $json.reminder_30m === true || Number($json.custom_reminder_minutes || 0) > 0)}}",
              "value2": true
            }
          ]
        }
      },
      "name": "CASE_EVENT_CREATE :: IF Client Payment Reminder",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1620,
        1170
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f!A:H",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f": "={{$json.payment_due_at ? ($json.event_id + '-payment') : (Number($json.custom_reminder_minutes || 0) > 0 ? ($json.event_id + '-custom') : ($json.event_id + '-30m'))}}",
            "id_\u0441\u043e\u0431\u044b\u0442\u0438\u044f": "={{$json.event_id}}",
            "\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f": "={{$json.payment_due_at ? 'client' : 'lawyer'}}",
            "telegram_chat_id": "={{$json.payment_due_at ? $json.client_chat_id : $json.lawyer_chat_id}}",
            "\u0442\u0435\u043a\u0441\u0442_\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f": "={{$json.payment_due_at ? ('\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u043e\u0431 \u043e\u043f\u043b\u0430\u0442\u0435 \u043f\u043e \u0434\u0435\u043b\u0443 ' + $json.case_code + ($json.payment_amount ? ('. \u0421\u0443\u043c\u043c\u0430: ' + $json.payment_amount) : '')) : ('\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435: \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u043e \u0434\u0435\u043b\u0443 ' + $json.case_code + (Number($json.custom_reminder_minutes || 0) > 0 ? (' \u0447\u0435\u0440\u0435\u0437 ' + Number($json.custom_reminder_minutes || 0) + ' \u043c\u0438\u043d\u0443\u0442.') : ' \u0447\u0435\u0440\u0435\u0437 30 \u043c\u0438\u043d\u0443\u0442.'))}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c_\u0432": "={{$json.payment_due_at ? $json.payment_due_at : DateTime.fromISO($json.start_at).minus({minutes: Number($json.custom_reminder_minutes || 30)}).toISO()}}",
            "\u0441\u0442\u0430\u0442\u0443\u0441": "={{$json.payment_due_at ? 'pending' : (($json.reminder_30m === true || Number($json.custom_reminder_minutes || 0) > 0) ? 'pending' : 'cancelled')}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e_\u0432": ""
          }
        }
      },
      "name": "CASE_EVENT_CREATE :: GS Append Client Payment Reminder",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1840,
        1170
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$env.YC_METADATA_MIRROR === '1' && !!$env.YC_METADATA_API_URL}}",
              "value2": true
            }
          ]
        }
      },
      "name": "CASE_EVENT_CREATE :: IF YC Mirror Enabled",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2060,
        1090
      ]
    },
    {
      "parameters": {
        "url": "={{$env.YC_METADATA_API_URL + '/events/upsert'}}",
        "method": "POST",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { event_id: $json.event_id, case_code: $json.case_code, event_type: $json.event_type, start_at: $json.start_at, end_at: $json.end_at, timezone: $json.timezone, lawyer_chat_id: $json.lawyer_chat_id, client_chat_id: $json.client_chat_id || null, payment_due_at: $json.payment_due_at || null, payment_amount: $json.payment_amount || null, created_at: $json.created_at } }}"
      },
      "name": "CASE_EVENT_CREATE :: YC Mirror Event Upsert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2280,
        1070
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 15
            }
          ]
        }
      },
      "name": "REMINDER_DISPATCH_CRON :: Cron",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        220,
        1920
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f!A:H"
      },
      "name": "REMINDER_DISPATCH_CRON :: GS Read Reminders",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        460,
        1920
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "read",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u0436\u0443\u0440\u043d\u0430\u043b_\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439!A:D"
      },
      "name": "REMINDER_DISPATCH_CRON :: GS Read Sent Log",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        700,
        1920
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const reminders = $items('GS Read Reminders').map(i => i.json);\nconst sentIds = new Set(items.map(i => i.json['id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f']).filter(Boolean));\nconst now = new Date();\nreturn reminders.filter(r => r['\u0441\u0442\u0430\u0442\u0443\u0441'] === 'pending' && new Date(r['\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c_\u0432']) <= now && !sentIds.has(r['id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f'])).map(r => ({ json: r }));"
      },
      "name": "REMINDER_DISPATCH_CRON :: Filter Due",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        940,
        1920
      ]
    },
    {
      "parameters": {
        "batchSize": 1
      },
      "name": "REMINDER_DISPATCH_CRON :: Split",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1160,
        1920
      ]
    },
    {
      "parameters": {
        "chatId": "={{$json['telegram_chat_id']}}",
        "text": "={{$json['\u0442\u0435\u043a\u0441\u0442_\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f'] || ($json['\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f'] === 'client' ? '\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u043f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u0434\u0435\u043b\u0443.' : '\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u043f\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044e.')}}"
      },
      "name": "REMINDER_DISPATCH_CRON :: TG Send",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        1380,
        1920
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u0436\u0443\u0440\u043d\u0430\u043b_\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439!A:D",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f": "={{$json[\"id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f\"]}}",
            "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e_\u0432": "={{$now}}",
            "\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f": "={{$json[\"\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f\"]}}",
            "\u0441\u0442\u0430\u0442\u0443\u0441": "sent"
          }
        }
      },
      "name": "REMINDER_DISPATCH_CRON :: GS Sent Log",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1600,
        1920
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$env.YC_METADATA_MIRROR === '1' && !!$env.YC_METADATA_API_URL}}",
              "value2": true
            }
          ]
        }
      },
      "name": "REMINDER_DISPATCH_CRON :: IF YC Mirror Enabled",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1820,
        1920
      ]
    },
    {
      "parameters": {
        "url": "={{$env.YC_METADATA_API_URL + '/reminders/sent'}}",
        "method": "POST",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { reminder_id: $json['id_\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f'], recipient_role: $json['\u0440\u043e\u043b\u044c_\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f'], sent_at: String($now), status: 'sent' } }}"
      },
      "name": "REMINDER_DISPATCH_CRON :: YC Mirror Reminder Sent",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2040,
        1900
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "updates": [
          "message",
          "callback_query"
        ]
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1,
      "position": [
        220,
        2870
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const m = $json.message || {};\nconst metaText = [m.caption, m.text].filter(Boolean).join(' ');\nconst caseMatch = metaText.match(/[\u0410A]\\d{2}-\\d+\\/\\d{4}|C-\\d{4}-\\d{3}|\\b\\d{4,}\\b/i);\nconst case_code = caseMatch ? caseMatch[0].toUpperCase() : null;\nconst photo = m.photo?.length ? m.photo[m.photo.length - 1] : null;\nconst document = m.document || null;\nconst file_id = document?.file_id || photo?.file_id || null;\nconst extRaw = (document?.file_name || '').split('.').pop()?.toLowerCase();\nconst ext = photo ? 'jpg' : (extRaw || null);\nconst mime = document?.mime_type || (photo ? 'image/jpeg' : null);\nconst allowed = new Set(['jpg','jpeg','png','pdf','doc','docx','txt']);\nif (!file_id) {\n  return [{ invalid: true, notFound: true, error_text: '\u041d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0444\u0430\u0439\u043b. \u041e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0444\u043e\u0442\u043e \u0438\u043b\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 (PDF/DOCX/TXT).', chat_id: m.chat?.id }];\n}\nif (!case_code) {\n  return [{ invalid: true, notFound: true, error_text: '\u041d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u043d\u043e\u043c\u0435\u0440 \u0434\u0435\u043b\u0430. \u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u0435\u0433\u043e \u0432 \u043f\u043e\u0434\u043f\u0438\u0441\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: A40-12345/2026.', chat_id: m.chat?.id }];\n}\nif (ext && !allowed.has(ext)) {\n  return [{ invalid: true, notFound: true, error_text: `\u041d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0442\u0438\u043f \u0444\u0430\u0439\u043b\u0430: .${ext}. \u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e: jpg, jpeg, png, pdf, doc, docx, txt.`, chat_id: m.chat?.id }];\n}\nreturn [{\n  invalid: false,\n  case_code,\n  from_id: m.from?.id || null,\n  chat_id: m.chat?.id || null,\n  file_id,\n  detected_ext: ext,\n  mime_hint: mime\n}];"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: Parse",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        2870
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u043f\u0430\u043f\u043a\u0438_\u0434\u0435\u043b!A:E"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: GS Read Folders",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        700,
        2870
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const input = $items('Parse')[0].json;\nif (input.invalid) return [input];\nconst row = items.map(i => i.json).find(r => String(r['\u043a\u043e\u0434_\u0434\u0435\u043b\u0430']) === String(input.case_code));\nif (!row) {\n  return [{ ...input, notFound: true, error_text: `\u0414\u0435\u043b\u043e ${input.case_code} \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043d\u043e\u043c\u0435\u0440.` }];\n}\nreturn [{ ...input, folder_path: row['\u043f\u0443\u0442\u044c_\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435'], notFound: false }];"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: Match Case",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        940,
        2870
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.notFound}}",
              "value2": true
            }
          ]
        }
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: IF Case Missing",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1160,
        2870
      ]
    },
    {
      "parameters": {
        "chatId": "={{$json.chat_id}}",
        "text": "={{$json.error_text || '\u041a\u043e\u0434 \u0434\u0435\u043b\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u044c: C-2025-001'}}"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: TG Case Not Found",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        1380,
        2750
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "=https://api.telegram.org/bot{{$credentials.telegramApi.accessToken}}/getFile?file_id={{$json.file_id}}",
        "method": "GET"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: TG getFile",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1380,
        2950
      ]
    },
    {
      "parameters": {
        "url": "=https://api.telegram.org/file/bot{{$credentials.telegramApi.accessToken}}/{{$json.result.file_path}}",
        "method": "GET",
        "responseFormat": "file",
        "binaryPropertyName": "data"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: TG Download",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1600,
        2950
      ]
    },
    {
      "parameters": {
        "jsCode": "const ext = ($json.detected_ext || $binary.data.fileExtension || 'bin').toLowerCase();\nconst ts = new Date().toISOString().replace(/[-:]/g,'').slice(0,15);\nconst rnd = Math.random().toString(36).slice(2,8);\nreturn [{...$json, stored_filename:`DOC_${$json.case_code}_${ts}_${rnd}.${ext}`}];"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: Safe Filename",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1820,
        2950
      ]
    },
    {
      "parameters": {
        "url": "=http://158.160.191.139/remote.php/dav/files/Vardkes{{$json.folder_path}}/{{$json.stored_filename}}",
        "method": "PUT",
        "sendBinaryData": true,
        "binaryPropertyName": "data"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: DAV Upload",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2040,
        2950
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "sheetId": "={{$env.GSHEET_ID}}",
        "range": "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b!A:H",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "id_\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430": "={{$now.toMillis()}}",
            "\u043a\u043e\u0434_\u0434\u0435\u043b\u0430": "={{$json.case_code}}",
            "telegram_id_\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f": "={{$json.from_id}}",
            "\u0438\u043c\u044f_\u0444\u0430\u0439\u043b\u0430_\u0432_\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435": "={{$json.stored_filename}}",
            "\u043f\u0443\u0442\u044c_\u0432_\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435": "={{$json.folder_path + \"/\" + $json.stored_filename}}",
            "mime_\u0442\u0438\u043f": "={{$binary.data.mimeType}}",
            "\u0440\u0430\u0437\u043c\u0435\u0440_\u0431\u0430\u0439\u0442": "={{$binary.data.fileSize}}",
            "\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043e_\u0432": "={{$now}}"
          }
        }
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: GS Append Document",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        2260,
        2950
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{$json.chat_id}}",
        "text": "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u0434\u0435\u043b\u0443."
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: TG Ack",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        2480,
        2950
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$env.YC_METADATA_MIRROR === '1' && !!$env.YC_METADATA_API_URL}}",
              "value2": true
            }
          ]
        }
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: IF YC Mirror Enabled",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2480,
        2950
      ]
    },
    {
      "parameters": {
        "url": "={{$env.YC_METADATA_API_URL + '/documents/upsert'}}",
        "method": "POST",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { doc_id: String($now.toMillis()), case_code: $json.case_code, uploaded_by_telegram_id: String($json.from_id || ''), stored_filename: $json.stored_filename, storage_path: $json.folder_path + '/' + $json.stored_filename, mime_type: $binary.data.mimeType, size_bytes: $binary.data.fileSize, uploaded_at: String($now) } }}"
      },
      "name": "TELEGRAM_DOCUMENT_INGEST :: YC Mirror Document Upsert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2700,
        2910
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "path": "ai/legal/consult",
        "httpMethod": "POST",
        "responseMode": "responseNode",
        "options": {
          "binaryData": true
        }
      },
      "name": "AI_LEGAL :: Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        260
      ]
    },
    {
      "parameters": {
        "jsCode": "const raw = $json || {};\nconst b = (raw && typeof raw.body === 'object' && raw.body !== null) ? raw.body : raw;\nconst binary = $binary || {};\n\nlet extractedFromFile = '';\nif (binary.file?.data) {\n  const mime = binary.file.mimeType || '';\n  const fileName = binary.file.fileName || 'uploaded_file';\n  if (mime.startsWith('text/')) {\n    extractedFromFile = Buffer.from(binary.file.data, 'base64').toString('utf8');\n  } else {\n    extractedFromFile = `[\u0424\u0430\u0439\u043b '${fileName}' (${mime || 'unknown mime'}) \u043f\u043e\u043b\u0443\u0447\u0435\u043d, \u043d\u043e \u0430\u0432\u0442\u043e\u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e. \u041f\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 text/document_text \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 OCR/\u043f\u0430\u0440\u0441\u0435\u0440 \u0432 workflow.]`;\n  }\n}\n\nconst documentText = String(b.document_text || b.text || b.case_text || extractedFromFile || '').trim();\nif (!documentText) {\n  throw new Error('\u041f\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u0442\u0435\u043a\u0441\u0442 \u0434\u0435\u043b\u0430 \u0432 body.document_text / body.text / body.case_text \u0438\u043b\u0438 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u0438\u0442\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0432 binary.file');\n}\n\nreturn [{\n  case_code: b.case_code || null,\n  jurisdiction: b.jurisdiction || '\u0420\u043e\u0441\u0441\u0438\u044f',\n  document_text: documentText\n}];"
      },
      "name": "AI_LEGAL :: Prepare Input",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        260
      ]
    },
    {
      "parameters": {
        "url": "={{$env.LEGAL_AI_API_URL || 'https://api.openai.com/v1/chat/completions'}}",
        "method": "POST",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { model: $env.LEGAL_AI_MODEL || 'gpt-4o-mini', temperature: 0.2, response_format: { type: 'json_object' }, messages: [ { role: 'system', content: '\u0422\u044b \u2014 \u044e\u0440\u0438\u0434\u0438\u0447\u0435\u0441\u043a\u0438\u0439 AI-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u044e\u0440\u0438\u0441\u0442\u043e\u0432 \u0438 \u0430\u0434\u0432\u043e\u043a\u0430\u0442\u043e\u0432. \u0420\u043e\u043b\u044c: \u0441\u0442\u0430\u0440\u0448\u0438\u0439 \u043a\u043e\u043d\u0441\u0443\u043b\u044c\u0442\u0430\u043d\u0442 \u0441 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u043e\u0439 20+ \u043b\u0435\u0442 \u043f\u043e \u043f\u0440\u0430\u0432\u0443 \u0420\u0424 (\u0444\u0435\u0434\u0435\u0440\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u0430\u043a\u043e\u043d\u043e\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e, \u043f\u043e\u0434\u0437\u0430\u043a\u043e\u043d\u043d\u044b\u0435 \u0430\u043a\u0442\u044b, \u0441\u0443\u0434\u0435\u0431\u043d\u0430\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430). \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0448\u044c \u0441\u0442\u0440\u043e\u0433\u043e \u0432 \u043f\u0440\u0430\u0432\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 \u0420\u0424, \u043f\u0438\u0448\u0435\u0448\u044c \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u041d\u0435 \u0432\u044b\u0434\u0443\u043c\u044b\u0432\u0430\u0439 \u043d\u043e\u0440\u043c\u044b \u043f\u0440\u0430\u0432\u0430: \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d \u2014 \u0443\u043a\u0430\u0436\u0438, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438. \u041e\u0442\u0432\u0435\u0442 \u0412\u0421\u0415\u0413\u0414\u0410 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c JSON \u0444\u043e\u0440\u043c\u0430\u0442\u0430: {\"summary\":\"...\",\"key_facts\":[\"...\"],\"legal_qualification\":[\"...\"],\"risks\":[\"...\"],\"recommended_next_steps\":[\"...\"],\"evidence_checklist\":[\"...\"],\"questions_for_client\":[\"...\"],\"disclaimer\":\"...\" }' }, { role: 'user', content: `\u042e\u0440\u0438\u0441\u0434\u0438\u043a\u0446\u0438\u044f: ${$json.jurisdiction}\\n\u041a\u043e\u0434 \u0434\u0435\u043b\u0430: ${$json.case_code || '\u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d'}\\n\\n\u0422\u0435\u043a\u0441\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u0434\u0435\u043b\u0430:\\n${$json.document_text}` } ] } }}"
      },
      "name": "AI_LEGAL :: LLM Analyze",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        760,
        260
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const raw = $json.choices?.[0]?.message?.content || '{}';\nlet parsed;\ntry {\n  parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n} catch (e) {\n  parsed = {\n    summary: String(raw),\n    key_facts: [],\n    legal_qualification: [],\n    risks: ['LLM \u0432\u0435\u0440\u043d\u0443\u043b \u043d\u0435-JSON \u0444\u043e\u0440\u043c\u0430\u0442, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0440\u0443\u0447\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430.'],\n    recommended_next_steps: [],\n    evidence_checklist: [],\n    questions_for_client: [],\n    disclaimer: '\u041e\u0442\u0432\u0435\u0442 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u044e\u0440\u0438\u0434\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c.'\n  };\n}\n\nreturn [{\n  status: 'ok',\n  generated_at: new Date().toISOString(),\n  ...parsed\n}];"
      },
      "name": "AI_LEGAL :: Normalize Output",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1020,
        260
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{$json}}"
      },
      "name": "AI_LEGAL :: Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1260,
        260
      ]
    }
  ],
  "connections": {
    "CASE_CREATE_AND_FOLDERS :: Webhook Case Create": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: GS Read Cases",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: GS Read Cases": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: Check Case Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: Check Case Code": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: IF Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: IF Exists": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: Respond 409",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: Build Paths",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: Build Paths": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Incoming",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Incoming": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Outgoing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Outgoing": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Evidence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: DAV MKCOL Evidence": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: GS Append Case",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: GS Append Case": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: GS Append Folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: GS Append Folders": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: IF YC Mirror Enabled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: IF YC Mirror Enabled": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: YC Mirror Case Upsert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: Respond 201",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_CREATE_AND_FOLDERS :: YC Mirror Case Upsert": {
      "main": [
        [
          {
            "node": "CASE_CREATE_AND_FOLDERS :: Respond 201",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: Webhook Event": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: Prepare",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: Prepare": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: Calendar Create",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: Calendar Create": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: GS Append Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: GS Append Event": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: GS Append Reminder 24h",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: GS Append Reminder 24h": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: GS Append Reminder 2h",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: GS Append Reminder 2h": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: IF Client Payment Reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: IF Client Payment Reminder": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: GS Append Client Payment Reminder",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "CASE_EVENT_CREATE :: IF YC Mirror Enabled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: GS Append Client Payment Reminder": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: IF YC Mirror Enabled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: IF YC Mirror Enabled": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: YC Mirror Event Upsert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "CASE_EVENT_CREATE :: Respond 201",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CASE_EVENT_CREATE :: YC Mirror Event Upsert": {
      "main": [
        [
          {
            "node": "CASE_EVENT_CREATE :: Respond 201",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: Cron": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: GS Read Reminders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: GS Read Reminders": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: GS Read Sent Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: GS Read Sent Log": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: Filter Due",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: Filter Due": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: Split",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: Split": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: TG Send",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: TG Send": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: GS Sent Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: GS Sent Log": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: IF YC Mirror Enabled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: IF YC Mirror Enabled": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: YC Mirror Reminder Sent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: Split",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REMINDER_DISPATCH_CRON :: YC Mirror Reminder Sent": {
      "main": [
        [
          {
            "node": "REMINDER_DISPATCH_CRON :: Split",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: Telegram Trigger": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: Parse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: Parse": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: GS Read Folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: GS Read Folders": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: Match Case",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: Match Case": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: IF Case Missing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: IF Case Missing": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: TG Case Not Found",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: TG getFile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: TG getFile": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: TG Download",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: TG Download": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: Safe Filename",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: Safe Filename": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: DAV Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: DAV Upload": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: GS Append Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: GS Append Document": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: IF YC Mirror Enabled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: IF YC Mirror Enabled": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: YC Mirror Document Upsert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: TG Ack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELEGRAM_DOCUMENT_INGEST :: YC Mirror Document Upsert": {
      "main": [
        [
          {
            "node": "TELEGRAM_DOCUMENT_INGEST :: TG Ack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI_LEGAL :: Webhook": {
      "main": [
        [
          {
            "node": "AI_LEGAL :: Prepare Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI_LEGAL :: Prepare Input": {
      "main": [
        [
          {
            "node": "AI_LEGAL :: LLM Analyze",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI_LEGAL :: LLM Analyze": {
      "main": [
        [
          {
            "node": "AI_LEGAL :: Normalize Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI_LEGAL :: Normalize Output": {
      "main": [
        [
          {
            "node": "AI_LEGAL :: Respond",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "2"
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

WF_UNIFIED_LEGAL_AUTOMATION. Uses googleSheets, httpRequest, telegram, telegramTrigger. Webhook trigger; 53 nodes.

Source: https://github.com/alexdmitrievi/Vardkesonva/blob/main/workflows/WF_UNIFIED_LEGAL_AUTOMATION.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

This workflow provides a complete solution for handling Telegram Stars payments, invoicing and refunds using n8n. It automates the process of sending invoices, managing pre-checkout approvals, recordi

HTTP Request, Execute Workflow Trigger, Google Sheets +2
Slack & Telegram

clients kept booking meetings during my prayer times. i'd either miss a prayer or scramble to reschedule. the problem wasn't the clients — it was that my calendar had no blocked windows for salah. i n

Telegram Trigger, HTTP Request, Google Calendar +3
Slack & Telegram

Generate 360° product videos from a single photo using Google Veo 3 and Telegram

Telegram, Telegram Trigger, HTTP Request +1
Slack & Telegram

02b — Article callback. Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 30 nodes.

Telegram Trigger, Google Sheets, Telegram +1
Slack & Telegram

Automates LinkedIn job searches across multiple countries and categories, filters results with AI, stores data in Google Sheets, and sends weekly Telegram notifications. Perfect for professionals seek

Telegram Trigger, Item Lists, HTTP Request +3