7 хв читанняІнтеграції

Інтеграція Linear зі скорочувачем посилань - автоматичне створення тікетів за алертами

Підключіть виявлення зламаних посилань Elido та стрибки порогів кліків до команди Linear. Налаштування, фільтр команди, маршрутизація міток і реальні сценарії збоїв.

Marius Voß
DevRel · edge infra
Пайплайн від виявлення до тікету: інтеграція Linear зі скорочувачем посилань створює issue з події про зламане посилання

Linear перейшов у статус Live у каталозі інтеграцій Elido 22 травня 2026 року. Першою подією, яку ми запустили, став broken_link_hook - коли наш сканер знаходить непрацююче коротке посилання, він створює issue в Linear у команді, обраній під час підключення, з метриками кліків у тілі тікету та мітками, що маршрутизуються за тегами. Цей пост - технічний розбір для інженерів: як працює автентифікація, як виглядає JSON-payload і як ми розширили той самий пайплайн на стрибки порогу кліків, щоб черговий отримував тікет, а не дзвінок о третій ночі.

Якщо ви підтримуєте сотні або тисячі коротких посилань у продакшні, ви вже знаєте цей сценарій збою. Маркетинг змінює ціль кампанії, новий URL повертає 404, і ніхто цього не помічає - поки користувач не опублікує скриншот мертвого посилання в Bluesky. Linear - це місце, де ваша команда вже займається тріажем багів, тому саме туди ми і надсилаємо тікет.

Підключення Linear через Personal API Key

Інтеграція Linear використовує Personal API Key, а не OAuth. Ми зробили цей вибір з трьох причин: API Key обмежений робочим простором, краще переживає зміну адміністраторів порівняно з OAuth-токенами, прив'язаними до конкретного користувача, і документація API: Authentication Linear прямо рекомендує його для задач типу сервер-сервер.

Згенеруйте ключ у Linear: Налаштування, API, Personal API keys, Створити ключ. Назвіть його elido-integration, щоб пізніше можна було відкликати без здогадок. Скопіюйте ключ (починається з lin_api_) і вставте його в картку інтеграції Linear у дашборді Elido.

Що відбувається далі: ми виконуємо запит viewer для перевірки ключа, потім запит teams для заповнення селектора команди. Ви обираєте команду за замовчуванням. Цей вибір записує рядок в integration_configs у Postgres, включно з team ID, присвоєним Linear. При наявності кількох команд тегову маршрутизацію можна додати тут же - детальніше нижче.

POST /v1/workspaces/:id/integrations/linear/connect
{
  "api_key": "lin_api_<redacted>",
  "default_team_id": "TEAM_a1b2c3",
  "default_priority": 2,
  "labels": ["short-link", "auto-filed"]
}

За лаштунками сервіс api-core зберігає ключ у зашифрованому вигляді згідно зі схемою envelope-шифрування з ADR-0036. Розшифрований ключ існує в пам'яті лише під час фактичного GraphQL-виклику. Ми ніколи не логуємо сире значення; у UI логів інтеграції відображаються лише останні 4 символи.

Важлива примітка: Personal API Keys Linear прив'язані до користувача, який їх створив. Якщо цей користувач піде з компанії і ви деактивуєте його обліковий запис, ключ перестане працювати. Найкраща практика - створити в Linear сервісного користувача (ми використовуємо [email protected]) і генерувати ключ від його імені.

Схема: url-scanner виявляє непрацюючий редирект і надсилає подію broken_link_hook до Issues API Linear

Наш сервіс url-scanner щотижня обходить усі активні короткі посилання в робочому просторі. Для кожного посилання він виконує HTTP HEAD на адресі призначення, потім GET, якщо HEAD не підтримується, а відтак перевіряє TLS-ланцюжок. Чотири умови переводять посилання в статус зламаного:

  1. HTTP 4xx або 5xx при двох послідовних перевірках (подвійна перевірка для фільтрації транзієнтних 500)
  2. TLS прострочений або самопідписаний там, де тиждень тому він був валідний
  3. DNS NXDOMAIN - хост призначення більше не резолвиться
  4. Збіг із відбитком припаркованого домену - хост резолвиться, але тіло відповіді відповідає відомому шаблону сквотера (ми підтримуємо невеликий набір відбитків)

При спрацьовуванні будь-якої з чотирьох умов сканер публікує подію link.broken у Redpanda. Webhook-dispatcher її споживає, знаходить активні інтеграції і для Linear матеріалізує наступний payload.

Реальний payload broken_link_hook зі staging-оточення (частину полів скорочено):

{
  "event": "link.broken",
  "link_id": "01J9V7QXMZ8K2Y3N4P5R6T7W8Z",
  "short_url": "https://s.elido.me/spring-launch",
  "destination_url": "https://oldcampaign.example.com/landing",
  "failure_type": "http_5xx",
  "failure_detail": "502 Bad Gateway, 2 consecutive probes",
  "last_working_at": "2026-05-28T14:22:00Z",
  "detected_at": "2026-06-04T03:11:42Z",
  "clicks_last_7d": 2841,
  "clicks_last_24h": 412,
  "top_referrers": [
    { "host": "linkedin.com", "clicks": 1203 },
    { "host": "twitter.com", "clicks": 488 },
    { "host": "direct", "clicks": 612 }
  ],
  "tags": ["campaign-spring-2026", "paid"],
  "owner_email": "[email protected]"
}

