{
  "id": "BFLStatusV031001",
  "name": "БФЛ — служебный статус операции",
  "active": true,
  "versionId": "e8945e80-5bfb-45b0-a328-c18999612aa1",
  "nodes": [
    {
      "id": "fb0005c3-eeb8-4688-b1e8-5929dde8e5a6",
      "name": "Вход статуса",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "parameters": {
        "inputSource": "passthrough"
      },
      "position": [
        0,
        0
      ]
    },
    {
      "id": "6f639618-6590-41b4-b97a-16216566d59d",
      "name": "Прочитать состояние операции",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "KszG5ycOvocFLwHW",
          "cachedResultName": "bfl_content_versions"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $json.id }}"
            },
            {
              "keyName": "owner_chat_id",
              "condition": "eq",
              "keyValue": "710000001"
            },
            {
              "keyName": "operation_id",
              "condition": "eq",
              "keyValue": "={{ $json.operation_id }}"
            }
          ]
        },
        "returnAll": true
      },
      "position": [
        250,
        0
      ]
    },
    {
      "id": "640344f7-784d-46ce-81ca-f3e76f7445a3",
      "name": "Выбрать актуальный статус",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "parameters": {
        "mode": "runOnceForEachItem",
        "language": "javaScript",
        "jsCode": "function bflAccess(){return $('Вход статуса').first().json._bfl;}\nconst __result = await (async()=>{\n'use strict';\n// Text catalog only. Persist job/message IDs and trigger these messages from real\n// workflow transitions. This module neither sends messages nor changes job state.\nfunction progressText(event,context={}){\n  switch(event){\n    case 'accepted_news': return 'Взято в работу. Проверяю источник и готовлю пост.';\n    case 'accepted_post': return 'Взято в работу. Готовлю пост по твоей теме.';\n    case 'accepted_revision': return context.preserve_image===true\n      ?'Правки приняты. Обновляю текст, картинку сохраню.'\n      :'Правки приняты. Готовлю обновлённый пост.';\n    case 'writing': return 'Готовлю текст поста.';\n    case 'revising': return context.preserve_image===true\n      ?'Применяю правки к тексту. Картинка остаётся прежней.'\n      :'Применяю правки.';\n    case 'generating_image': return 'Создаю иллюстрацию. Это может занять несколько минут.';\n    case 'rendering': return 'Собираю обложку в фирменном стиле.';\n    case 'sending_preview': return 'Отправляю готовый пост на согласование.';\n    case 'preview_ready': return 'Готово. Пост отправлен на согласование — проверь его и выбери действие под картинкой.';\n    case 'publishing': return 'Публикую одобренный пост.';\n    case 'published': return 'Готово — пост опубликован в тестовом канале.';\n    case 'rejected': return 'Черновик отклонён.';\n    case 'duplicate_pending': return 'Этот запрос уже в работе. Повторно отправлять его не нужно.';\n    case 'stale_button': return 'Этот вариант уже неактивен. Используй кнопки под последним черновиком.';\n    case 'error_caption_too_long': return context.can_retry_revision===true\n      ?'Текст не поместился под картинкой. Нажми «Доработать» под последним доступным черновиком и попроси сократить его.'\n      :'Текст не поместился под картинкой. Не удалось подготовить вариант для согласования.';\n    case 'error_text': return context.previous_preserved===true\n      ?'Не удалось применить правки. Предыдущий черновик и картинка сохранены.'\n      :'Не удалось подготовить текст. Попробуй уточнить задачу.';\n    case 'error_image': return 'Не удалось создать иллюстрацию. Текст сохранён; пост пока не готов к согласованию.';\n    case 'generation_unknown': return 'Сервис не подтвердил результат генерации. Автоматический повтор остановлен, чтобы не запустить её дважды.';\n    case 'delivery_unknown': return 'Не удалось подтвердить отправку поста. Проверь, появился ли он: повторная отправка пока остановлена, чтобы не создать дубль.';\n    default: throw new Error('Unknown progress event');\n  }\n}\n\nconst input=$('Вход статуса').first().json;\nconst r=$json;\nconst events={accepted_news:[10,['text_preparing']],accepted_post:[10,['text_preparing']],accepted_revision:[10,['text_preparing']],writing:[20,['text_generating']],revising:[20,['text_generating']],generating_image:[30,['image_generating']],rendering:[40,['rendering_cover']],sending_preview:[50,['sending_preview_photo']],preview_ready:[60,['awaiting_approval']],publishing:[70,['publishing']],published:[80,['published']],rejected:[80,['rejected']],error:[90,['text_failed','image_failed','image_outcome_unknown','image_received_invalid','image_upload_failed','render_failed','preview_failed','preview_outcome_unknown','publication_outcome_unknown']]};\nconst event=input._notification_event,rule=events[event];\nconst base={...r,_notification_event:event,_notify:false};\nif(!rule||String(r.owner_chat_id)!=='710000001'||r.operation_id!==input.operation_id||!rule[1].includes(r.status)||r.notification_lock||['unknown','missing','disabled'].includes(r.notification_state)||Number(r.notification_retry_after||0)>Date.now())return {json:base};\nconst rank=rule[0];if(rank<Number(r.notification_rank||0))return {json:base};\nif(event==='preview_ready'&&(!r.approval_message_id||r.preview_photo_state!=='sent'))return {json:base};\nif(event==='published'&&(!r.published_message_id||r.channel_photo_state!=='sent'))return {json:base};\nlet text;\nif(event==='error'){\n if(r.status==='text_failed'&&r.origin==='news'&&/outcome_unknown/.test(r.error_code||'')){text='Ответ платного запроса не подтверждён. Тема и исходная статья сохранены. Повтор заблокирован до проверки результата запроса; другую тему можно выбрать отдельно.';}else if(r.status==='text_failed'&&r.origin==='news'&&r.error_code==='selected_primary_document_required'){text='Для этого правового вывода не хватает проверенного первичного документа. Источник сохранён. Можно выбрать другую тему или отправить /retry '+r.draft_key+' '+r.version+' подготовь узкий пересказ с атрибуцией источнику.';}else if(r.status==='text_failed'&&r.origin==='news'&&r.error_code==='selected_needs_source_check'){text='По сохранённому источнику не удалось подтвердить основной сюжет. Картинка не создавалась. Можно выбрать другую тему или уточнить задание: /retry '+r.draft_key+' '+r.version+' уточнение.';}else if(r.status==='text_failed'&&r.origin==='news'){\n const retry='/retry '+r.draft_key+' '+r.version;\n if(/caption_too_long|cover_.*too_long|cover_fields/.test(r.error_code||''))text='Подпись или надписи обложки не уложились в лимиты после двух попыток сокращения. Тема и источник сохранены. Продолжить тот же запрос без новых замечаний: '+retry;\n else if(/preview_semantic_fail|preview_exact_requires_owner_edit/.test(r.error_code||'')){let issues=[];try{issues=JSON.parse(r.editorial_notes||'[]');}catch{}const problem=String(issues.find(x=>typeof x.problem==='string')?.problem||'Спорная формулировка не подтверждена источником.').replace(/[\\r\\n\\u0000-\\u001f]/g,' ').slice(0,240);text='Не удалось подтвердить формулировку: '+problem+' Тема и источник сохранены. Для изменения этой формулировки можно добавить уточнение к '+retry;}\n else if(/^selected_/.test(r.error_code||''))text='Не удалось подготовить факты: ответ проверки не соответствует ожидаемому формату. Тема и источник сохранены. Продолжить тот же запрос без новых замечаний: '+retry;else text='Не удалось собрать пост из-за технической ошибки. Тема и источник сохранены. Продолжить тот же запрос без новых замечаний: '+retry;\n }else if(r.status==='text_failed'){\n  const retained=!!r.previous_caption&&!!r.source_image_id;\n  text=r.error_code?.includes('caption_too_long')?'Текст не поместился под картинкой. Не удалось подготовить вариант для согласования.':retained?'Не удалось применить правки. Предыдущий черновик и картинка сохранены.':'Не удалось подготовить текст.';\n  if(retained)text+=' Для продолжения отправь: /retry '+r.draft_key+' '+r.version+' новые замечания.';\n  else text+=' Попробуй уточнить тему новым /post.';\n }else if(r.status==='image_outcome_unknown')text=progressText('generation_unknown');\n else if(['preview_outcome_unknown','publication_outcome_unknown'].includes(r.status)){\n  if(r.error_code==='telegram_transport_interrupted')text=progressText('delivery_unknown');\n  else if(r.error_code==='telegram_rejected')text='Telegram отклонил отправку поста. Сохранённый текст и картинка не удалены. Сообщи об этой ошибке для проверки подключения бота; автоматического повтора нет.';\n  else text='Ответ Telegram не прошёл проверку отправленного поста. Текст и картинка сохранены. Сообщи об этой ошибке для проверки ответа; повторная отправка остановлена.';\n }\n else if(['image_failed','image_received_invalid'].includes(r.status))text=progressText('error_image');\n else text='Не удалось завершить подготовку. Текст и сохранённая картинка не удалены. Для продолжения отправь: /resume '+r.draft_key+' '+r.version+'.';\n}else text=progressText(event,{preserve_image:!!r.source_image_id});\nif(rank===Number(r.notification_rank||0)&&r.notification_text===text)return {json:base};\nconst operation=r.operation_id;\nreturn {json:{...base,_notify:true,_notify_rank:rank,_notify_text:text,_notify_lock:operation+'|'+String($execution.id),_notify_method:r.status_message_id?'editMessageText':'sendMessage'}};\n\n})();\nif(__result===null||__result===undefined)return __result;\nconst __a=bflAccess();\nconst __attach=(item)=>({...item,json:{...item.json,_bfl:__a,operation_actor_user_id:__a.user_id,operation_actor_chat_id:__a.chat_id,created_by_user_id:item.json.created_by_user_id||$json.created_by_user_id||__a.user_id}});\nreturn Array.isArray(__result)?__result.map(__attach):__attach(__result);"
      },
      "position": [
        500,
        0
      ]
    },
    {
      "id": "86141d29-1e15-4a93-b0e8-9c76c31028e5",
      "name": "Статус нужно обновить?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json._notify === true }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        }
      },
      "position": [
        750,
        0
      ]
    },
    {
      "id": "8a18603d-33d3-4653-acde-13854eff5cda",
      "name": "Закрепить обновление статуса",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "parameters": {
        "resource": "row",
        "operation": "update",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "KszG5ycOvocFLwHW",
          "cachedResultName": "bfl_content_versions"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $(\"Выбрать актуальный статус\").first().json.id }}"
            },
            {
              "keyName": "owner_chat_id",
              "condition": "eq",
              "keyValue": "710000001"
            },
            {
              "keyName": "status",
              "condition": "eq",
              "keyValue": "={{ $json.status }}"
            },
            {
              "keyName": "operation_id",
              "condition": "eq",
              "keyValue": "={{ $json.operation_id }}"
            },
            {
              "keyName": "notification_rank",
              "condition": "eq",
              "keyValue": "={{ $json.notification_rank }}"
            },
            {
              "keyName": "notification_lock",
              "condition": "eq",
              "keyValue": ""
            },
            {
              "keyName": "notification_state",
              "condition": "eq",
              "keyValue": "={{ $json.notification_state }}"
            }
          ]
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "notification_rank": "={{ $json._notify_rank }}",
            "notification_lock": "={{ $json._notify_lock }}"
          },
          "schema": [
            {
              "id": "notification_rank",
              "displayName": "notification_rank",
              "type": "number"
            },
            {
              "id": "notification_lock",
              "displayName": "notification_lock",
              "type": "string"
            }
          ]
        }
      },
      "position": [
        1000,
        0
      ],
      "alwaysOutputData": true
    },
    {
      "id": "30fcd24f-e6dd-4803-ad75-1fbbd8bfb885",
      "name": "Блокировка статуса получена?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ !!$json.id && $json.notification_lock === $(\"Выбрать актуальный статус\").first().json._notify_lock }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        }
      },
      "position": [
        1250,
        0
      ]
    },
    {
      "id": "80ca1ef7-85b6-4091-a9ab-234ea3f6032c",
      "name": "Есть сообщение статуса?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ !!$json.status_message_id }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        }
      },
      "position": [
        1500,
        0
      ]
    },
    {
      "id": "d67476cf-945b-41c4-a615-91fafab8f7c6",
      "name": "Отправить сообщение статуса",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "parameters": {
        "method": "POST",
        "url": "http://bfl-collaboration:8084/telegram",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {ticket:$('Вход статуса').first().json._bfl.ticket,purpose:\"progress\",context:$json,method:\"sendMessage\",body:{\"text\":($(\"Выбрать актуальный статус\").first().json._notify_text),\"parse_mode\":\"HTML\",\"disable_web_page_preview\":true} } }}",
        "options": {
          "timeout": 150000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "position": [
        0,
        260
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "CREDENTIAL_01",
          "name": "REDACTED httpHeaderAuth"
        }
      },
      "onError": "continueRegularOutput",
      "retryOnFail": false
    },
    {
      "id": "1021d7ef-63f2-4efe-8e97-a133705295ea",
      "name": "Изменить сообщение статуса",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "parameters": {
        "method": "POST",
        "url": "http://bfl-collaboration:8084/telegram",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {ticket:$('Вход статуса').first().json._bfl.ticket,purpose:\"progress\",context:$json,method:\"editMessageText\",body:{\"text\":($(\"Выбрать актуальный статус\").first().json._notify_text),\"parse_mode\":\"HTML\"} } }}",
        "options": {
          "timeout": 150000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "position": [
        250,
        260
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "CREDENTIAL_01",
          "name": "REDACTED httpHeaderAuth"
        }
      },
      "onError": "continueRegularOutput",
      "retryOnFail": false
    },
    {
      "id": "ed7ffea9-abe3-48e2-bd5a-5aea26bcc619",
      "name": "Проверить результат уведомления",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "parameters": {
        "mode": "runOnceForEachItem",
        "language": "javaScript",
        "jsCode": "function bflAccess(){return $('Вход статуса').first().json._bfl;}\nconst __result = await (async()=>{\nconst p=$('Закрепить обновление статуса').first().json;\nconst desired=$('Выбрать актуальный статус').first().json;\nlet ok=$json.ok===true;\nconst result=$json.result;\nconst existing=String(p.status_message_id||'');\nlet messageId=existing,error='',state='idle',retryAt=0;\nlet serial='';try{serial=JSON.stringify($json.error||$json);}catch{}\n// Only derived code/state is returned; raw Telegram errors never enter owner text.\nif(!ok&&/message is not modified/i.test(serial)&&existing)ok=true;\nif(ok){\n if(result&&typeof result==='object'&&String(result.chat?.id)===bflAccess().chat_id&&Number.isSafeInteger(result.message_id))messageId=String(result.message_id);\n if(!messageId){ok=false;error='notification_result_unconfirmed';state='unknown';}\n}else{\n let retry=Number($json.parameters?.retry_after||$json.error?.parameters?.retry_after||$json.error?.cause?.parameters?.retry_after||0);\n if(!retry){const m=/retry_after[^\\d]{0,12}(\\d+)/i.exec(serial);if(m)retry=Number(m[1]);}\n if(retry>0||/429|Too Many Requests/i.test(serial)){error='notification_rate_limited';state='rate_limited';retryAt=Date.now()+Math.max(retry,1)*1000;}\n else if(/message to edit not found|message can.t be edited/i.test(serial)){error='notification_message_missing';state='missing';}\n else if(/400|403|Bad Request|Forbidden/i.test(serial)){error='notification_rejected';state='disabled';}\n else{error='notification_outcome_unknown';state='unknown';}\n}\nreturn {json:{...p,status_message_id:messageId,notification_text:ok?desired._notify_text:p.notification_text||'',notification_error:error,notification_state:state,notification_retry_after:retryAt,_notify_ok:ok}};\n\n})();\nif(__result===null||__result===undefined)return __result;\nconst __a=bflAccess();\nconst __attach=(item)=>({...item,json:{...item.json,_bfl:__a,operation_actor_user_id:__a.user_id,operation_actor_chat_id:__a.chat_id,created_by_user_id:item.json.created_by_user_id||$json.created_by_user_id||__a.user_id}});\nreturn Array.isArray(__result)?__result.map(__attach):__attach(__result);"
      },
      "position": [
        500,
        260
      ]
    },
    {
      "id": "03038e48-93e7-4ee5-96d2-1b54ae79d8a4",
      "name": "Сохранить результат уведомления",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "parameters": {
        "resource": "row",
        "operation": "update",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "KszG5ycOvocFLwHW",
          "cachedResultName": "bfl_content_versions"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $(\"Закрепить обновление статуса\").first().json.id }}"
            },
            {
              "keyName": "owner_chat_id",
              "condition": "eq",
              "keyValue": "710000001"
            },
            {
              "keyName": "operation_id",
              "condition": "eq",
              "keyValue": "={{ $(\"Закрепить обновление статуса\").first().json.operation_id }}"
            },
            {
              "keyName": "notification_lock",
              "condition": "eq",
              "keyValue": "={{ $(\"Закрепить обновление статуса\").first().json.notification_lock }}"
            }
          ]
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "status_message_id": "={{ $json.status_message_id }}",
            "notification_text": "={{ $json.notification_text }}",
            "notification_error": "={{ $json.notification_error }}",
            "notification_state": "={{ $json.notification_state }}",
            "notification_retry_after": "={{ $json.notification_retry_after }}",
            "notification_lock": ""
          },
          "schema": [
            {
              "id": "status_message_id",
              "displayName": "status_message_id",
              "type": "string"
            },
            {
              "id": "notification_text",
              "displayName": "notification_text",
              "type": "string"
            },
            {
              "id": "notification_error",
              "displayName": "notification_error",
              "type": "string"
            },
            {
              "id": "notification_state",
              "displayName": "notification_state",
              "type": "string"
            },
            {
              "id": "notification_retry_after",
              "displayName": "notification_retry_after",
              "type": "number"
            },
            {
              "id": "notification_lock",
              "displayName": "notification_lock",
              "type": "string"
            }
          ]
        }
      },
      "position": [
        750,
        260
      ],
      "alwaysOutputData": true
    },
    {
      "id": "9f611ae1-1450-4d90-999a-f4b7c7c5dfaa",
      "name": "Один повтор уведомления разрешён?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.notification_state === \"rate_limited\" && Number($(\"Вход статуса\").first().json._notification_attempt||0)<1 && $json.notification_retry_after-Date.now()<=10000 }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        }
      },
      "position": [
        1000,
        260
      ]
    },
    {
      "id": "259e84f5-3c7d-43af-b002-85d2c032a658",
      "name": "Дождаться retry_after",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "parameters": {
        "amount": "={{ Math.max(0.01,($json.notification_retry_after-Date.now())/1000) }}",
        "unit": "seconds"
      },
      "position": [
        1250,
        260
      ]
    },
    {
      "id": "affb1651-b4de-4ae5-9187-2f52f5ab8291",
      "name": "Повторить только актуальное уведомление",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "parameters": {
        "mode": "runOnceForEachItem",
        "language": "javaScript",
        "jsCode": "function bflAccess(){return $('Вход статуса').first().json._bfl;}\nconst __result = await (async()=>{\nreturn {json:{...$('Вход статуса').first().json,_notification_attempt:1}};\n})();\nif(__result===null||__result===undefined)return __result;\nconst __a=bflAccess();\nconst __attach=(item)=>({...item,json:{...item.json,_bfl:__a,operation_actor_user_id:__a.user_id,operation_actor_chat_id:__a.chat_id,created_by_user_id:item.json.created_by_user_id||$json.created_by_user_id||__a.user_id}});\nreturn Array.isArray(__result)?__result.map(__attach):__attach(__result);"
      },
      "position": [
        1500,
        260
      ]
    },
    {
      "id": "4ea4d9b3-be0b-4cea-b543-6aeca52c0a9f",
      "name": "Один повтор служебного статуса",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "parameters": {
        "source": "database",
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "BFLStatusV031001"
        },
        "mode": "once",
        "options": {
          "waitForSubWorkflow": true
        }
      },
      "position": [
        0,
        520
      ],
      "onError": "continueRegularOutput",
      "alwaysOutputData": true,
      "retryOnFail": false
    },
    {
      "id": "da14aedf-2df7-4f8d-b248-d604143c58c6",
      "name": "Вернуть управление",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "parameters": {
        "mode": "runOnceForEachItem",
        "language": "javaScript",
        "jsCode": "function bflAccess(){return $('Вход статуса').first().json._bfl;}\nconst __result = await (async()=>{\nreturn {json:{notification_complete:true}};\n})();\nif(__result===null||__result===undefined)return __result;\nconst __a=bflAccess();\nconst __attach=(item)=>({...item,json:{...item.json,_bfl:__a,operation_actor_user_id:__a.user_id,operation_actor_chat_id:__a.chat_id,created_by_user_id:item.json.created_by_user_id||$json.created_by_user_id||__a.user_id}});\nreturn Array.isArray(__result)?__result.map(__attach):__attach(__result);"
      },
      "position": [
        250,
        520
      ]
    },
    {
      "id": "bea85434-d4d1-54c2-a45e-15fcd31c04a9",
      "name": "Участник → Один повтор служебного статуса",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -2200,
        1500
      ],
      "parameters": {
        "jsCode": "const a=$('Вход статуса').first().json._bfl;if(!a?.ticket)throw Error(\"actor_context_missing\");return $input.all().map((i,k)=>({...i,json:{...i.json,_bfl:a,operation_actor_user_id:a.user_id,operation_actor_chat_id:a.chat_id},pairedItem:{item:k}}));"
      }
    },
    {
      "id": "edaafe2e-f6cd-5fa6-9184-17c2e8d8786b",
      "name": "Записать контекст выполнения",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        -2300,
        1800
      ],
      "parameters": {
        "method": "POST",
        "url": "http://bfl-collaboration:8084/execution-context",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {ticket:$json._bfl.ticket,context:$json,execution_id:String($execution.id)} }}",
        "options": {
          "timeout": 60000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "CREDENTIAL_01",
          "name": "REDACTED httpHeaderAuth"
        }
      },
      "retryOnFail": false
    }
  ],
  "connections": {
    "Вход статуса": {
      "main": [
        [
          {
            "node": "Записать контекст выполнения",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Прочитать состояние операции": {
      "main": [
        [
          {
            "node": "Выбрать актуальный статус",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Выбрать актуальный статус": {
      "main": [
        [
          {
            "node": "Статус нужно обновить?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Статус нужно обновить?": {
      "main": [
        [
          {
            "node": "Закрепить обновление статуса",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Вернуть управление",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Закрепить обновление статуса": {
      "main": [
        [
          {
            "node": "Блокировка статуса получена?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Блокировка статуса получена?": {
      "main": [
        [
          {
            "node": "Есть сообщение статуса?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Вернуть управление",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Есть сообщение статуса?": {
      "main": [
        [
          {
            "node": "Изменить сообщение статуса",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Отправить сообщение статуса",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Отправить сообщение статуса": {
      "main": [
        [
          {
            "node": "Проверить результат уведомления",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Изменить сообщение статуса": {
      "main": [
        [
          {
            "node": "Проверить результат уведомления",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Проверить результат уведомления": {
      "main": [
        [
          {
            "node": "Сохранить результат уведомления",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Сохранить результат уведомления": {
      "main": [
        [
          {
            "node": "Один повтор уведомления разрешён?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Один повтор уведомления разрешён?": {
      "main": [
        [
          {
            "node": "Дождаться retry_after",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Вернуть управление",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Дождаться retry_after": {
      "main": [
        [
          {
            "node": "Повторить только актуальное уведомление",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Повторить только актуальное уведомление": {
      "main": [
        [
          {
            "node": "Участник → Один повтор служебного статуса",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Один повтор служебного статуса": {
      "main": [
        [
          {
            "node": "Вернуть управление",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Участник → Один повтор служебного статуса": {
      "main": [
        [
          {
            "node": "Один повтор служебного статуса",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Записать контекст выполнения": {
      "main": [
        [
          {
            "node": "Прочитать состояние операции",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "executionTimeout": 20,
    "saveDataSuccessExecution": "all",
    "saveDataErrorExecution": "all",
    "saveExecutionProgress": false,
    "errorWorkflow": "BFLEditorError20260916"
  },
  "activeVersionId": "e8945e80-5bfb-45b0-a328-c18999612aa1"
}