docs: add daily WhatsApp summary implementation plan
This commit is contained in:
parent
9569485f78
commit
5a757ab8be
1 changed files with 238 additions and 0 deletions
238
docs/superpowers/plans/2025-05-12-daily-summary.md
Normal file
238
docs/superpowers/plans/2025-05-12-daily-summary.md
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
# Dagelijkse WhatsApp samenvatting — Implementation Plan
|
||||||
|
|
||||||
|
> **Voor agentic workers:** REQUIRED SUB-SKILL: Gebruik superpowers:subagent-driven-development (aanbevolen) of superpowers:executing-plans om dit plan taak-voor-taak te implementeren. Stappen gebruiken checkbox (`- [ ]`) syntax voor tracking.
|
||||||
|
|
||||||
|
**Goal:** Elke dag om 10:00 een WhatsApp-bericht naar de admin sturen met het totaal aantal dienstaanvragen van de vorige dag.
|
||||||
|
|
||||||
|
**Architecture:** Nieuwe module `dailyStats.js` houdt een dagtotaal bij in memory. `messageHandler.js` roept increment aan bij elke aanvraag. `node-cron` triggert om 10:00 de reset en verzending via bestaande `whatsappApi.sendTextMessage()`.
|
||||||
|
|
||||||
|
**Tech Stack:** Node.js, node-cron (nieuwe dependency), bestaande axios/express stack
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/dailyStats.js`
|
||||||
|
- Modify: `src/messageHandler.js`
|
||||||
|
- Modify: `src/index.js`
|
||||||
|
- Modify: `package.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Create dailyStats module
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/dailyStats.js`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write the dailyStats module**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let dailyTotal = 0
|
||||||
|
let yesterdayTotal = 0
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
dailyTotal++
|
||||||
|
}
|
||||||
|
|
||||||
|
function getYesterdayTotal() {
|
||||||
|
return yesterdayTotal
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetDay() {
|
||||||
|
yesterdayTotal = dailyTotal
|
||||||
|
dailyTotal = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { increment, getYesterdayTotal, resetDay }
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify the module loads without errors**
|
||||||
|
|
||||||
|
Run: `node -e "const m = require('./src/dailyStats'); m.increment(); m.increment(); m.resetDay(); console.log(m.getYesterdayTotal() === 2 ? 'OK' : 'FAIL')"`
|
||||||
|
Expected: `OK`
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/dailyStats.js
|
||||||
|
git commit -m "feat: add dailyStats module for tracking daily request totals"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Integrate dailyStats into messageHandler
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/messageHandler.js`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add dailyStats import and increment call**
|
||||||
|
|
||||||
|
`src/messageHandler.js` line 1-4, add import:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { findDienst, getPngFilePaths } = require('./dienstService')
|
||||||
|
const { sendTextMessage, sendImageMessage, notifyAdmin } = require('./whatsappApi')
|
||||||
|
const { checkLimit, increment, MAX_REQUESTS_PER_DAY } = require('./rateLimiter')
|
||||||
|
const { increment: incrementDaily } = require('./dailyStats')
|
||||||
|
```
|
||||||
|
|
||||||
|
`src/messageHandler.js` after `increment(author)` (line 51), add:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
increment(author)
|
||||||
|
incrementDaily()
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify messageHandler still loads**
|
||||||
|
|
||||||
|
Run: `node -e "require('./src/messageHandler'); console.log('OK')"`
|
||||||
|
Expected: `OK` (may show dotenv warning, that's fine)
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/messageHandler.js
|
||||||
|
git commit -m "feat: integrate dailyStats counter into message handler"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Add node-cron and schedule daily 10:00 summary
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `package.json`
|
||||||
|
- Modify: `src/index.js`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Install node-cron**
|
||||||
|
|
||||||
|
Run: `npm install node-cron`
|
||||||
|
Expected: node-cron added to `node_modules` and `package.json`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add cron job to index.js**
|
||||||
|
|
||||||
|
`src/index.js` — replace the entire file:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
require('dotenv').config()
|
||||||
|
const cron = require('node-cron')
|
||||||
|
const express = require('express')
|
||||||
|
const { handleWebhook } = require('./messageHandler')
|
||||||
|
const { loadDiensten } = require('./dienstService')
|
||||||
|
const { resetDay, getYesterdayTotal } = require('./dailyStats')
|
||||||
|
const { sendTextMessage } = require('./whatsappApi')
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
app.use(express.json({ limit: '10mb' }))
|
||||||
|
|
||||||
|
app.post('/webhook', async (req, res) => {
|
||||||
|
try {
|
||||||
|
await handleWebhook(req.body)
|
||||||
|
res.json({ success: true })
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Webhook processing error:', err.message)
|
||||||
|
res.status(500).json({ success: false, error: err.message })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/health', (req, res) => {
|
||||||
|
res.json({ status: 'ok' })
|
||||||
|
})
|
||||||
|
|
||||||
|
const PORT = process.env.WEBHOOK_PORT || 3002
|
||||||
|
|
||||||
|
loadDiensten()
|
||||||
|
|
||||||
|
cron.schedule('0 10 * * *', () => {
|
||||||
|
const adminNumber = process.env.ADMIN_NUMBER
|
||||||
|
if (!adminNumber) {
|
||||||
|
console.error('ADMIN_NUMBER not configured, skipping daily summary')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resetDay()
|
||||||
|
const total = getYesterdayTotal()
|
||||||
|
|
||||||
|
sendTextMessage(adminNumber, `Aantal dienstaanvragen gisteren: ${total}`)
|
||||||
|
.then(() => console.log(`Daily summary sent: ${total} requests`))
|
||||||
|
.catch(err => console.error('Failed to send daily summary:', err.message))
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`dienst-bot listening on port ${PORT}`)
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify server starts without errors**
|
||||||
|
|
||||||
|
Run: `timeout 3 node src/index.js || true`
|
||||||
|
Expected: Output shows `dienst-bot listening on port ...` and `Daily summary cron job scheduled for 10:00`
|
||||||
|
|
||||||
|
- [ ] **Step 4: Test cron callback manually**
|
||||||
|
|
||||||
|
Run: `node -e "
|
||||||
|
require('dotenv').config()
|
||||||
|
const { increment, resetDay, getYesterdayTotal } = require('./src/dailyStats')
|
||||||
|
increment()
|
||||||
|
increment()
|
||||||
|
increment()
|
||||||
|
resetDay()
|
||||||
|
console.log('Total:', getYesterdayTotal())
|
||||||
|
console.log(getYesterdayTotal() === 3 ? 'PASS' : 'FAIL')
|
||||||
|
"`
|
||||||
|
Expected: `Total: 3` followed by `PASS`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add package.json package-lock.json src/index.js
|
||||||
|
git commit -m "feat: add node-cron daily summary job at 10:00"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Verify end-to-end flow
|
||||||
|
|
||||||
|
**Files:** (none, verification only)
|
||||||
|
|
||||||
|
- [ ] **Step 1: Start the server**
|
||||||
|
|
||||||
|
Run: `node src/index.js &`
|
||||||
|
Wait 2 seconds for startup.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Simulate a webhook request to increment the counter**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
curl -s -X POST http://localhost:3002/webhook \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"dataType":"message","sessionId":"EdGpt","data":{"message":{"from":"120363407356808413@g.us","fromMe":false,"author":"test@c.us","body":"@EdGpt 0001","_data":{"mentionedJidList":["bot@c.us"]}}}}}'
|
||||||
|
```
|
||||||
|
Expected: `{"success":true}`
|
||||||
|
|
||||||
|
- [ ] **Step 3: Trigger the cron callback directly to verify summary message**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
node -e "
|
||||||
|
require('dotenv').config()
|
||||||
|
const { resetDay, getYesterdayTotal } = require('./src/dailyStats')
|
||||||
|
const { sendTextMessage } = require('./src/whatsappApi')
|
||||||
|
resetDay()
|
||||||
|
const total = getYesterdayTotal()
|
||||||
|
console.log('Would send to admin:', process.env.ADMIN_NUMBER)
|
||||||
|
console.log('Message:', 'Aantal dienstaanvragen gisteren: ' + total)
|
||||||
|
console.log(total > 0 ? 'PASS' : 'FAIL - expected >0')
|
||||||
|
"
|
||||||
|
```
|
||||||
|
Expected: `PASS` (shows message with total > 0)
|
||||||
|
|
||||||
|
- [ ] **Step 4: Stop the server**
|
||||||
|
|
||||||
|
Run: `kill %1 2>/dev/null; true`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit any remaining changes**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status
|
||||||
|
# Only commit if there are remaining changes
|
||||||
|
```
|
||||||
Loading…
Reference in a new issue