Skip to content

Repository files navigation

msk_multi_bot_banner

Discord Multi-Bot

A modular Discord bot system built with discord.js v14, running three independent bots in a single Node.js process.

Version License: AGPL-3.0 Node.js Discord.js Documentation

📄 Readme (EN) · Readme (DE)


Overview

Bot Purpose
Commands Bot Server management slash commands: rules, roles, information, orders, support, admin tools, utility
Events Bot Guild event logging, context menus, automated message handling
Minigames Bot 12 interactive minigames with a shared points & reward system

All three bots run in parallel. If one crashes, it automatically restarts after 10 seconds without affecting the others.


Requirements

  • Node.js >= 22 (LTS — built-in fetch and AbortSignal.timeout() required for the Trivia API)
  • npm
  • A Discord application with three bot tokens (one per bot)
  • A Discord server (guild) with the required roles and channels configured

Installation

# 1. Clone the repository
git clone https://github.com/MSK-Scripts/discord_multibot.git
cd discord_multibot

# 2. Install dependencies
npm install

# 3. Configure environment variables
cp .env.example .env
# → Fill in your tokens, IDs and database credentials in .env

# 4. Start all bots
node main.js

Deployment (Linux / Debian)

systemd Service

A ready-to-use systemd unit file is included at multibot.service (user discord, working directory /opt/discord_multibot).

1. Adjust the paths and user in the file if necessary.

2. Copy the service file to systemd:

sudo cp multibot.service /etc/systemd/system/

3. Reload systemd and enable the service:

sudo systemctl daemon-reload
sudo systemctl enable --now multibot

4. Check the status:

sudo systemctl status multibot

Useful commands:

# View live logs
journalctl -u multibot -f

# Restart after update
sudo systemctl restart multibot

# Stop the bots
sudo systemctl stop multibot

Note: The service reads the .env file via EnvironmentFile=. Make sure the file exists at the configured path and is readable by the service user.

Automated deployment

.github/workflows/deploy.yml deploys every push to main that touches actual code: it runs the CI gate first, then connects over SSH, resets /opt/discord_multibot onto origin/main, runs npm ci --omit=dev, restarts the service and fails the run if the bot is not alive afterwards.

Four repository secrets are required:

Secret Meaning
DEPLOY_HOST Server hostname or IP
DEPLOY_USER SSH user (needs sudo systemctl and write access to /opt/discord_multibot)
DEPLOY_SSH_KEY Private SSH key for that user
DEPLOY_PORT SSH port

Two things stay outside the pipeline on purpose. The production .env is never transferred through git, the deploy aborts if it is missing. And multibot.service is not installed automatically, a changed unit has to be copied over and reloaded by hand.

The deploy uses git clean -df without -x, so everything in .gitignore survives: .env, data/ (points and database backups), assets/, the log files and the untracked bots/commands/commands/orders.js.


Configuration

All configuration is done via a .env file in the root directory. Copy .env.example and fill in the values.

Required

COMMANDS_BOT_TOKEN=your_commands_bot_token
EVENTS_BOT_TOKEN=your_events_bot_token
MINIGAMES_BOT_TOKEN=your_minigames_bot_token
GUILD_ID=your_guild_id

Optional (fall back to hardcoded MSK Scripts defaults)

# Logging & channels
LOG_CHANNEL_ID=
FEEDBACK_CHANNEL_ID=
MEMBER_COUNT_CHANNEL_ID=

# Role IDs (FOUNDER / MANAGER / DEVELOPER / TEAM gate the staff commands)
MEMBER_ROLE_ID=
FOUNDER_ROLE_ID=
MANAGER_ROLE_ID=
DEVELOPER_ROLE_ID=
TEAM_ROLE_ID=
GIVEAWAY_NOTIFY_ROLE_ID=
GARAGE_ROLE_ID=
HANDCUFFS_ROLE_ID=
STORAGE_ROLE_ID=
VEHICLEKEYS_ROLE_ID=

# Database (for /backup_database)
DB_HOST=localhost
DB_USER=
DB_PASS=
DB_NAME=es_extended

