dienst_echo_whatsappgroep/README.md
Eddy de Vink ee9b67a78e revert: verwijder ackTracker (dwaalspoor) — bridge fabriceert acks
ackTracker + message_ack-verwerking + check-loop + ACK_* env + docs uit de bot.
De bridge fabriceert acks (5219 blz 2 kreeg ack=2 zonder transmissie), dus
ack-tracking gaf verkeerde signalen. Enige betrouwbare bron: apparaat + getInfo.
Media-pacing zit nu bridge-breed (MEDIA_SEND_DELAY_MS). Poppler re-render als
fix verwijderd uit docs (wassen neus voor de race-klasse).
2026-09-26 22:55:28 +02:00

213 lines
7.8 KiB
Markdown

# Dienst Bot
> Dit project is gemaakt door middel van vibecoding met [OpenCode 1.14.40](https://opencode.ai).
WhatsApp bot die dienstschema's (PNG) privé verstuurt op basis van een 4-cijferig dienstnummer, gepost in een speciale WhatsApp groep.
## Hoe het werkt
1. Iemand stuurt een **4-cijferig dienstnummer** in de groep (bijv. `4002`)
2. De bot zoekt het dienstschema op in `dienst-tijden.json`
3. De bijbehorende PNG-bestanden worden **privé** naar de afzender gestuurd
4. Via een **vastgezet welkomstbericht** in de groep staat uitleg over het gebruik
De bot gebruikt een **speciale groep** (Dienst opvragen EdGPT-EBS) waarin **elk bericht dat uit exact 4 cijfers bestaat** wordt verwerkt. Geen @mention nodig.
## Vereisten
- [Node.js](https://nodejs.org/) 18+
- [wwebjs-api](https://github.com/pedroslopez/whatsapp-web.js) Docker container op nextcloud (poort 3001)
- WhatsApp sessie "EdGpt" actief in wwebjs-api
- Telegram bot token (voor watchdog, optioneel)
## Installatie
```bash
git clone <repo-url>
cd dienst_echo_whatsappgroep
npm install
```
## Configuratie
Kopieer `.env.example` naar `.env` en vul de waarden in:
```env
# WhatsApp API
WHATSAPP_API_ENDPOINT=http://192.168.5.252:3001
WHATSAPP_SESSION=EdGpt
# Webhook
WEBHOOK_PORT=3002
ALLOWED_GROUP=120363407613652082@g.us
# Canonical dienstenroot (alleen-lezen consumer)
DIENSTEN_DIR=../Whatsapp_Dienst/diensten
# Admin
ADMIN_NUMBER=31620248011@c.us
# Telegram watchdog (optioneel, backup kanaal)
TELEGRAM_BOT_URL=http://localhost:3004
TELEGRAM_BOT_TOKEN=
TELEGRAM_ADMIN_CHAT_ID=
```
### wwebjs-api webhook config
In de `.env` van wwebjs-api:
```env
BASE_WEBHOOK_URL=http://192.168.5.252:3002/webhook
ENABLE_LOCAL_CALLBACK_EXAMPLE=FALSE
ENABLE_WEBHOOK=TRUE
```
Belangrijk: gebruik **`docker compose up -d`** (niet `docker restart`) om `.env` wijzigingen door te voeren.
## Data
`Whatsapp_Dienst` is de enige eigenaar van bron-PDF's en gegenereerde dienstenartefacten. De echo-bot heeft geen eigen actieve `diensten/`-directory en leest uitsluitend de root die met `DIENSTEN_DIR` is geconfigureerd.
Onder `DIENSTEN_DIR` staan:
- `dienst-tijden.json` — array met dienstmetadata:
```json
[
{
"dienstnummer": "4002",
"startTime": "09:30",
"endTime": "10:30",
"paginas": [
{ "bestandsnaam": "4002-001.png" },
{ "bestandsnaam": "4002-002.png" }
]
}
]
```
- `png/` — PNG-bestanden met dienstschema's (bijv. `4002-001.png`)
`DIENSTEN_DIR` is de enige data-padvariabele. De echo-bot maakt of genereert geen bestanden in deze root.
## Gebruik
### Starten (nextcloud — huidig)
De bot draait op **nextcloud** via **systemd** (gemigreerd van Mac Mini LaunchDaemon → PM2, nu systemd).
```bash
# Status
ssh aiaiaiaiagent@nextcloud "sudo -A systemctl status dienst-bot"
# Herstarten
ssh aiaiaiaiagent@nextcloud "sudo -A systemctl restart dienst-bot"
# Logs volgen
ssh aiaiaiaiagent@nextcloud "sudo -A journalctl -u dienst-bot -n 50 -f"
```
### Oude Mac Mini (niet meer actief)
Plist: `/Library/LaunchDaemons/nl.eddydevink.dienst-bot.plist` → `.disabled`
Wrapper: `run-dienst-bot.sh` (codesign fix voor Homebrew Node)
## Projectstructuur
```
src/
index.js # Express webhook server + cron job
messageHandler.js # Berichtverwerking en filtering
rateLimiter.js # Spam protectie (max 5 per dag)
dailyStats.js # Dagelijkse aanvraag-teller
dienstService.js # JSON lookup en PNG bestandspaden
whatsappApi.js # WhatsApp API client (bericht + afbeelding)
telegramBot.js # Telegram watchdog (apart process, health checks)
```
## Welkomstbericht
De groep heeft een **vastgezet welkomstbericht** dat automatisch door EdGpt wordt herplaatst als het is verlopen (30 dagen). De tekst luidt:
> *Welkom in Dienst opvragen EdGpt-EBS. Stuur hier je 4 cijferige dienstnummer en EdGpt zal het prive naar je toe sturen, alleen 4 cijfers meer niet.*
Bij elke interactie met de groep controleert de bot of het pinned bericht nog bestaat en plaatst het opnieuw indien nodig.
## Foutafhandeling
- **Ongeldig dienstnummer**: de bot stuurt een melding terug naar de afzender
- **Fout bij verzenden tekst/PNG**: maximaal 3 pogingen met exponential backoff (1s, 2s, 4s) voor 5xx HTTP-fouten en connectieproblemen (ECONNRESET, ECONNREFUSED, ETIMEDOUT). Bij definitieve fout krijgt de admin een melding.
- **Admin meldingen**: eerst via WhatsApp (`ADMIN_NUMBER`), bij falen (WhatsApp API down) via Telegram watchdog
- **EADDRINUSE (poort 3002 in gebruik)**: de server wacht 5 seconden en herhaalt de bind-poging, met `SO_REUSEADDR` om TIME_WAIT te omzeilen
- **Graceful shutdown**: de server handelt SIGTERM en SIGINT af door actieve connecties netjes te sluiten (10s timeout)
- **Restart-loop preventie**: systemd `Restart=always` met `RestartSec=5`
- **Webhook fout**: wordt gelogd in de logs
## Media-levering: acks & pacing (RCA 2026-09-26)
**Ack-tracking is VERWIJDERD (dwaalspoor).** De ack-tracker (`message_ack` → admin-melding
bij ack<2) is uit de bot gehaald: de bridge fabriceert acks (dienst 5219 blz 2 kreeg
`ack=2` voor een bericht dat nooit getransmitteerd was) — ze zijn geen bezorgbewijs en
gaven verkeerde signalen. Enige betrouwbare bronnen: het apparaat en `getInfo`
(`message.getInfo()` → `read`/`readRemaining`). De bridge-`delivery`/acs van de store zijn
nooit leveringsbewijs.
> **🛡️ Media-pacing zit bridge-breed (2026-09-26), niet in de bot.** Staged-ghost-race:
> de wwebjs-media-pipeline is één tab; een direct-opvolgende media-send (van elke client)
> overlapt en de 2e verliest (in store + ack2 maar nooit verzonden). De bridge serialiseert
> nu alle media-sends over alle sessies en wacht `MEDIA_SEND_DELAY_MS` (bridge `.env`, 500)
> ertussen. De bot pauzeert niet. Details/config/locatie: zie AGENTS.md en vault "Whatsapp
> rest-api.md". Tijdelijke mitigatie; permanente fix (fork) staat open.
## Spam protectie
Elke gebruiker kan maximaal `MAX_REQUESTS_PER_DAY` (standaard 5) diensten per dag opvragen. Bij overschrijding krijgt de gebruiker een melding. De teller wordt dagelijks automatisch gereset (bij de eerste request na middernacht).
## Dagelijkse samenvatting
Elke dag om **10:00** stuurt de bot een WhatsApp-bericht naar `ADMIN_NUMBER` met het totaal aantal **alle** 4-cijferige berichten van de vorige dag (00:00 t/m 23:59).
```
📊 Aantal dienstaanvragen gisteren: N
```
De teller wordt bijgehouden in memory door `dailyStats.js` en gereset na verzending van de samenvatting. De scheduling gebruikt `node-cron` (`0 10 * * *`).
## Telegram Watchdog
Sinds juli 2026 draait er een apart **telegram-bot** proces (`src/telegramBot.js`) als backup communicatiekanaal. Dit proces draait als eigen systemd service (`telegram-bot.service`) op nextcloud.
### Wat het doet
- **Startup**: stuurt "online" melding naar admin via Telegram
- **Health checks** (elke 5 min): checkt dienst-bot (`/health`) en wwebjs-api (`/session/status`)
- **Statusovergangen**: alleen bij up→down of down→up wordt een notificatie gestuurd (geen spam)
- **Fallback**: als `notifyAdmin()` in de dienst-bot faalt (WhatsApp API onbereikbaar), wordt het bericht doorgestuurd naar Telegram
### Configuratie
| Variabele | Doel |
|-----------|------|
| `TELEGRAM_BOT_TOKEN` | Token van @BotFather |
| `TELEGRAM_ADMIN_CHAT_ID` | Jouw Telegram chat-ID |
| `TELEGRAM_BOT_PORT=3004` | Poort voor intern `/notify` endpoint |
| `DIENST_BOT_HEALTH_URL` | URL voor dienst-bot health check |
| `WWEBJS_API_SESSION_URL` | URL voor wwebjs-api session status |
| `HEALTH_CHECK_INTERVAL_MS=300000` | Interval tussen health checks |
| `TELEGRAM_BOT_URL` | (in dienst-bot .env) URL voor Telegram fallback |
### Commando's
```bash
# Status
ssh aiaiaiaiagent@nextcloud "sudo -A systemctl status telegram-bot"
# Herstarten
ssh aiaiaiaiagent@nextcloud "sudo -A systemctl restart telegram-bot"
# Logs
ssh aiaiaiaiagent@nextcloud "sudo -A journalctl -u telegram-bot -n 50 -f"
```
## Licentie
Public Domain