# 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 ```