Features

Commands Bot

Command Description Role-restricted
/information Posts a branded server information embed ✅ Manager / Founder
/rules Posts the server rules with Verification & Giveaway Notify buttons ✅ Manager / Founder
/roles Posts script update notification role buttons ✅ Manager / Founder
/script_guides Links to documentation for a chosen script ✅ Support+
/donation Displays donation options with payment links ✅ Manager / Founder
/order_terms Sends the terms of service PDF with Accept / Reject buttons ✅ Developer / Manager / Founder
/order_price Shows an order price with Accept / Reject buttons ✅ Developer / Manager / Founder
/send_message Sends a custom message to any channel via modal ✅ Manager / Founder
/send_embed Sends a fully customizable embed to any channel ✅ Manager / Founder
/backup_database Creates a MySQL database backup and uploads it to the log channel ✅ Founder
/ping Shows bot latency and API response time
/userinfo Shows info and minigame points for a user
/clear Bulk-deletes up to 100 messages ✅ Team
/random Picks a random number in a given range (for guess games) ✅ Team
/rg Guess the currently active secret number
/flachwitz Posts a random flat joke from the local collection
/add_flachwitz Adds a new joke to the collection ✅ Team

Persistent role-toggle buttons (survive bot restarts):

  • ✅ Verification — assigns the Member role
  • 🎁 Giveaway Notify — toggles the Giveaway notification role
  • ⏰ Garage / Handcuffs / Storage / Vehicle Keys — toggles script update notification roles

Events Bot

Guild logging — All events are posted as colored embeds to the configured log channel:

Category Events logged
Members Join, Leave, Kick, Ban, Unban, Timeout set/removed
Roles Role Added (incl. added by), Role Removed (incl. removed by)
Username / Nickname Username changed, Nickname changed
Messages Edited, Deleted (incl. deleted by), Bulk delete (incl. deleted by)
Channels Created, Deleted, Updated (name, topic, slowmode, NSFW)
Roles Created, Deleted, Updated (name, color, permissions diff)
Voice Joined, Left, Moved, Server Muted/Unmuted, Server Deafened/Undeafened
Invites Created (with max uses & expiry), Deleted
  • Auto-reply — Automatically responds when non-team members mention "Musiker15"
  • Feedback embed — Messages posted in the feedback channel are auto-converted to branded embeds and the original is deleted
  • Context menus (right-click on messages):
    • 📝 Comment Feedback — Adds a moderator comment to a feedback embed and DMs the author
    • 💬 Answer a Message — Sends a reply to any message via modal
    • ✏️ Edit Message — Edits a bot message via modal
    • 🖼️ Edit Embed — Edits a bot embed (title, description, thumbnail, image, footer) via modal

Minigames Bot

All minigames are session-based (no global state) and award or deduct points on each outcome.

Command Description
/8ball Magic 8-Ball — asks a yes/no question
/dice Roll a die — d4 to d100, 1–10 dice
/flipcoin Flip a coin — Heads or Tails
/rps Rock Paper Scissors vs. the bot
/slots Slot machine with animated spin and 7 symbol tiers
/trivia Multiple-choice trivia (OpenTrivia DB + local fallback)
/hangman Classic Hangman with letter-modal input
/wordle Wordle — guess the 5-letter word in 6 tries
/tictactoe TicTacToe — Easy / Medium / Minimax Hard AI
/connect4 Connect Four — bot AI with win/block/center logic
/blackjack Blackjack — Hit, Stand, Double Down vs. the dealer
/points Shows your current point balance with a progress bar

Points & Rewards System

Points are stored persistently in data/points.json. Each game awards or deducts points depending on the outcome and difficulty. Reward milestones automatically assign Discord roles and notify the user.

Default reward thresholds:

Points Reward
500 🥉 Bronze Player
1,500 🥈 Silver Player
4,000 🥇 Gold Player
10,000 💎 Diamond Player

Point values per game are configurable in bots/minigames/points_config.json.


Testing

npm test

