A TypeScript-based WhatsApp bot coordinator designed for the DK24 and ECB developer networks. It integrates with the Groq AI API (Llama-3.3-70B), Neon PostgreSQL for session persistence, a prompt-injection firewall, and the dk24.org public API for calendar, community, and project data.
- Multiple Bot Profiles:
- Bot 0 (Generic): Default assistant for chats/groups with no specialised bot assigned — neutral, general-purpose help.
- Bot 1 (ECB): ECB-specific bot answering questions about hardware, microcontrollers, and embedded systems.
- Bot 2 (DKB): Community directory coordinator for mentor registrations, calendar events, and intake queries.
- Bot 3 (PARAG): Technical assistant for general coding and hackathons.
- Groq AI Integration: Multi-turn chat sessions utilizing
llama-3.3-70b-versatilewith restricted prompts focusing on technical topics. - PostgreSQL Session Store: Session state is saved in Neon PostgreSQL. Supports optional JWT encryption at rest to protect authorization tokens.
- Sequential ID Administration:
- Plural and singular commands to list, add, edit, disable, or enable allowed groups and private chats.
- Administration requires sequential primary IDs rather than raw JIDs (e.g.
!rmgroup -id 4or!editgroup -id 2 -b 2). - EPHEMERAL-safe storage: Allowlist records are saved entirely in PostgreSQL, avoiding issues with temporary local files on platforms like Render.
- Admin Confirmation Prompts: Deletions, edits, and bot re-assignments require a
!YESconfirmation from the specific administrator who initiated the action. - DK24 Data Sync: Fetches events, communities, and projects from the dk24.org public API (
/api/v1/calendar,/api/v1/communities,/api/v1/projects) with 24h Neon-backed caching and in-flight de-duplication. - Security Protections:
- RBAC Firewall: Standard JIDs and
@lididentifiers are resolved and checked againstADMIN_JIDSvalues. - LID Resolver: Resolves WhatsApp Localized Identifiers (
@lid) to phone JIDs (@s.whatsapp.net) using metadata caches and socket update events. - Rate Limits & Muting: Controls message frequency per user/group and uses burst limits to prevent spam.
- RBAC Firewall: Standard JIDs and
- Runtime: Node.js (v20+) with TypeScript
- WhatsApp Client:
@whiskeysockets/baileys(v7.0.0-rc13) - Database client: Neon PostgreSQL (using pg connection pooling)
- AI Completion: Groq API SDK
- DK24 data source: dk24.org public REST API (native
fetch)
- Node.js (v20.x or higher)
- PostgreSQL database instance (such as Neon.tech)
- Groq Cloud API Key
- A WhatsApp account to link via QR code
Copy .env.example to .env and set the following parameters:
cp .env.example .env| Variable | Required | Description | Example |
|---|---|---|---|
GROQ_API_KEY |
Yes | Groq Cloud API Key | gsk_xxxxxx... |
GROQ_MODEL |
No | Llama model to invoke | llama-3.3-70b-versatile |
ADMIN_JIDS |
Yes | Comma-separated administrator JIDs | 919902849280@s.whatsapp.net |
ALLOWED_GROUPS |
No | Initial allowed groups list | 1203630234567@g.us 1 |
ALLOWED_CHATS |
No | Initial allowed private chats list | 919902849280@s.whatsapp.net 2 |
DATABASE_URL |
Yes | Connection string for Neon PostgreSQL | postgresql://user:pass@host/db?sslmode=require |
AUTH_STATE_JWT_SECRET |
No | Encryption secret for DB auth state | secure_secret_key |
ALLOW_FROM_ME_MESSAGES |
No | Process commands sent from self | true |
PORT |
No | Port for health check endpoint | 3000 |
npm installRuns the coordinator locally with reloading enabled:
npm run devScan the printed QR code using WhatsApp on your phone under Linked Devices.
npm run build
npm startgraph TD
A[WhatsApp Message] -->|Baileys Socket| B(JID & LID Resolution Layer)
B -->|Resolves @lid to phone JID| C{Admin Command Check}
C -->|Yes| D[Admin Action Router]
C -->|No| E{Allowlist Check}
E -->|Muted/Disabled| F[Ignore Message]
E -->|Active/Enabled| G{Rate Limiter}
G -->|Muted/Burst Triggered| H[Mute Bot response]
G -->|Allowed| I[Bot Prompt Selector]
I -->|Bot 2 DKB| J[DK24 API Sync / Mentor DB]
I -->|Bot 0/1/3| K[Groq AI Completion Engine]
K -->|Replies via typing state| L[WhatsApp Send Socket]
Database tables are generated automatically on startup:
wa_allowed_groups (Allowed groups registry)
├── id (SERIAL, Primary Key)
├── jid (TEXT, Unique, Not Null)
├── bot_number (INTEGER, default 0)
├── enabled (BOOLEAN, default TRUE)
└── added_at (TIMESTAMPTZ)
wa_allowed_chats (Allowed private chats registry)
├── id (SERIAL, Primary Key)
├── jid (TEXT, Unique, Not Null)
├── bot_number (INTEGER, default 0)
├── enabled (BOOLEAN, default TRUE)
└── added_at (TIMESTAMPTZ)
dk24_mentors (Mentor directory)
├── id (SERIAL, Primary Key)
├── name (TEXT, Not Null)
├── organization (TEXT)
├── expertise (TEXT)
├── description (TEXT)
├── linkedin/instagram/github/email/phone (TEXT)
└── created_at (TIMESTAMPTZ)
dk24_action_logs (Action logs registry)
├── id (SERIAL, Primary Key)
├── actor_jid (TEXT)
├── action_type (TEXT)
├── target_id (TEXT)
├── target_name (TEXT)
├── details (TEXT)
└── logged_at (TIMESTAMPTZ)
These commands are restricted to JIDs listed in ADMIN_JIDS. All commands must be prefixed with !.
!addgroup <group_jid> [bot_number]- Adds a group and assigns the designated bot profile. Starts as active.
!rmgroup -id <id_number>(or!removegroup)- Removes a group from the allowlist using its database ID. Prompts with a
!YESconfirmation.
- Removes a group from the allowlist using its database ID. Prompts with a
!listgroups(or!listgroup)- Lists registered groups, database IDs, bot assignments, and enabled/disabled states.
!addchat <chat_jid> [bot_number]- Adds a private chat to the allowlist.
!rmchat -id <id_number>(or!removechat)- Removes a private chat from the allowlist by ID. Prompts with a
!YESconfirmation.
- Removes a private chat from the allowlist by ID. Prompts with a
!listchats(or!listchat)- Lists registered private chats, database IDs, bot assignments, and enabled/disabled states.
!editgroup -id <id_number> -b <bot_number>/!editchat -id <id_number> -b <bot_number>- Changes the bot assigned to a group or chat. Alerts and skips if unchanged. Otherwise, prompts for
!YESconfirmation.
- Changes the bot assigned to a group or chat. Alerts and skips if unchanged. Otherwise, prompts for
!disablegroup -id <id_number>/!disablechat -id <id_number>- Sets the enabled status to
false. The bot will ignore standard messages in this channel immediately without requesting confirmation.
- Sets the enabled status to
!enablegroup -id <id_number>/!enablechat -id <id_number>- Sets the enabled status to
true, unmuting the bot.
- Sets the enabled status to
!neonping- Tests connections and database latency.
!neonconnect- Shuts down the process with exit code 1 to let the environment manager (e.g. Render) restart the service.
Manage mentor registrations and profiles in the DK24 Directory.
!mentors [page]- Displays a paginated list of mentors (10 records per page).
!mentor -id <id_number>- Searches and displays detail cards for a mentor by ID.
!mentor -f <query> [page]- Filters mentors by name, expertise area, or organization.
!addmentor -n <name> -o <org> [-d <desc>] [-ex <expert>] [-l <linkedin>] ...- Adds a new mentor to the directory.
!editmentor -id <id_number> -<flag> <value>- Modifies a field for a mentor record (supported flags:
-n,-o,-d,-ex,-l,-i,-g,-e,-p).
- Modifies a field for a mentor record (supported flags:
!delmentor -id <id_number>- Removes a mentor record by ID. Prompts with a
!YESconfirmation.
- Removes a mentor record by ID. Prompts with a
Events, communities, and projects are pulled from the dk24.org public REST API
(/api/v1/calendar, /api/v1/communities, /api/v1/projects) using native
fetch — no browser/scraper involved. The base URL is overridable via
DK24_API_BASE_URL.
- In-flight de-duplication: Concurrent requests for the same resource reuse a single in-flight promise to avoid redundant API hits.
- Caching: Records are cached in Neon; a stale (>24h) cache is served instantly while a background refresh runs. A foreground fetch happens only when the cache table is empty.
Runs on a plain VPS (Docker or a Node process manager).
- Pull the latest code on the server:
git pull. - Ensure the environment is configured (a
.envfile or exported vars). At minimum:GROQ_API_KEY,ADMIN_JIDS,DATABASE_URL(Neon),REDIS_URL, andAUTH_STATE_KEY— the bot fails to start without an auth-state encryption key unlessALLOW_UNENCRYPTED_AUTH_STATE=true. See.env.examplefor the full list. - Build and start:
- Docker:
docker build -t whatsapp-bot . && docker run --env-file .env whatsapp-bot - Direct:
npm install && npm run build && npm start(keep it alive with pm2/systemd).
- Docker:
- Schema and the one-time bot-number migration apply automatically on boot via
ensureSchema/migrateParagToBot3.
- Firewall Filtering: Prompts are monitored to prevent roleplay bypasses or jailbreaks.
- Secrets Protection: Always use environment parameters to store connection strings and credentials.
- Database Audit Logs: State changes to allowlists and mentor records are logged with the actor's JID, action type, target ID, and modifications.