|
| 1 | +<p align="center"> |
| 2 | + <img src="docs/logo.png" width="200" alt="DashCord Logo"> |
| 3 | +</p> |
| 4 | + |
| 5 | +# DashCord |
| 6 | + |
| 7 | +A highly flexible, configuration-driven Discord bot that translates chat commands, file uploads, and interactive UI panels (buttons) into HTTP webhook requests. |
| 8 | + |
| 9 | +Originally built for **n8n**, this bot works flawlessly with **Make (Integromat), Zapier, Node-RED**, or any custom API. |
| 10 | + |
| 11 | +Instead of hardcoding new Discord commands every time you want to automate something, you simply define them in a `routes.json` file. The bot acts as a universal headless bridge between Discord and your automation platform. |
| 12 | + |
| 13 | +| 🎛️ Interactive UI Panels | 📁 Advanced File Handling (TTS) | |
| 14 | +| :--- | :--- | |
| 15 | +|  |  | |
| 16 | +| **📊 System Automation Logs** | **🏃 Manual Chat Commands** | |
| 17 | +|  |  | |
| 18 | + |
| 19 | +## ✨ Features |
| 20 | + |
| 21 | +- **⚡ Dynamic Commands:** Add new slash-free commands (e.g., `!weather`, `!deploy`) just by editing a JSON file. |
| 22 | +- **🎛️ Sticky Dashboard Panels:** Generate persistent UI button panels in specific channels. The bot can automatically "persist" these panels, moving them to the bottom of the chat so they never get buried. Users can click buttons to trigger workflows without typing. |
| 23 | +- **📁 Intelligent File Fan-out:** Forward files directly to your webhooks. Can auto-parse JSON attachments, convert to Base64, and dynamically fan-out requests (upload 5 files, it triggers 5 separate webhook calls). |
| 24 | +- **🎭 Dynamic Body Templating:** Inject Discord metadata (like `{{discord.user_display}}` or `{{discord.channel_id}}`) directly into the JSON payload sent to your webhook, molding the data to fit your API perfectly. |
| 25 | +- **🔒 Security Built-In:** Restrict specific commands to specific Discord channels or user IDs. Secures outbound requests with a custom `X-DashCord-Token` header. |
| 26 | +- **💬 Native Discord Replies:** Your webhook can respond with JSON containing plain text or rich Discord Embeds, and the bot will cleanly post it back to the channel. |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## 🚀 Quick Start (Docker) |
| 31 | + |
| 32 | +1. Clone the repository: |
| 33 | +```bash |
| 34 | +git clone https://github.com/yourusername/DashCord.git |
| 35 | +cd DashCord |
| 36 | +``` |
| 37 | + |
| 38 | +2. Setup Configuration: |
| 39 | +```bash |
| 40 | +cp .env.example .env |
| 41 | +cp routes.json.example routes.json |
| 42 | +``` |
| 43 | + |
| 44 | +3. Open `.env` and add your **Discord Bot Token**. |
| 45 | + |
| 46 | +4. Configure your commands and endpoints in `routes.json`. |
| 47 | + |
| 48 | +5. Run it (using the Docker Compose wrapper): |
| 49 | +```bash |
| 50 | +chmod +x start.sh |
| 51 | +./start.sh |
| 52 | +``` |
| 53 | +*(To view live logs, simply run `./logs.sh`)* |
| 54 | + |
| 55 | +> **⚠️ CRITICAL SETUP STEP:** |
| 56 | +> Because this bot reads chat commands (`!weather`), you **must** enable the **Message Content Intent**. |
| 57 | +> Go to the [Discord Developer Portal](https://discord.com/developers/applications) -> Your Bot -> **Bot** tab -> Scroll down to **Privileged Gateway Intents** -> Turn ON **Message Content Intent**. |
| 58 | +
|
| 59 | +--- |
| 60 | + |
| 61 | +## ⚙️ Configuration File (`routes.json`) |
| 62 | + |
| 63 | +All routing logic is driven by `routes.json`. It has two main sections: `commands` and `panels`. |
| 64 | + |
| 65 | +### 1. Defining a Command |
| 66 | + |
| 67 | +Commands map a typed Discord message to a webhook URL. |
| 68 | + |
| 69 | +```json |
| 70 | +"commands": { |
| 71 | + "ping": { |
| 72 | + "endpoint": "https://your-automation-tool.com/webhook/ping", |
| 73 | + "method": "POST", |
| 74 | + "allowed_users": ["1234567890"], |
| 75 | + "allowed_channels":[] |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | +*Typing `!ping test` will send a POST request containing the arguments to that webhook. Because `allowed_users` has an ID, only that Discord user can trigger it.* |
| 80 | + |
| 81 | +### 2. Defining File Uploads |
| 82 | + |
| 83 | +You can allow commands to accept attachments, or even fire automatically when a specific filetype is uploaded without a command at all. |
| 84 | + |
| 85 | +```json |
| 86 | +"upload": { |
| 87 | + "endpoint": "https://your-webhook...", |
| 88 | + "method": "POST", |
| 89 | + "accept_attachments": true, |
| 90 | + "allow_without_command": true, |
| 91 | + "attachment_rules": { |
| 92 | + "extensions":[".json", ".csv"], |
| 93 | + "max_bytes": 2500000, |
| 94 | + "require_json": false |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +### 3. Designing Interactive UI Panels |
| 100 | + |
| 101 | +Panels create persistent messages with buttons. You can bind specific commands and background arguments to each button. |
| 102 | + |
| 103 | +```json |
| 104 | +"panels": { |
| 105 | + "Server_Controls": { |
| 106 | + "channels":["1029384756"], |
| 107 | + "buttons":[ |
| 108 | + { |
| 109 | + "label": "Restart Server", |
| 110 | + "command": "ping", |
| 111 | + "args": ["restart"], |
| 112 | + "style": "danger" |
| 113 | + }, |
| 114 | + { |
| 115 | + "label": "Check Status", |
| 116 | + "command": "ping", |
| 117 | + "args": ["status"], |
| 118 | + "style": "primary" |
| 119 | + } |
| 120 | + ] |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | +**Button Styles Available:** |
| 125 | +| Style Name | Discord Color | Best Used For | |
| 126 | +| :--- | :--- | :--- | |
| 127 | +| `primary` | Blurple (Blue) | Main actions | |
| 128 | +| `secondary`| Grey | Neutral / Informational | |
| 129 | +| `success` | Green | Confirmations / Starts | |
| 130 | +| `danger` | Red | Restarts / Stops / Deletes | |
| 131 | + |
| 132 | +*Note: Clicking the "Restart Server" button above executes the `ping` command with the argument `restart` behind the scenes, exactly as if the user typed `!ping restart`.* |
| 133 | + |
| 134 | +### 4. Dynamic Body Templating (Optional) |
| 135 | + |
| 136 | +If you need a specific payload structure rather than the default, you can define a `body_template` in your command configuration. DashCord will automatically fill in the `{{placeholders}}`: |
| 137 | + |
| 138 | +```json |
| 139 | +"commands": { |
| 140 | + "alert": { |
| 141 | + "endpoint": "https://your-webhook...", |
| 142 | + "method": "POST", |
| 143 | + "body_template": { |
| 144 | + "priority": "high", |
| 145 | + "triggered_by": "{{discord.user_display}}", |
| 146 | + "source_channel": "{{discord.channel_name}}", |
| 147 | + "original_text": "{{raw}}", |
| 148 | + "file_data": "{{attachment_b64}}" |
| 149 | + } |
| 150 | + } |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +--- |
| 155 | + |
| 156 | +## 📦 What your Webhook Receives (Payload format) |
| 157 | + |
| 158 | +Whenever a command or button is triggered (and no custom template is used), your Webhook will receive a JSON POST payload like this: |
| 159 | + |
| 160 | +```json |
| 161 | +{ |
| 162 | + "source": "discord", |
| 163 | + "event_type": "command", |
| 164 | + "command": "ping", |
| 165 | + "args": ["restart", "now"], |
| 166 | + "raw": "!ping restart now", |
| 167 | + "timestamp": "2026-02-25T12:00:00-05:00", |
| 168 | + "discord": { |
| 169 | + "guild_id": "123456...", |
| 170 | + "channel_id": "123456...", |
| 171 | + "user_id": "123456...", |
| 172 | + "user_display": "CoolUser" |
| 173 | + }, |
| 174 | + "attachment_b64": "..." |
| 175 | +} |
| 176 | +``` |
| 177 | + |
| 178 | +> **🔑 Authentication Header** |
| 179 | +> The bot sends the `DASHCORD_SHARED_SECRET` (from your `.env` file) as a custom header: |
| 180 | +> `X-DashCord-Token: your_secret_here` |
| 181 | +> *Ensure your webhook validates this header so nobody else can trigger your endpoints!* |
| 182 | +> |
| 183 | +> **💡 n8n Tip:** Most automation platforms (like Node.js & n8n) normalize HTTP headers to lowercase. You should look for `x-dashcord-token` in your expressions (e.g., `{{ $json.headers["x-dashcord-token"] }}`). |
| 184 | +
|
| 185 | +--- |
| 186 | + |
| 187 | +## 💬 Responding to Discord |
| 188 | + |
| 189 | +Your webhook should respond with a **200 OK** status. To make the bot reply natively in Discord, return JSON from your webhook. |
| 190 | + |
| 191 | +**Simple Text Reply:** |
| 192 | +```json |
| 193 | +{ |
| 194 | + "reply": { |
| 195 | + "content": "✅ Server restart initiated!" |
| 196 | + } |
| 197 | +} |
| 198 | +``` |
| 199 | + |
| 200 | +**Rich Embed Reply:** |
| 201 | +DashCord fully supports Discord embeds. Just pass an array of embed objects: |
| 202 | +```json |
| 203 | +{ |
| 204 | + "reply": { |
| 205 | + "content": "Server Status Check:", |
| 206 | + "embeds":[ |
| 207 | + { |
| 208 | + "title": "CPU Usage", |
| 209 | + "description": "Currently running at 45% capacity.", |
| 210 | + "color": 65280 |
| 211 | + } |
| 212 | + ] |
| 213 | + } |
| 214 | +} |
| 215 | +``` |
| 216 | + |
| 217 | +*(If you do not want the bot to reply at all, return `{"reply": {"suppress": true}}` or just an empty 200 OK).* |
| 218 | + |
| 219 | +--- |
| 220 | + |
| 221 | +### 🔧 Pro Configuration (.env) |
| 222 | + |
| 223 | +DashCord is highly customizable. You can fine-tune exactly how the bot, your webhooks, and your interactive panels behave by modifying your `.env` file. |
| 224 | + |
| 225 | +#### 🤖 General Bot Settings |
| 226 | +- `DISCORD_TOKEN`: **(Required)** Your Discord Bot Token. |
| 227 | +- `COMMAND_PREFIX`: The prefix used for typed commands in chat (Default: `!`). |
| 228 | +- `TIMEZONE`: The timezone used for panel timestamps and payload metadata (Default: `America/New_York`). |
| 229 | +- `DISPLAY_UNKNOWN_COMMAND_ERROR`: If a user mistypes a command (e.g., `!wether`), the bot will reply with a helpful list of commands they actually have permission to use (Default: `true`). |
| 230 | +- `DASHCORD_DEBUG`: Enables verbose internal debug logging in the console (Default: `false`). |
| 231 | +- `ROUTES_PATH`: The file path to your routing configuration (Default: `routes.json` in the bot's root directory). |
| 232 | + |
| 233 | +#### 🌐 Webhook & API Settings |
| 234 | +- `DASHCORD_SHARED_SECRET`: A secret string sent as the `X-DashCord-Token` HTTP header to secure your webhooks from unauthorized requests. |
| 235 | +- `HTTP_TIMEOUT_SECONDS`: How long the bot waits for your webhook to respond before throwing a timeout error (Default: `20`). |
| 236 | +- `VERIFY_TLS`: Whether to verify SSL/TLS certificates when hitting your webhook URLs. Set to `false` if you are using self-signed certs on a local network (Default: `true`). |
| 237 | +- `DEBUG_WEBHOOK`: Prints beautifully formatted, raw webhook request and response payloads directly to the console for API troubleshooting (Default: `false`). |
| 238 | + |
| 239 | +#### 🎛️ Panel Interaction & Spawning |
| 240 | +- `PANEL_SPAWN_NEW_ON_CLICK`: Post a fresh copy of the panel at the bottom of the chat automatically after a user clicks a button (Default: `true`). |
| 241 | +- `PANEL_STATUS_LINE`: When a button is clicked, update the old panel's text to show an audit log of who clicked it (e.g., `Last: !ping restart • CoolUser • 4:05 PM`) (Default: `true`). |
| 242 | +- `PANEL_ARCHIVE_DISABLE_BUTTONS`: When a button is clicked, permanently grey-out/disable the buttons on that specific message so users must use the newest panel at the bottom (Default: `true`). |
| 243 | +- `PANEL_REPOST_ON_STARTUP`: When the bot boots up, it will scan channels to find your panels and "re-attach" itself to them so buttons keep working (Default: `true`). |
| 244 | +- `PANEL_FORCE_NEW_ON_STARTUP`: Instead of editing the existing panel in-place on boot, the bot will delete the old one and post a brand new panel at the bottom of the chat (Default: `true`). |
| 245 | + |
| 246 | +#### 🧹 Panel Persistence & Cleanup |
| 247 | +*Persistence is the bot's ability to keep panels at the bottom of the chat so they don't get lost when users are talking.* |
| 248 | +- `PANEL_PERSIST_DEFAULT`: The global default for whether panels should automatically "jump" to the bottom of the chat (Default: `false`). *(Note: You can override this per-panel in `routes.json`)*. |
| 249 | +- `PANEL_PERSIST_INTERVAL_SECONDS`: How often the background loop checks if chat activity has buried your panels (Default: `45`). |
| 250 | +- `PANEL_PERSIST_CLEANUP_OLD_ACTIVE`: When the bot moves a panel to the bottom of the chat, it deletes the old one to prevent duplicates (Default: `true`). |
| 251 | +- `PANEL_DELETE_OLD_PANELS`: Allows the bot to mass-delete old, disconnected panels if things get messy (Default: `true`). |
| 252 | +- `PANEL_SCAN_LIMIT`: How many messages up the chat history the bot will scan when looking for old panels to clean up (Default: `50`). |
0 commit comments