A production-ready, feature-rich Discord bot with an optional web dashboard.
Built in Rust with Poise + Serenity and Axum.
- ๐ฎ Fun Commands โ Daily rewards, work economy, balance, coin flip, dice roll, 8-ball
- ๐ณ๏ธ Misc Commands โ Polls with reaction voting, reminders, random choice picker
- ๐จ Moderation โ Ban, kick, timeout, warn, warnings log, purge, slowmode, lock/unlock, unban
- ๐ซ Ticket System โ Create, close, add/remove members from support tickets
- ๐ ๏ธ Utility โ Ping, uptime, stats, help, user/server/channel/role info, avatar, embed builder, connection time
- ๐ Optional Dashboard โ Modern web control panel with sidebar navigation, server analytics, bot module toggles, and a browser-based setup wizard
- ๐๏ธ MongoDB Integration โ Persistent economy profiles and warning records (optional โ bot runs fine without a DB)
- ๐ก Structured Logging โ
tracing+tracing-subscriberwithRUST_LOGenv-var control - ๐ Graceful Shutdown โ Handles SIGINT/SIGTERM for clean process exit
- Rust โ install via rustup
- A Discord bot token from the Discord Developer Portal
- MongoDB (optional โ bot runs without a database)
-
Clone the repository
git clone https://github.com/TurboRx/Turbo-Gravity.git cd Turbo-Gravity -
Configure the bot
Run the bot once and open
http://127.0.0.1:8080/setupin your browser to configure everything through the setup wizard. -
Build and run
cargo run --release
The bot registers slash commands to the guild specified by guild_id (instant) or globally (up to 1 hour delay) based on command_scope.
[bot]
token = "" # Required: Discord bot token
client_id = "" # Discord application/client ID
guild_id = "" # Leave empty for global command registration
command_scope = "guild" # "guild" (instant) or "global"
presence_text = "Ready to serve"
presence_type = 0 # 0=Playing 1=Streaming 2=Listening 3=Watching 4=Competing
[database]
mongo_uri = "" # Optional: MongoDB URI; leave empty to run without DB
[dashboard]
enable_dashboard = true # Set to false to disable the web API entirely
port = 8080
session_secret = "" # Reserved for future OAuth2 session signing
client_secret = "" # Reserved for future Discord OAuth2 login
callback_url = "http://localhost:8080/auth/discord/callback"
admin_ids = [] # Reserved for future admin access controlEnvironment variables in a .env file are loaded automatically (via dotenvy) and can be used alongside config.toml.
main.rs
โโโ Arc<AppState> โ shared state (config + optional MongoDB pool)
โ
โโโ tokio::spawn โ dashboard::serve() โ optional Axum REST API (port 8080)
โ State<Arc<AppState>> โ same Arc injected into every route
โ
โโโ bot::start() โ Poise framework (blocks until shutdown)
ctx.data() โ SharedState accessible in every command
| Concern | Solution |
|---|---|
| Command framework | poise 0.6 with #[poise::command(slash_command)] |
| Shared state | Arc<AppState> โ passed as Poise Data type and Axum State |
| Dashboard toggle | enable_dashboard = true/false in config.toml |
| Dashboard API | axum 0.8 spawned via tokio::spawn before bot blocks |
| Database | mongodb 3 driver; bot operates without DB if URI is empty |
| Configuration | config.toml (TOML) loaded at startup; .env also supported |
| Async runtime | tokio with full features |
| Graceful shutdown | tokio::signal handles SIGINT + SIGTERM |
The optional web dashboard runs at http://localhost:8080 (or the configured port).
Dashboard โ Dark mode (default)

Mobile view (390px โ hamburger sidebar, responsive layout)
| Dark | Light |
|---|---|
![]() |
![]() |
Setup wizard (/setup โ browser-based config, no file editing required)

| Route | Description |
|---|---|
GET /dashboard |
Main control panel โ analytics, bot modules, quick actions |
GET /setup |
Browser-based setup wizard (pre-fills current config) |
POST /setup |
Saves wizard form to config.toml and shows the setup-complete page |
GET /selector |
Guild selector โ lists all servers the bot is in |
GET /health |
Liveness probe โ returns {"status":"ok","version":"..."} |
GET /api/stats |
Runtime stats (DB connected, bot configured, port) |
GET /api/config |
Public (non-secret) config values |
GET /styles.css |
Embedded stylesheet (dark/light/system theme support) |
The dashboard supports dark mode, light mode, and device-default (respects prefers-color-scheme). Use the โ๏ธ button in the top-right to toggle โ your preference is saved to localStorage.
# Build
docker build -t turbo-gravity .
# Run
docker run -d \
-p 8080:8080 \
-v $(pwd)/config.toml:/app/config.toml:ro \
--name turbo-gravity \
turbo-gravityMount your config.toml at /app/config.toml โ never bake secrets into the image.
- Create
src/bot/commands/<category>/mycommand.rs - Write the handler following the Poise pattern:
use crate::bot::{Context, Error}; /// Brief description shown in /help #[poise::command(slash_command, ephemeral)] pub async fn mycommand(ctx: Context<'_>) -> Result<(), Error> { ctx.say("Hello!").await?; Ok(()) }
- Add
mod mycommand;and includemycommand::mycommand()in thecommands()vec insrc/bot/commands/<category>/mod.rs
// ctx.data() returns &Arc<AppState>
let Some(db) = ctx.data().database() else {
ctx.say("No database configured.").await?;
return Ok(());
};cargo check # fast type-check
cargo clippy -- -D warnings # lints (CI-grade)
cargo build --release- Never commit
config.tomlwith real tokens โ it is listed in.gitignore session_secretandclient_secretare reserved for future OAuth2 support- Use HTTPS in production via a reverse proxy (nginx, Caddy, Traefik)
- MongoDB URI should use credentials in production
- The dashboard API has no authentication in the current release โ restrict access at the network/proxy level until OAuth2 is implemented
This project is licensed under MIT.
We welcome contributions! Please read CONTRIBUTING.md for the Rust workflow, commit guidelines, and PR process. For major changes, open an issue first.
For issues or questions, open an issue on GitHub.