Адаптер Linear у services/api-core/internal/integrations/linear/broken_link_hook.go бере цей payload і формує GraphQL-мутацію до Issues API Linear. Заголовок issue слідує фіксованому шаблону, щоб черговий міг знайти його через grep:

[Elido] Broken link: /spring-launch (502 Bad Gateway)

Тіло - це структурований Markdown із п'яти розділів: деталі посилання, останній робочий часовий штамп, дельта кліків відносно 7-денного baseline, три головних реферери та блок запропонованого рішення. Блок рішення дивиться на failure_type і обирає шаблонну пораду - для http_5xx: "Перевірте, чи не застосовує призначення rate limit або не знаходиться в процесі деплою"; для parked_domain: "Домен міг закінчитись або бути захоплений сквотером, заархівуйте це посилання"; і так далі.

Мітки призначаються з двох джерел: ваш набір міток за замовчуванням (налаштовується при підключенні) і динамічні мітки, похідні зі списку тегів. Якщо тег відповідає paid або organic, він додається як мітка, щоб PM-и могли фільтрувати свої представлення в Linear.

Дедуплікація, rate limits і dead-letter queue

Ми дедуплікуємо події broken_link_hook за хостом призначення на 24 години. Якщо oldcampaign.example.com впав і 800 коротких посилань ведуть на нього, ви отримаєте один тікет у Linear з усіма 800 короткими URL у тілі, а не 800 окремих тікетів. Це сувора порода з ранньої бети - перший клієнт, який потрапив на впалий домен, був засипаний тікетами.

GraphQL-ендпоінт Linear має глобальний rate limit на робочий простір. Наш webhook-dispatcher відстежує заголовок Retry-After і використовує експоненційний backoff із повним джиттером до п'яти спроб. Після п'яти спроб подія потрапляє в чергу недоставлених повідомлень. Записи DLQ видно в розділі Налаштування, Інтеграції, Linear, Невдалі події; кожну можна відтворити одним кліком. DLQ також доступна через функцію webhooks для програмного відтворення.

Пороги кліків і користувацькі тригери

Макет тіла issue в Linear, створеного Elido: шаблон заголовка, розділи тіла та маршрутизація міток

Той самий адаптер Linear обробляє події click_threshold_hook. Пороги задаються на рівні посилання або кампанії в дашборді Elido; issue в Linear створюється при перетині смуги. Сьогодні підтримуються два типи смуг:

  • Spike: кліки за останню годину перевищують N-кратне значення ковзного 7-денного погодинного baseline (за замовчуванням N дорівнює 3). Корисно для виявлення вірусного поширення або, що менш приємно, ботового трафіку.
  • Cliff: кліки за останню годину падають нижче 10% ковзного baseline. Корисно для виявлення мертвих кампаній - якщо платна реклама була призупинена на стороні джерела, ви побачите тікет у Linear ще до маркетингового стендапу.

Payload click_threshold_hook:

{
  "event": "link.click_threshold",
  "link_id": "01J9V7QXMZ8K2Y3N4P5R6T7W8Z",
  "short_url": "https://s.elido.me/spring-launch",
  "band": "spike",
  "current_hour_clicks": 8421,
  "baseline_hourly_clicks": 612,
  "multiplier": 13.76,
  "top_referrers": [
    { "host": "news.ycombinator.com", "clicks": 6203 },
    { "host": "direct", "clicks": 1488 }
  ],
  "tags": ["campaign-spring-2026"],
  "triggered_at": "2026-06-04T11:14:00Z"
}

Для spike блок рішення каже: "Переконайтеся, що це органічний трафік, а не кампанія з підміни рефереру. Перевірте розбивку рефереру вище." Для cliff: "Переконайтеся, що кампанія ще активна на стороні джерела. Якщо вона була призупинена - заархівуйте це посилання."

Тегова маршрутизація між кількома командами

Стандартного селектора команди достатньо для робочого простору з 20 осіб. У великих організаціях потрібно, щоб тікет Linear за маркетинговим посиланням ішов у команду Marketing, а тікет за посиланням із документації - в команду Documentation. З цим справляється тегова маршрутизація.

Правила маршрутизації зберігаються в integration_configs.routing_json і застосовуються зверху вниз. Правило виглядає так:

[
  {
    "tag_glob": "campaign-*",
    "team_id": "TEAM_growth",
    "labels": ["growth", "urgent"]
  },
  { "tag_glob": "docs-*", "team_id": "TEAM_docs", "labels": ["docs"] },
  {
    "tag_glob": "internal-*",
    "team_id": "TEAM_internal",
    "labels": ["internal"]
  },
  { "default": true, "team_id": "TEAM_a1b2c3" }
]

