NestJSTypeScriptRedisBullMQWebSocketsPuppeteerDocker

WhatsApp Bridge Gateway

A production-ready app built with NestJS that acts as an intelligent bridge to WhatsApp via whatsapp-web.js. It exposes simple HTTP endpoints for triggering WhatsApp messages, while leveraging BullMQ and Redis for reliable message queuing and rate-limiting. A built-in WebSocket gateway provides real-time event publishing (e.g., QR Code generation, authentication status, and message receipts), providing a robust backbone for building enterprise-grade WhatsApp integrations.

NestJS
NestJS
TypeScript
TypeScript
Redis
Redis
Puppeteer
Puppeteer

๐Ÿ“Œ Elevator Pitch

A production-ready app built with NestJS that acts as an intelligent bridge to WhatsApp via whatsapp-web.js. It exposes simple HTTP endpoints for triggering WhatsApp messages, while leveraging BullMQ and Redis for reliable message queuing and rate-limiting. A built-in WebSocket gateway provides real-time event publishing (e.g., QR Code generation, authentication status, and message receipts), providing a robust backbone for building enterprise-grade WhatsApp integrations.


๐Ÿ›  Tech Stack

  • Backend Framework: NestJS (Node.js) + TypeScript
  • Message Broker: BullMQ over Redis
  • Real-time Communication: Socket.IO
  • WhatsApp Core: whatsapp-web.js (Puppeteer-driven)
  • API Documentation: Swagger / OpenAPI
  • Logging & Monitoring: Winston + @nestjs/terminus (Health Checks)
  • Containerization: Docker & Docker Compose

๐Ÿ— System Architecture

The application handles incoming REST requests to queue outgoing messages, safely processing them out-of-band via a worker to respect WhatsApp's native rate limits. Meanwhile, clients can subscribe to the WebSocket gateway to receive asynchronous updates.

graph TD subgraph Client Application Frontend["Client / Mobile / Web"] end subgraph Service API HTTP["REST Controllers"] WS["WebSocket Gateway"] Health["Health Checks"] end subgraph Background Processing Queue["BullMQ Message Queue"] Processor["Queue Worker"] end subgraph Infrastructure Redis[("Redis")] Puppeteer["Chromium / WhatsApp Web"] end Frontend -- REST POST --> HTTP Frontend -- Ws Connect --> WS HTTP -- Enqueues Job --> Queue Queue --- Redis Processor -- Polls Job --> Queue Processor -- Send Message --> Puppeteer Puppeteer -- State Updates --> WS

Key Data Flow Summary:

  1. Init: Client calls /api/whatsapp/initialize โ€” the server provisions a Puppeteer instance, and forwards the QR code payload via WebSocket (whatsapp.qr).
  2. Messaging: Client submits a message payload to /api/whatsapp/send-message.
  3. Queueing: Message is staged into Redis via BullMQ (whatsapp-message-queue).
  4. Execution: The MessageProcessor fetches the job subject to a rate limit constraint (1 message / 5s) and pushes it via Puppeteer to WhatsApp Servers. Real-time updates confirm delivery.

โš™๏ธ Environment Variables

Copy .env.example to .env in the root directory before running the app.

VariableDescriptionExample
`MQ_REDIS_HOST`Hostname of the Redis server.`redis` (in Docker) or `localhost`
`MQ_REDIS_PORT`Port of the Redis server.`6379`
`SHOW_QR_ON_TERMINAL`Render QR code logic directly in console?`true` or `false`
_Note: Never expose actual cryptographic secrets or production tokens in your version control._

๐Ÿš€ Prerequisites & Local Setup

1) System Requirements

  • Node.js: v22+
  • Package Manager: pnpm (run npm install -g pnpm)
  • Redis: Up and running locally (or via Docker Compose)

2) Installation

# Install all dependencies
pnpm install

# Setup environment variables
cp .env.example .env

# Review and edit your .env values if running on local OS (expecting Redis on localhost)

3) Getting Started with Docker

The fastest way to boot the full suite (Redis + API) is via Docker Compose:

# Run in detached mode
docker-compose up -d

# To observe the application logs (helpful for capturing the QR Code!)
docker-compose logs -f api

If you wish to run the app on the host machine but retain the Dockerized Redis DB:

# Start just Redis
docker-compose up -d redis

# Boot the NestJS DEV server
pnpm run start:dev

๐Ÿ“ก API Documentation

REST API

By default, the global API prefix is set to /api. The Swagger documentation UI is available if swagger.yaml is bootstrapped.

  • Swagger Base URL: http://localhost:3000/docs
**Core Endpoints:**
  • GET /api/health
Runs health checks across Memory heaps, HTTP availability, and Redis connectivity.
  • POST /api/whatsapp/initialize
Spawns the WhatsApp engine for a defined connection context.
  • POST /api/whatsapp/send-message
Accepts JSON body: `{ "phone": "1234567890", "message": "Hello World" }`

WebSocket Gateway

Connect to http://localhost:3000 via your Socket.io client.

  • Handshake/Query parameter setup: Supply ?user_id=YOUR_ID when initializing the socket.
  • Subscribable Events:
- `qr`: Triggers when waiting on authentication. - `ready`: Triggers when the active tab logs in. - `disconnected`: Lost connection to WhatsApp. - `message`: Triggers upon message processing events.

๐Ÿงช Testing Strategy

The project leverages Jest for both unit and End-to-End coverage.

# Run the entire unit test suite
pnpm run test

# Run tests in watch mode
pnpm run test:watch

# Generate an execution coverage report
pnpm run test:cov

# Run End-to-End integration tests
pnpm run test:e2e

E2E testing is defined in the test/ directory, while unit logic acts primarily on .spec.ts files adjacent to module business layers.


๐Ÿ›ฅ Deployment Guide & Troubleshooting

Building for Production

The application features a structured Dockerfile utilizing a minimal node:22-slim image to reduce footprint. It has a multistage build:

  1. builder stage: Compiles NestJS typescript to /dist.
  2. production stage: Copies output, installs Chromium binary, skips node internal Puppeteer download, and locks down execution privileges via appuser.
**Important: Puppeteer / Chromium Compatibility** Puppeteer can be challenging in minimal Linux containers. This app installs `chromium` and a slew of associated binary dependencies (e.g., `libasound2`, `libatk-bridge2.0-0`, `libnss3`, `libx11-xcb1`) utilizing `apt-get` directly within the image.

Linux / Container Troubleshooting:

  • Crash on Boot: If Puppeteer fails to run browser.launch, verify that your container operates without an aggressive AppArmor profile or simply bind Chromium to run with --no-sandbox params in your whatsapp.client.ts initialization.
  • Dangling instances: In some host environments, orphaned chromium processes linger. Ensure you have --init enabled in Docker (e.g., init: true in your compose configuration) pointing to a zombie reaper like dumb-init, or simply use docker-compose down gracefully.
  • Cache Volumes: Note that WhatsApp persistent accounts are mapped into the whatsapp_sessions and whatsapp_cache volumes. If QR scanning requires a loop reset, run: docker volume rm whatsapp-integration_whatsapp_sessions.