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

57 lines
2.8 KiB
Markdown

# 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.