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

Читать дальше