Перемагає перше правило, чий glob збігається хоча б з одним тегом посилання. Якщо збігів немає - спрацьовує правило за замовчуванням. Синтаксис glob збігається з фільтрами збережених представлень Linear, які PM-и вже знають.

Можна також маршрутизувати за failure_type. Деякі команди хочуть, щоб усі TLS-збої йшли до команди платформи - вони зазвичай вказують на помилки конфігурації сертифіката в користувацькому домені тенанта. Додайте правило з ключем failure_type: tls_expired - і готово.

Користувацькі тригери через webhooks

Не кожна команда хоче створювати тікети в Linear для кожного типу подій, що ми публікуємо. Повний каталог подій задокументовано на сторінці функції webhooks, але поширені комбінації, які команди налаштовують поряд із Linear, такі:

  • link.created - у Linear для аудиту нових посилань (рідко, як правило для compliance-команд)
  • domain.takeover_detected - для TLS-сюрпризів у користувацьких доменах
  • link.scan_complete - для щотижневих зведених тікетів (один issue на запуск сканування з усіма позначеними посиланнями)

Якщо потрібної події немає в каталозі, її можна побудувати самостійно за допомогою універсального webhook-призначення та нашого посібника з observability. Або просто залиште запит функціональності на нашій публічній Linear-дошці - мета, але рекурсивно.

Тарифи і що доступно на кожному плані

Інтеграція Linear входить у тариф Pro і вище. На Free можна підключити Linear, але доступний лише broken_link_hook (без порогів кліків і користувацьких тригерів). Повну таблицю дивіться на сторінці тарифів. Якщо ви велика команда, що розглядає інтеграцію з міркувань compliance - наприклад, стаття 32 GDPR вимагає виявлення витоків даних через зламані редиректи на домени сквотерів - на сторінці Enterprise-рішень описано, що ми пропонуємо у масштабі.

Матеріали за темою

У повному каталозі інтеграцій станом на червень 2026 року 43 вендори, з яких Linear входить до числа 20 активних. Якщо ваша команда використовує Jira - адаптер для нього знаходиться в беті; напишіть нам, і ми його увімкнемо.

Поширені запитання

Як Elido автентифікується в Linear?

Ми використовуємо Personal API Key з областю дії на рівні робочого простору, а не OAuth. Ключ генерується в Linear у розділі Налаштування - API, після чого вставляється в картку інтеграції Elido. Ключ ніколи не виходить з нашого vault і приховується з логів. При ротації ключа наступна подія ініціює м'який запит повторної автентифікації замість тихої помилки.

Що саме вважається зламаним посиланням у події broken_link_hook?

Наш url-scanner щотижня обходить кожне активне коротке посилання і фіксує чотири умови: HTTP 4xx або 5xx при двох послідовних перевірках, прострочений або невалідний TLS-сертифікат, DNS NXDOMAIN та збіг із відомими відбитками припаркованих доменів. Будь-яка з цих чотирьох умов створює один тікет у Linear, дедуплікований за хостом призначення на 24 години - щоб один впалий домен не генерував 800 тікетів.

Чи можна надсилати issue в різні команди Linear залежно від тегів посилання?

Так. На екрані підключення обирається команда за замовчуванням, після чого додаються правила маршрутизації - наприклад, теги виду campaign-* ідуть у команду Growth, а теги виду docs-* - в Engineering. Правила застосовуються зверху вниз із дефолтним fallback. Набір правил зберігається в Postgres, тому зміни доступні в журналі аудиту адміністратора.

Чи працює це і для алертів за порогом кліків, а не лише для зламаних посилань?

Так, починаючи з Phase 12. Той самий адаптер Linear обробляє події click_threshold_hook поряд із broken_link_hook. Пороги задаються на рівні посилання або кампанії в дашборді Elido, і при перетині смуги створюється issue в Linear - або spike (3x базове значення за годину), або cliff (падіння нижче 10% базового значення).

Що станеться, якщо Linear застосує rate limit до інтеграції?

GraphQL-ендпоінт Linear повертає 429 із заголовком Retry-After. Наш webhook-dispatcher враховує це з експоненційним backoff до п'яти спроб, після чого поміщає подію в чергу недоставлених повідомлень. Записи DLQ видно в Налаштування - Інтеграції - Linear - Невдалі події; кожну можна відтворити одним кліком. DLQ також доступна через GraphQL API за адресою /v1/integrations/linear/dlq. Стійкого 429 від Linear у продакшні ми поки не бачили.

Спробуйте Elido

Вставте URL - отримайте коротке посилання

Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.

Безкоштовно, без реєстрації · 2 на день

Спробуйте Elido

URL-скорочувач із хостингом у ЄС: власні домени, глибока аналітика, відкритий API. Безкоштовний тариф - без кредитної картки.

Теги
linear url shortener integration
linear broken link detection
linear automation
linear API integration
short link alerts linear

Читати далі