tcef-notifications/docs/legacy-telegram.md
vjrj d1fc6798dc Fase 1c: canal Telegram (telegram-worker) — codigo migrado, inerte
Envio de alertas Telegram desde el servicio (docs/legacy-telegram.md): por alerta,
texto Markdown (content + firelink i18n) + ubicacion, como node-red.

- types: canal 'telegram', notif.type 'telegram', campo telegramNotified
- telegram/message.ts: buildTelegramMessages (firelink es/en/gl + location)
- telegram/client.ts: cliente Bot API (fetch), interpretResponse (429 retry_after,
  403 blocked)
- telegram/rate.ts: throttle por chat (1 msg/s) + computeWaitMs puro
- handlers.processTelegramJob: idempotencia (notification_sends canal telegram),
  modos dry-run/shadow/canary/full, throttle, 429->retry, bloqueo->sub inactiva
- poller/queue/index: canal telegram integrado; worker con rate limiter global
  BullMQ (25/s por bot); cliente por idioma (es/gl->ES, en->EN)
- config: bloque telegram (tokens es/en, server, globalPerSec, perChatMinMs)

85 tests en verde, typecheck y build OK. Sin TELEGRAM_TOKEN_* configurados el
worker no se activa (todo inerte). Falta: extraer tokens de bot de flows_cred +
rollout con el usuario. Los flujos conversacionales de los bots siguen en node-red.
2026-07-13 18:49:52 +02:00

2.8 KiB

Envío Telegram viejo (fase 1c — caracterización)

Fuente: todos-contra-el-fuego/telegram-bot/flows.json (nodos "calc distances", "send location", senders telegram sender), locales node-red.

Qué envía node-red por cada alerta de fuego a un chat suscrito

Dos mensajes al chatId de la suscripción (subs type: 'telegram'):

  1. Texto (type: "message", parse_mode: "Markdown"): content + salto de línea + firelink.
    • content = la misma cadena kmnasa/kmvecinal del matching (ver legacy-matching.md §3; lleva 🔥 y el км cirílico).
    • firelink (i18n): [<label>](https://{{server}}/fire/{{enc}}) con enc = sealed (el mismo Iron del matching).
      • es: [más información](https://{{server}}/fire/{{enc}})
      • en: [more information](https://{{server}}/fire/{{enc}})
      • gl: [máis información](https://{{server}}/fire/{{enc}})
  2. Ubicación (type: "location"): { latitude: fire.lat, longitude: fire.lon }.

No hay botones/inline-keyboard en la alerta (solo parse_mode: Markdown).

Bots

  • Dos instancias node-red separadas: ES (/opt/node-red-data-git, puerto 1880) y EN (/opt/node-red-data-git-en, 1881). Tokens en flows_cred*.json (cifrados con el credentialSecret de node-red; copiados a tcef-private-config). El servicio los recibe por env (TELEGRAM_TOKEN_ES / TELEGRAM_TOKEN_EN) — no están en claro aquí; hay que extraerlos/pedirlos.
  • Selección de bot: por idioma del suscriptor (es/gl → bot ES, en → bot EN).

Límites de la Bot API de Telegram

  • ~30 msg/s global por bot → el servicio usa 25/s (margen).
  • ~1 msg/s por chat individual.
  • 429 devuelve parameters.retry_after (segundos) → respetar.
  • Bot bloqueado por el usuario (403 "bot was blocked by the user") → marcar la sub inactiva y no reintentar.

Integración en el servicio (unificada)

  • El matcher (1b) genera docs notifications con type: 'telegram' para las subs telegram cuando MATCHER_AUDIENCE incluye telegram. El doc lleva subsId → el worker carga la sub para el chatId.
  • Un telegram-worker (canal telegram, como fcm/email) consume esos docs: envía texto + ubicación, marca telegramNotified, idempotencia por notification_sends (canal telegram), mismos modos dry-run/shadow/canary/full y kill switch.

Fuera de alcance (documentado)

  • Canales públicos: si los flows publican alertas también en canales públicos del proyecto (además de a las subs), esa vía se migra aparte o se deja explícitamente en node-red. Config opcional TELEGRAM_PUBLIC_CHANNELS; por defecto no se toca.
  • Flujos conversacionales de los bots (/start, alta/baja de subs, /lang, etc.) se quedan en node-red — solo se migra el ENVÍO de alertas.