diff --git a/docs/superpowers/plans/2026-05-11-spam-protection.md b/docs/superpowers/plans/2026-05-11-spam-protection.md new file mode 100644 index 0000000..b25c1a3 --- /dev/null +++ b/docs/superpowers/plans/2026-05-11-spam-protection.md @@ -0,0 +1,174 @@ +# Spam Protection Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Limit each user to max 5 dienst requests per day, with automatic daily reset. + +**Architecture:** In-memory rate limiter module that tracks request counts per user per day. Integrated into the message handler pipeline before dienst lookup. Sends a friendly warning when limit is exceeded. + +**Tech Stack:** Node.js, no new dependencies needed + +--- + +### Task 1: Create rate limiter module + +**Files:** +- Create: `src/rateLimiter.js` + +- [ ] **Step 1: Create `src/rateLimiter.js`** + +```js +const MAX_REQUESTS_PER_DAY = parseInt(process.env.MAX_REQUESTS_PER_DAY, 10) || 5 + +const userCounts = new Map() +let currentDate = new Date().toDateString() + +function resetIfNeeded() { + const today = new Date().toDateString() + if (today !== currentDate) { + userCounts.clear() + currentDate = today + console.log('Rate limiter: daily counters reset') + } +} + +function checkLimit(userId) { + resetIfNeeded() + const count = userCounts.get(userId) || 0 + return { + allowed: count < MAX_REQUESTS_PER_DAY, + count, + max: MAX_REQUESTS_PER_DAY + } +} + +function increment(userId) { + resetIfNeeded() + const count = (userCounts.get(userId) || 0) + 1 + userCounts.set(userId, count) + return count +} + +module.exports = { checkLimit, increment, MAX_REQUESTS_PER_DAY } +``` + +- [ ] **Step 2: Commit** + +```bash +git add src/rateLimiter.js +git commit -m "feat: add rate limiter module" +``` + +--- + +### Task 2: Integrate rate limiter into message handler + +**Files:** +- Modify: `src/messageHandler.js:1,25-36` + +- [ ] **Step 1: Add rate limiter import at top of `src/messageHandler.js`** + +Add after line 2: + +```js +const { checkLimit, increment, MAX_REQUESTS_PER_DAY } = require('./rateLimiter') +``` + +- [ ] **Step 2: Add rate limit check in `handleWebhook` after dienstnummer extraction** + +Insert between the `dienstnummer` null check (line 36) and the `console.log` (line 38), replacing lines 38-40 with: + +```js + console.log(`Processing dienst ${dienstnummer} for ${message.author}`) + + const author = message.author + if (!author) return + + const limit = checkLimit(author) + if (!limit.allowed) { + await sendTextMessage(author, `Je hebt vandaag het maximum van ${limit.max} diensten bereikt. Probeer het morgen opnieuw.`) + console.log(`Rate limit reached for ${author} (${limit.count}/${limit.max})`) + return + } + + increment(author) +``` + +- [ ] **Step 3: Verify the file looks correct** + +Run: `node -e "require('./src/messageHandler')"` (should not throw) + +- [ ] **Step 4: Commit** + +```bash +git add src/messageHandler.js +git commit -m "feat: integrate rate limiter into message handler" +``` + +--- + +### Task 3: Add config to .env and restart + +**Files:** +- Modify: `.env` +- Modify: `.env.example` + +- [ ] **Step 1: Add `MAX_REQUESTS_PER_DAY` to `.env`** + +Append to `.env`: + +``` +# Rate limiting +MAX_REQUESTS_PER_DAY=5 +``` + +- [ ] **Step 2: Add `MAX_REQUESTS_PER_DAY` to `.env.example`** + +Append to `.env.example`: + +``` +# Rate limiting +MAX_REQUESTS_PER_DAY=5 +``` + +- [ ] **Step 3: Restart bot and verify** + +```bash +npx pm2 restart dienst-bot && npx pm2 save +npx pm2 logs dienst-bot --lines 5 --nostream +``` + +Expected: bot starts without errors, logs show listening on port 3002. + +- [ ] **Step 4: Commit and push** + +```bash +git add .env.example +git commit -m "feat: add rate limiting config option" +git push +``` + +--- + +### Task 4: Update README + +**Files:** +- Modify: `README.md` + +- [ ] **Step 1: Add rate limiting section to README.md** + +Add after the "Foutafhandeling" section: + +```markdown +## 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). +``` + +- [ ] **Step 2: Commit and push** + +```bash +git add README.md +git commit -m "docs: add spam protection section to README" +git push +```