181 lines
5.6 KiB
Markdown
181 lines
5.6 KiB
Markdown
# 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:
|
|
|
|
```json
|
|
{
|
|
"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)
|
|
|
|
```env
|
|
# 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)
|
|
|
|
```env
|
|
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`
|