test/harness.js boots every bot module against a fake client, exactly the way main.js does but without logging in. It unions the intents, builds the shared command registry through all three attach() calls, serializes the exact payload that goes to Discord, and dispatches mock interactions through the real InteractionCreate listeners. It also round trips the points system and restores data/points.json afterwards, so it is safe to run on a machine that holds real data.

The last section makes one unauthenticated request to Discord: it logs in with an obviously invalid token and asserts that Discord rejects it. That proves the REST stack works end to end. Set SKIP_NETWORK_TESTS=1 to skip it offline.

What it cannot cover. An invalid token fails at REST authentication, so the gateway WebSocket is never opened and @discordjs/ws never runs. Anything that touches the gateway needs a real login with a real token. This is not a theoretical gap: an @discordjs/ws override once passed this harness 47 checks out of 47 and still crashed the bot on startup.

The harness runs in CI on every pull request.


Project Structure

discord_multibot/
├── main.js                          ← Starts all 3 bots, handles auto-restart
├── package.json
├── .env                             ← Not committed (see .gitignore)
├── .github/
│   ├── dependabot.yml               ← Weekly dependency update checks
│   └── workflows/
│       ├── ci.yml                   ← Syntax + JSON + audit check on every PR
│       ├── codeql.yml               ← Code scanning
│       ├── deploy.yml               ← SSH deploy + systemd restart on push to main
│       └── release.yml              ← GitHub release on v* tags
├── test/
│   └── harness.js                   ← Boot harness, run via npm test
├── core/
│   ├── config.js                    ← Environment config
│   ├── utils.js                     ← Shared helpers (makeEmbed, readJson, …)
│   └── pointsManager.js             ← Points read/write + reward notifications
├── data/
│   ├── points.json                  ← Persistent user points (auto-created)
│   └── backups/                     ← Database backup files (auto-created, auto-deleted)
├── assets/                          ← Static files, e.g. terms PDF
└── bots/
    ├── commands/
    │   ├── bot.js
    │   └── commands/
    │       ├── community.js          ← /information, /rules, /roles
    │       ├── admin.js              ← /backup_database, /send_message, /send_embed
    │       ├── support.js            ← /script_guides
    │       ├── orders.js             ← /donation, /order_terms, /order_price
    │       ├── utility.js            ← /ping, /userinfo, /clear
    │       └── minigames.js          ← /random, /rg, /flachwitz, /add_flachwitz
    ├── events/
    │   ├── bot.js
    │   └── handlers/
    │       ├── logging.js
    │       ├── messageHandler.js
    │       └── contextMenus.js
    └── minigames/
        ├── bot.js
        ├── points_config.json
        └── commands/
            ├── eightball.js
            ├── dice.js
            ├── flipcoin.js
            ├── rps.js
            ├── slots.js
            ├── trivia.js
            ├── hangman.js
            ├── wordle.js
            ├── tictactoe.js
            ├── connect4.js
            ├── blackjack.js
            └── points.js

Dependencies

Package Version
discord.js ^14.27.0
dotenv ^17.4.2

Dependency updates are monitored automatically via Dependabot (weekly, grouped).

No overrides, on purpose

npm outdated --all reports major updates for @discordjs/collection, @discordjs/ws and undici. They belong to the discord.js 15 line and are deliberately left alone. Both attempts to force them failed:

  • undici@8 kills the REST layer. @discordjs/rest puts Node's sensitiveHeaders symbol into the request headers and undici 8 rejects it (Key Symbol(sensitiveHeaders) in init is a symbol, which cannot be converted to a ByteString). No command registration, no interaction reply. npm test catches this one.
  • @discordjs/ws@2.0.4 passed every test and crashed the bot on startup in production. Note that discord.js 14.27.0 pins @discordjs/collection to exactly 1.5.3, without a caret.

Patch level updates inside the existing ranges are fine and need no override.


Links


© MSK Scripts – Musiker15

About

A modular Discord bot system built with Discord.js v14, running three independent bots in a single Node.js process.

Topics

Resources

Code of conduct

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages