dienst_echo_whatsappgroep/docs/superpowers/specs/2025-05-11-dienst-bot-design.md

5.6 KiB

Dienst Bot - WhatsApp Dienstnummer Bot

Samenvatting

Een Node.js webhook service die luistert naar berichten in een WhatsApp groep via de wwebjs-api. Wanneer een groepsllid EdGpt noemt (@EdGpt) met een 4-cijferig dienstnummer, zoekt de bot de bijbehorende PNG-afbeeldingen op en stuurt deze privé terug naar de afzender.

Context

  • wwebjs-api: REST API wrapper voor whatsapp-web.js, draait op localhost:3000
  • Sessie: EdGpt, actief in WhatsApp groep TestGpt
  • Diensten: Gescande dienstschema's opgeslagen als PNG in diensten/png/, met metadata in diensten/dienst-tijden.json
  • dienst-tijden.json: Array van objecten met dienstnummer (4 cijfers), startTime, endTime, en paginas (array met bestandsnaam voor PNG)

Architectuur

WhatsApp groep bericht ("@EdGpt 4001")
  → wwebjs-api (localhost:3000)
    → webhook POST naar dienst-bot (localhost:3002/webhook)
      → bericht parsing: @EdGpt + 4-cijferig dienstnummer
      → lookup PNGs via dienst-tijden.json
      → stuur PNGs privé via wwebjs-api REST endpoint

Twee componenten:

  1. wwebjs-api (bestaand) - met BASE_WEBHOOK_URL=http://localhost:3002/webhook geconfigureerd
  2. dienst-bot (nieuw) - Express.js webhook receiver op poort 3002

Webhook Payload

wwebjs-api stuurt per message event een POST naar de webhook URL:

{
  "dataType": "message",
  "sessionId": "EdGpt",
  "data": {
    "message": {
      "from": "120363407356808413@g.us",
      "author": "31620248011@c.us",
      "body": "@EdGpt 4001",
      "fromMe": false,
      "hasMedia": false,
      "_data": {
        "mentionedJidList": ["31620248011@c.us"]
      }
    }
  }
}

Belangrijke velden:

  • from: groep-ID bij groepsberichten (eindigt op @g.us)
  • author: de afzender van het bericht binnen de groep
  • fromMe: true als het bericht van de bot zelf komt
  • mentionedJidList: array van genoemde contact-IDs

Berichtverwerking (Core Logic)

  1. Filter op dataType: negeer alles behalve dataType === "message"
  2. Filter op afzender: negeer als fromMe === true (bot's eigen berichten)
  3. Filter op groep: negeer als from !== ALLOWED_GROUP
  4. Check mention: controleer of het bot-nummer voorkomt in mentionedJidList OF of de tekst @EdGpt (case-insensitive) bevat
  5. Extract dienstnummer: regex \b(\d{4})\b op message body - neem het eerste match
  6. Lookup: zoek dienstnummer in dienst-tijden.json, krijg lijst met PNG bestandsnamen
  7. Stuur PNGs: voor elke PNG, stuur privé naar afzender via wwebjs-api

Afbeelding Versturen

Per PNG bestand:

  1. Lees file van schijf uit DIENSTEN_PNG directory
  2. Converteer naar base64
  3. Stuur via wwebjs-api endpoint:
POST {WHATSAPP_API_ENDPOINT}/client/sendMessage/EdGpt
Content-Type: application/json

{
  "chatId": "{author}",
  "contentType": "MessageMedia",
  "content": {
    "mimetype": "image/png",
    "data": "{base64_string}",
    "filename": "{bestandsnaam}.png"
  }
}

Elke PNG wordt als apart privébericht verstuurd.

Foutafhandeling

Situatie Actie
Ongeldig dienstnummer (niet in JSON) Stuur privé bericht: "Dienstnummer XXXX niet gevonden."
Geen PNGs gevonden voor dienst Stuur privé bericht: "Geen pagina's gevonden voor dienst XXXX."
Geen dienstnummer in bericht Negeer stil (geen actie)
Fout bij verzenden PNG Log error + stuur WhatsApp foutmelding naar admin
Webhook verwerking fout Log error + stuur WhatsApp foutmelding naar admin, return 500 naar wwebjs-api

Configuratie

.env (dienst-bot project)

# WhatsApp API Configuration
WHATSAPP_API_ENDPOINT=http://localhost:3000
WHATSAPP_SESSION=EdGpt

# Webhook Configuration
WEBHOOK_PORT=3002
ALLOWED_GROUP=120363407356808413@g.us
BOT_NAME=EdGpt

# Paths
DIENSTEN_JSON=./diensten/dienst-tijden.json
DIENSTEN_PNG=./diensten/png

# Admin notifications
ADMIN_NUMBER=31620248011@c.us

wwebjs-api .env (toevoeging)

BASE_WEBHOOK_URL=http://localhost:3002/webhook

Bestandsstructuur

dienst_echo_whatsappgroep/
├── .env                        # configuratie
├── package.json                # dependencies: express, dotenv, axios
├── src/
│   ├── index.js                # Express server, webhook endpoint
│   ├── messageHandler.js       # bericht parsing + dienst lookup + dispatch
│   └── dienstService.js        # JSON laden + PNG file reading
├── diensten/                   # bestaande data
│   ├── dienst-tijden.json
│   └── png/
└── docs/
    └── superpowers/
        └── specs/
            └── 2025-05-11-dienst-bot-design.md

Modules

src/index.js

  • Express server op WEBHOOK_PORT
  • POST /webhook endpoint
  • Laadt .env en start server
  • Delegeert verwerking naar messageHandler

src/messageHandler.js

  • handleWebhook(payload): hoofdfunctie, voert alle filterstappen uit
  • Parse message body voor dienstnummer
  • Roept dienstService aan voor lookup
  • Stuurt PNGs of foutmelding via wwebjs-api

src/dienstService.js

  • loadDiensten(): laadt en cache dienst-tijden.json
  • findDienst(nummer): retourneer dienst-object of null
  • getPngFiles(dienst): retourneer array van absolute bestandspaden

Dependencies

  • express - HTTP server voor webhook endpoint
  • dotenv - .env variabelen laden
  • axios - HTTP client voor wwebjs-api calls
  • fs - file reading voor PNG bestanden (built-in)
  • path - pad constructie (built-in)

Operationeel

  • Starten: pm2 start src/index.js --name dienst-bot
  • Loggen: pm2 logs dienst-bot
  • Herstarten: pm2 restart dienst-bot
  • Stoppen: pm2 stop dienst-bot