diff --git a/.env.example b/.env.example index 84dd46e..ce6f5ab 100644 --- a/.env.example +++ b/.env.example @@ -16,14 +16,3 @@ MAX_REQUESTS_PER_DAY=5 # Admin notifications ADMIN_NUMBER=31612345678@c.us - -# Telegram watchdog (fallback when WhatsApp API is down) -TELEGRAM_BOT_URL=http://localhost:3004 - -# Telegram watchdog configuration (telegram-bot process) -TELEGRAM_BOT_TOKEN= -TELEGRAM_ADMIN_CHAT_ID= -TELEGRAM_BOT_PORT=3004 -DIENST_BOT_HEALTH_URL=http://localhost:3002/health -WWEBJS_API_SESSION_URL=http://192.168.5.252:3001/session/status/EdGpt -HEALTH_CHECK_INTERVAL_MS=300000 diff --git a/docs/superpowers/plans/2026-07-12-telegram-watchdog.md b/docs/superpowers/plans/2026-07-12-telegram-watchdog.md deleted file mode 100644 index 57702bd..0000000 --- a/docs/superpowers/plans/2026-07-12-telegram-watchdog.md +++ /dev/null @@ -1,202 +0,0 @@ -# Telegram Watchdog Implementation Plan - -> **For agentic workers:** Stappen gebruiken checkbox (`- [ ]`) syntax voor tracking. - -**Goal:** Apart Telegram bot process dat de admin waarschuwt als WhatsApp API of dienst-bot plat ligt. - -**Architecture:** `telegramBot.js` draait als apart systemd process op nextcloud, gebruikt Telegram Bot API via axios. Dienst-bot roept `POST /notify` aan als WhatsApp notificatie faalt. Periodieke health checks naar beide services. - -**Tech Stack:** Node.js, Express, axios, dotenv (bestaande dependencies, geen nieuwe) - ---- - -### Task 1: Create `src/telegramBot.js` - -- [ ] **Create `src/telegramBot.js`** - -```js -require('dotenv').config() -const express = require('express') -const axios = require('axios') - -const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN -const ADMIN_CHAT_ID = process.env.TELEGRAM_ADMIN_CHAT_ID -const PORT = process.env.TELEGRAM_BOT_PORT || 3004 -const DIENST_BOT_HEALTH = process.env.DIENST_BOT_HEALTH_URL || 'http://localhost:3002/health' -const WWEBJS_SESSION = process.env.WWEBJS_API_SESSION_URL || 'http://192.168.5.252:3001/session/status/EdGpt' -const CHECK_INTERVAL = parseInt(process.env.HEALTH_CHECK_INTERVAL_MS || '300000', 10) - -const app = express() -app.use(express.json()) - -let dienstBotOk = true -let wwebjsOk = true - -function sendTelegram(text) { - return axios.post(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, { - chat_id: ADMIN_CHAT_ID, - text, - parse_mode: 'Markdown' - }, { timeout: 10000 }) -} - -async function startupNotification() { - try { - await sendTelegram('✅ Telegram watchdog online — gezondheidschecks actief') - console.log('Startup notification sent') - } catch (err) { - console.error('Failed to send startup notification:', err.message) - } -} - -async function checkHealth() { - let currentDienstBotOk = true - let currentWwebjsOk = true - - try { - await axios.get(DIENST_BOT_HEALTH, { timeout: 5000 }) - } catch { - currentDienstBotOk = false - } - - try { - const res = await axios.get(WWEBJS_SESSION, { timeout: 5000 }) - currentWwebjsOk = res.data?.state === 'CONNECTED' - } catch { - currentWwebjsOk = false - } - - if (dienstBotOk !== currentDienstBotOk) { - const icon = currentDienstBotOk ? '✅' : '❌' - const status = currentDienstBotOk ? 'weer online' : 'niet bereikbaar' - try { - await sendTelegram(`${icon} dienst-bot ${status}`) - } catch (err) { - console.error('Failed to send dienst-bot status:', err.message) - } - dienstBotOk = currentDienstBotOk - } - - if (wwebjsOk !== currentWwebjsOk) { - const icon = currentWwebjsOk ? '✅' : '❌' - const status = currentWwebjsOk ? 'weer online' : 'niet bereikbaar' - try { - await sendTelegram(`${icon} wwebjs-api ${status}`) - } catch (err) { - console.error('Failed to send wwebjs-api status:', err.message) - } - wwebjsOk = currentWwebjsOk - } - - console.log(`Health check: dienst-bot=${currentDienstBotOk ? 'UP' : 'DOWN'}, wwebjs-api=${currentWwebjsOk ? 'UP' : 'DOWN'}`) -} - -app.post('/notify', async (req, res) => { - const { text } = req.body - if (!text) { - return res.status(400).json({ success: false, error: 'missing text' }) - } - try { - await sendTelegram(`⚠️ ${text}`) - res.json({ success: true }) - } catch (err) { - console.error('Failed to forward notification:', err.message) - res.status(500).json({ success: false, error: err.message }) - } -}) - -app.get('/health', (req, res) => { - res.json({ status: 'ok', services: { dienstBot: dienstBotOk, wwebjsApi: wwebjsOk } }) -}) - -startupNotification() -setInterval(checkHealth, CHECK_INTERVAL) -checkHealth() - -app.listen(PORT, () => { - console.log(`telegram-bot listening on port ${PORT}`) -}) -``` - -- [ ] **Update `.env.example` — add Telegram variables** - -``` -# Telegram watchdog -TELEGRAM_BOT_TOKEN= -TELEGRAM_ADMIN_CHAT_ID= -TELEGRAM_BOT_PORT=3004 -DIENST_BOT_HEALTH_URL=http://localhost:3002/health -WWEBJS_API_SESSION_URL=http://192.168.5.252:3001/session/status/EdGpt -HEALTH_CHECK_INTERVAL_MS=300000 -``` - -### Task 2: Update `src/whatsappApi.js` — add Telegram fallback - -- [ ] **Modify `notifyAdmin()` in `src/whatsappApi.js`** - -Replace: -```js -async function notifyAdmin(errorText) { - const adminNumber = process.env.ADMIN_NUMBER - if (!adminNumber) { - console.error('ADMIN_NUMBER not configured, skipping admin notification') - return - } - try { - await sendTextMessage(adminNumber, `[dienst-bot fout] ${errorText}`) - } catch (err) { - console.error('Failed to notify admin:', err.message) - } -} -``` - -With: -```js -async function notifyAdmin(errorText) { - const adminNumber = process.env.ADMIN_NUMBER - if (!adminNumber) { - console.error('ADMIN_NUMBER not configured, skipping admin notification') - return - } - try { - await sendTextMessage(adminNumber, `[dienst-bot fout] ${errorText}`) - } catch (err) { - console.error('WhatsApp admin notification failed, falling back to Telegram:', err.message) - try { - const telegramUrl = process.env.TELEGRAM_BOT_URL - if (telegramUrl) { - await axios.post(`${telegramUrl}/notify`, { text: errorText }, { timeout: 5000 }) - } - } catch (telegramErr) { - console.error('Telegram notification also failed:', telegramErr.message) - } - } -} -``` - -- [ ] **Update `.env.example` — add TELEGRAM_BOT_URL to dienst-bot section** - -``` -# Telegram watchdog (fallback when WhatsApp API is down) -TELEGRAM_BOT_URL=http://localhost:3004 -``` - -### Task 3: Update AGENTS.md - -- [ ] **Add telegram-bot to tables and commands** - -Add rows: -- Systemd service: `telegram-bot.service` -- Poort: `3004` -- Health check: `curl http://localhost:3004/health` -- Commands for status/restart/logs - -- [ ] **Update release-proces** — add step for restarting telegram-bot - -### Task 4: Deploy & verify on nextcloud - -- [ ] `ssh aiaiaiaiagent@nextcloud` — create systemd service -- [ ] Add TELEGRAM_* vars to .env on nextcloud -- [ ] `sudo systemctl daemon-reload && sudo systemctl enable --now telegram-bot` -- [ ] Check status & logs -- [ ] Update release-proces: rsync + restart beide services diff --git a/docs/superpowers/specs/2026-07-12-telegram-watchdog-design.md b/docs/superpowers/specs/2026-07-12-telegram-watchdog-design.md deleted file mode 100644 index 68c6da6..0000000 --- a/docs/superpowers/specs/2026-07-12-telegram-watchdog-design.md +++ /dev/null @@ -1,135 +0,0 @@ -# Telegram Watchdog — Design Document - -## Doel - -Een apart Telegram bot proces dat de admin waarschuwt wanneer de WhatsApp API (wwebjs-api) of de dienst-bot zelf niet bereikbaar is. Dit is het enige communicatiekanaal dat overblijft als WhatsApp uitvalt. - -## Architectuur - -``` - ┌──────────────────┐ - │ dienst-bot │ Node.js (nextcloud:3002) - │ (Express) │ - └──────┬───────────┘ - │ POST /notify (alleen bij falen WhatsApp) - │ - ┌──────▼───────────┐ - │ telegram-bot │ Node.js (nextcloud:3003) - │ (Express) │ - │ │ - │ ─── health check │ dienst-bot /health (elke 5min) - │ ─── health check │ wwebjs-api /session/status (elke 5min) - │ ─── Telegram API │ verstuur notificaties naar admin - └──────────────────┘ -``` - -### Twee processen - -- **dienst-bot** (bestaand, ongewijzigd behalve `notifyAdmin`): stuurt bij fouten eerst WhatsApp, als dat faalt → Telegram via POST /notify -- **telegram-bot** (nieuw): ontvangt notificaties van dienst-bot, voert zelfstandig health checks uit, stuurt Telegram berichten - -### Geen nieuwe npm packages - -Zowel dienst-bot als telegram-bot gebruiken alleen `axios` en `dotenv` — beide al in gebruik. - -## telegram-bot — specificatie - -### Endpoints - -| Endpoint | Doel | -|----------|------| -| `POST /notify` | Ontvangt notificaties van dienst-bot (alleen als WhatsApp faalde) | -| `GET /health` | Health check voor systemd | - -**POST /notify body:** -```json -{ - "text": "Kan wwebjs-api niet bereiken na 3 pogingen (ECONNREFUSED)" -} -``` - -### Health checks (periodiek) - -Elke 5 minuten worden beide endpoints gecheckt: - -1. `GET http://localhost:3002/health` — dienst-bot -2. `GET http://192.168.5.252:3001/session/status/EdGpt` — wwebjs-api - -Statusovergangen triggeren een notificatie: -- **down → up**: "✅ dienst-bot is weer online" -- **up → down**: "❌ dienst-bot niet bereikbaar (ECONNREFUSED)" - -### Notificaties bij opstart - -Bij het opstarten stuurt telegram-bot direct een bericht: -"✅ Telegram watchdog online — gezondheidschecks aktief" - -### .env variabelen (telegram-bot) - -``` -TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234 -TELEGRAM_ADMIN_CHAT_ID=123456789 -TELEGRAM_BOT_PORT=3003 -DIENST_BOT_HEALTH_URL=http://localhost:3002/health -WWEBJS_API_SESSION_URL=http://192.168.5.252:3001/session/status/EdGpt -HEALTH_CHECK_INTERVAL_MS=300000 -``` - -## Wijzigingen aan dienst-bot - -### whatsappApi.js — notifyAdmin() - -```js -async function notifyAdmin(errorText) { - // WhatsApp eerst (als de API werkt) - try { - await sendTextMessage(adminNumber, `[dienst-bot fout] ${errorText}`) - } catch (err) { - // WhatsApp faalt (API down) → Telegram backup - await notifyTelegram(errorText) - } -} - -async function notifyTelegram(text) { - const url = process.env.TELEGRAM_BOT_URL - if (!url) return - try { - await axios.post(`${url}/notify`, { text }, { timeout: 5000 }) - } catch (err) { - console.error('Telegram notification failed:', err.message) - } -} -``` - -### Nieuwe .env variabele (dienst-bot) - -``` -TELEGRAM_BOT_URL=http://localhost:3003 -``` - -## Systemd service - -Bestand: `/etc/systemd/system/telegram-bot.service` - -- Working directory: `/home/aiaiaiaiagent/whatsapp-scripts/dienst_echo_whatsappgroep` -- ExecStart: `/usr/bin/node src/telegramBot.js` -- User: `aiaiaiaiagent` -- Depends: dienst-bot.service (After= dienst-bot.service) -- Restart: always - -## Bestanden in de repo - -| Bestand | Doel | -|---------|------| -| `src/telegramBot.js` | Telegram watchdog process (Express server) | -| `.env.example` | Nieuwe TELEGRAM_* variabelen toevoegen | -| `docs/superpowers/specs/2026-07-12-telegram-watchdog-design.md` | Dit document | - -Geen wijzigingen aan `package.json` — beide processen gebruiken dezelfde dependencies. - -## Error handling - -- telegram-bot faalt: dienst-bot logt error, verder geen impact op WhatsApp verkeer -- dienst-bot faalt: telegram-bot detecteert via health check en stuurt notificatie -- telegram-bot zelf fault: systemd restart (Restart=always) -- Telegram API timeout: loggen en negeren (geen retry nodig) diff --git a/src/index.js b/src/index.js index 9a398de..8319573 100644 --- a/src/index.js +++ b/src/index.js @@ -2,22 +2,11 @@ require('dotenv').config() const http = require('http') const cron = require('node-cron') const express = require('express') -const axios = require('axios') const { handleWebhook } = require('./messageHandler') const { loadDiensten } = require('./dienstService') const { resetDay, getYesterdayTotal } = require('./dailyStats') const { sendTextMessage } = require('./whatsappApi') -async function notifyTelegramOnline() { - const url = process.env.TELEGRAM_BOT_URL - if (!url) return - try { - await axios.post(`${url}/notify`, { text: 'dienst-bot online' }, { timeout: 5000 }) - } catch (err) { - console.error('Telegram startup notification failed:', err.message) - } -} - const app = express() app.use(express.json({ limit: '10mb' })) @@ -83,7 +72,6 @@ async function startServer() { console.log(`Allowed group: ${process.env.ALLOWED_GROUP}`) console.log(`Bot name: ${process.env.BOT_NAME}`) console.log('Daily summary cron job scheduled for 10:00') - notifyTelegramOnline() }) function shutdown(signal) { diff --git a/src/telegramBot.js b/src/telegramBot.js deleted file mode 100644 index efccff7..0000000 --- a/src/telegramBot.js +++ /dev/null @@ -1,101 +0,0 @@ -require('dotenv').config() -const express = require('express') -const axios = require('axios') - -const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN -const ADMIN_CHAT_ID = process.env.TELEGRAM_ADMIN_CHAT_ID -const PORT = process.env.TELEGRAM_BOT_PORT || 3004 -const DIENST_BOT_HEALTH = process.env.DIENST_BOT_HEALTH_URL || 'http://localhost:3002/health' -const WWEBJS_SESSION = process.env.WWEBJS_API_SESSION_URL || 'http://192.168.5.252:3001/session/status/EdGpt' -const CHECK_INTERVAL = parseInt(process.env.HEALTH_CHECK_INTERVAL_MS || '300000', 10) - -const app = express() -app.use(express.json()) - -let dienstBotOk = null -let wwebjsOk = null - -function sendTelegram(text) { - return axios.post(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, { - chat_id: ADMIN_CHAT_ID, - text, - parse_mode: 'Markdown' - }, { timeout: 10000 }) -} - -async function startupNotification() { - try { - await sendTelegram('✅ Telegram watchdog online — gezondheidschecks actief') - console.log('Startup notification sent') - } catch (err) { - console.error('Failed to send startup notification:', err.message) - } -} - -async function checkHealth() { - let currentDienstBotOk = true - let currentWwebjsOk = true - - try { - await axios.get(DIENST_BOT_HEALTH, { timeout: 5000 }) - } catch { - currentDienstBotOk = false - } - - try { - const res = await axios.get(WWEBJS_SESSION, { timeout: 5000 }) - currentWwebjsOk = res.data?.state === 'CONNECTED' - } catch { - currentWwebjsOk = false - } - - if (dienstBotOk !== null && dienstBotOk !== currentDienstBotOk) { - const icon = currentDienstBotOk ? '✅' : '❌' - const status = currentDienstBotOk ? 'weer online' : 'niet bereikbaar' - try { - await sendTelegram(`${icon} dienst-bot ${status}`) - } catch (err) { - console.error('Failed to send dienst-bot status:', err.message) - } - } - dienstBotOk = currentDienstBotOk - - if (wwebjsOk !== null && wwebjsOk !== currentWwebjsOk) { - const icon = currentWwebjsOk ? '✅' : '❌' - const status = currentWwebjsOk ? 'weer online' : 'niet bereikbaar' - try { - await sendTelegram(`${icon} wwebjs-api ${status}`) - } catch (err) { - console.error('Failed to send wwebjs-api status:', err.message) - } - } - wwebjsOk = currentWwebjsOk - - console.log(`Health check: dienst-bot=${currentDienstBotOk ? 'UP' : 'DOWN'}, wwebjs-api=${currentWwebjsOk ? 'UP' : 'DOWN'}`) -} - -app.post('/notify', async (req, res) => { - const { text } = req.body - if (!text) { - return res.status(400).json({ success: false, error: 'missing text' }) - } - try { - await sendTelegram(text) - res.json({ success: true }) - } catch (err) { - console.error('Failed to forward notification:', err.message) - res.status(500).json({ success: false, error: err.message }) - } -}) - -app.get('/health', (req, res) => { - res.json({ status: 'ok', services: { dienstBot: dienstBotOk, wwebjsApi: wwebjsOk } }) -}) - -startupNotification() -setInterval(checkHealth, CHECK_INTERVAL) -setTimeout(checkHealth, 10000) - -app.listen(PORT, () => { - console.log(`telegram-bot listening on port ${PORT}`) -}) diff --git a/src/whatsappApi.js b/src/whatsappApi.js index e0e65b9..72b29dd 100644 --- a/src/whatsappApi.js +++ b/src/whatsappApi.js @@ -73,15 +73,7 @@ async function notifyAdmin(errorText) { try { await sendTextMessage(adminNumber, `[dienst-bot fout] ${errorText}`) } catch (err) { - console.error('WhatsApp admin notification failed, falling back to Telegram:', err.message) - try { - const telegramUrl = process.env.TELEGRAM_BOT_URL - if (telegramUrl) { - await axios.post(`${telegramUrl}/notify`, { text: `[dienst-bot fout] ${errorText}` }, { timeout: 5000 }) - } - } catch (telegramErr) { - console.error('Telegram notification also failed:', telegramErr.message) - } + console.error('Failed to notify admin:', err.message) } }