# The Arbiter - Discord Bot & Admin Panel **Service:** The Arbiter **Purpose:** Discord subscription automation and role management **Server:** Command Center (63.143.34.217) **Status:** ✅ Deployed and operational **Deployed:** March 27, 2026 **Deployed by:** The Verifier (Chronicler #42) --- ## Overview The Arbiter is a Discord bot that automates subscription-based role assignment for Firefrost Gaming. It receives webhooks from Paymenter when subscriptions are created, renewed, cancelled, or expired, and automatically assigns or removes Discord roles accordingly. The bot includes a web-based admin panel where Holly, Meg, and Michael can manage Discord role mappings without SSH access. --- ## Architecture **Flow:** ``` User Subscribes → Paymenter → Webhook (port 3500) → The Arbiter Bot → Discord Role → LuckPerms → In-game Permissions ``` **Components:** 1. **Discord Bot** - Monitors Firefrost Gaming server, assigns roles 2. **Webhook Receiver** - Receives Paymenter subscription events 3. **Admin Panel** - Web interface for managing role mappings 4. **OAuth2 Authentication** - Discord login for authorized admins --- ## Access Information **Admin Panel URL:** https://discord-bot.firefrostgaming.com/admin **Authorized Users:** - Holly (unicorn20089) - Discord ID: `269225344572063754` - Michael (Frostystyle) - Discord ID: `219309716021444609` - Meg (Gingerfury) - Discord ID: `669981568059703316` **Discord Bot:** - Name: The Arbiter - Username: The Arbiter#6636 - Application ID: `1487080166969577502` - Guild ID (Firefrost Gaming): `1260574715546701936` **Server Location:** - Command Center: 63.143.34.217 - Directory: `/opt/firefrost-discord-bot` - Port: 3500 (internal) - HTTPS: 443 (Nginx reverse proxy) --- ## Bot Branding **Visual Identity:** - **Icon:** Scales of Justice with Fire (left, orange #FF6B35) and Frost (right, cyan #4ECDC4) balanced by purple Arcane energy (#A855F7) - **Banner:** Judgment hall with Fire path (left) and Frost path (right) divided by Arcane beam - **Theme:** Fire/Frost/Arcane gradient throughout UI **Generated by:** Gemini AI (Google) **Design Philosophy:** The Arbiter judges who enters the realm and assigns paths --- ## Configuration **Environment File:** `/opt/firefrost-discord-bot/.env` ```bash DISCORD_BOT_TOKEN=MTQ4NzA4MDE2Njk2OTU3NzUwMg.GU5EsT.mqBwo7XUHsciN9jNy9OygTRkaMZ9qJ2tHw7HbI GUILD_ID=1260574715546701936 DISCORD_CLIENT_ID=1487080166969577502 DISCORD_CLIENT_SECRET=xOK9ZYgionyqd-huGJRE2Rym98zy0W-m REDIRECT_URI=https://discord-bot.firefrostgaming.com/auth/discord/callback ADMIN_USERS=269225344572063754,219309716021444609,669981568059703316 PORT=3500 NODE_ENV=production SESSION_SECRET=[auto-generated on deployment] ``` **⚠️ Security Note:** All credentials stored in Vaultwarden. Never commit .env to Git. --- ## Role Mappings **Configuration File:** `/opt/firefrost-discord-bot/role-mappings.json` **Status:** ✅ **COMPLETE** - All 10 tiers configured by Holly on March 27, 2026 **Current Mappings:** ```json { "the-awakened": "1482490386634248273", "the-sovereign": "1482488242677874778", "fire-elemental": "1487181476755996823", "frost-elemental": "1487184348474218778", "fire-knight": "1487183625751880818", "frost-knight": "1487184476371222558", "fire-master": "1487183822951895546", "frost-master": "1487184618860249261", "fire-legend": "1487184056387748935", "frost-legend": "1487184718152138865" } ``` **By Path:** 🔥 **Fire Path:** - Fire Elemental ($5): `1487181476755996823` - Fire Knight ($10): `1487183625751880818` - Fire Master ($15): `1487183822951895546` - Fire Legend ($20): `1487184056387748935` ❄️ **Frost Path:** - Frost Elemental ($5): `1487184348474218778` - Frost Knight ($10): `1487184476371222558` - Frost Master ($15): `1487184618860249261` - Frost Legend ($20): `1487184718152138865` ⚡ **Universal Tiers:** - The Awakened ($1): `1482490386634248273` - The Sovereign ($499): `1482488242677874778` **Mapping Structure:** - Keys: Paymenter product slugs (lowercase, hyphenated) - Values: Discord role IDs (18-19 digit snowflakes) **Configured By:** Holly (unicorn20089 / The Catalyst) **Date Completed:** March 27, 2026 **Full Documentation:** See `docs/systems/arbiter-discord-role-mappings.md` for complete mapping table, testing checklist, and troubleshooting guide. --- ## Systemd Service **Service File:** `/etc/systemd/system/firefrost-discord-bot.service` ```ini [Unit] Description=The Arbiter - Firefrost Gaming Discord Bot After=network.target [Service] Type=simple User=root WorkingDirectory=/opt/firefrost-discord-bot ExecStart=/usr/bin/node /opt/firefrost-discord-bot/bot.js Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=firefrost-discord-bot [Install] WantedBy=multi-user.target ``` **Management Commands:** ```bash # View status systemctl status firefrost-discord-bot # View logs (live) journalctl -u firefrost-discord-bot -f # View last 50 log entries journalctl -u firefrost-discord-bot -n 50 # Restart service systemctl restart firefrost-discord-bot # Stop service systemctl stop firefrost-discord-bot # Start service systemctl start firefrost-discord-bot ``` --- ## Nginx Configuration **Config File:** `/etc/nginx/sites-available/discord-bot.firefrostgaming.com` ```nginx server { listen 63.143.34.217:80; server_name discord-bot.firefrostgaming.com; return 301 https://$server_name$request_uri; } server { listen 63.143.34.217:443 ssl http2; server_name discord-bot.firefrostgaming.com; ssl_certificate /etc/letsencrypt/live/discord-bot.firefrostgaming.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/discord-bot.firefrostgaming.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; location / { proxy_pass http://localhost:3500; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; } access_log /var/log/nginx/discord-bot.access.log; error_log /var/log/nginx/discord-bot.error.log; } ``` **SSL Certificate:** - Provider: Let's Encrypt - Issued: March 27, 2026 - Expires: June 25, 2026 - Auto-renewal: Certbot handles this automatically --- ## Dependencies **Node.js:** v20.20.0 (LTS) **npm:** 10.8.2 **npm Packages:** ```json { "discord.js": "^14.14.1", "express": "^4.18.2", "body-parser": "^1.20.2", "express-session": "^1.18.1", "passport": "^0.7.0", "passport-discord": "^0.1.4", "cookie-parser": "^1.4.7", "dotenv": "^17.3.1" } ``` **Install dependencies:** ```bash cd /opt/firefrost-discord-bot npm install ``` --- ## Admin Panel Features **Role Management:** - View all 10 subscription tiers - Add/update Discord role IDs - See current role status (configured/not configured) - Real-time validation of role IDs **Authentication:** - Discord OAuth2 login - Whitelist-based authorization (only Holly, Meg, Michael) - Session-based authentication with secure cookies **User Interface:** - Fire Path tiers (orange accent) - Frost Path tiers (cyan accent) - Universal tiers (purple accent) - Responsive design - User avatar and logout in header --- ## Webhook Endpoints **Paymenter Webhook:** - URL: `https://discord-bot.firefrostgaming.com/webhook/paymenter` - Method: POST - Content-Type: application/json **Expected Payload:** ```json { "event": "subscription.created", "user": { "discord_id": "123456789012345678" }, "product": { "slug": "fire-elemental", "id": "1" } } ``` **Supported Events:** - `subscription.created` - Add role - `subscription.renewed` - Add role - `subscription.cancelled` - Remove role - `subscription.expired` - Remove role **Health Check:** - URL: `https://discord-bot.firefrostgaming.com/health` - Method: GET - Returns: Bot status, uptime --- ## OAuth2 Configuration **Discord Developer Portal:** - Application: The Arbiter - Client ID: `1487080166969577502` - Redirect URI: `https://discord-bot.firefrostgaming.com/auth/discord/callback` **OAuth2 Scopes:** - `identify` - Read user profile **Privileged Gateway Intents (Enabled):** - Presence Intent ✅ - Server Members Intent ✅ (CRITICAL for role assignment) - Message Content Intent ✅ --- ## Troubleshooting ### Bot Shows Offline in Discord ```bash # Check service status systemctl status firefrost-discord-bot # Check logs for errors journalctl -u firefrost-discord-bot -n 50 ``` **Common causes:** - Invalid bot token - Discord API outage - Service not running ### Admin Panel Login Loop **Symptoms:** Redirects to login after authorizing Discord **Solution:** Verify `app.set('trust proxy', 1);` is present in bot.js (line 62) **Why this happens:** Nginx does SSL termination, Express sees HTTP requests, refuses to set secure cookies without trusting X-Forwarded-Proto header. ### Role Not Assigned After Webhook ```bash # Check webhook logs journalctl -u firefrost-discord-bot | grep "Webhook received" # Verify role mapping exists cat /opt/firefrost-discord-bot/role-mappings.json # Check Discord bot permissions # Bot must have "Manage Roles" permission # Bot's role must be HIGHER than the roles it's assigning ``` ### Nginx 502 Bad Gateway ```bash # Verify bot is listening on port 3500 netstat -tlnp | grep 3500 # Restart bot service systemctl restart firefrost-discord-bot # Check Nginx config nginx -t ``` --- ## Deployment History **March 27, 2026 - Initial Deployment & Configuration** - Created Discord bot application "The Arbiter" - Generated icon and banner via Gemini AI - Deployed bot.js on Command Center - Configured systemd service - Set up Nginx reverse proxy with Let's Encrypt SSL - Deployed admin panel with Discord OAuth2 - Fixed SSL termination / secure cookie issue with `app.set('trust proxy', 1);` - Created Holly's role setup guide - **Holly completed all 10 role ID mappings** (Fire/Frost paths + Universal tiers) - Status: ✅ **Fully Operational** - All tiers configured, ready for webhook testing --- ## Security Considerations **Secrets Management:** - All credentials in .env file - .env never committed to Git - Session secret auto-generated with openssl - Client secret rotated during deployment **Authentication:** - Whitelist-based admin access (3 users) - Discord OAuth2 for identity verification - Session-based authentication - Secure cookies in production **Network Security:** - Bot only accessible via HTTPS - Nginx handles SSL termination - Internal port 3500 not exposed externally - Rate limiting via Nginx (if needed, add later) **Bot Permissions:** - Minimal Discord permissions (Manage Roles, Send Messages) - No Administrator permission - Bot role positioned correctly in Discord hierarchy --- ## Future Enhancements **Potential additions:** - Audit logging to Discord channel for role changes - Webhook retry logic for failed deliveries - Role assignment history/statistics - Integration with LuckPerms for in-game permission sync - Multi-server support (if Firefrost expands to multiple Discord servers) --- ## Related Documentation - **Holly's Role Setup Guide:** `docs/guides/holly-discord-roles-setup.md` - **Subscription Automation Guide:** `docs/guides/subscription-automation-guide.md` - **Discord Bot Admin Panel Guide:** `docs/guides/discord-bot-admin-panel.md` - **Paymenter Configuration:** `docs/services/paymenter-configuration.md` - **LuckPerms MySQL Database:** `docs/services/luckperms-mysql-database.md` --- ## Support Contacts **Technical Issues:** - Michael (Frostystyle) - Server owner, technical lead - Discord: #staff-lounge channel **Role Management Questions:** - Holly (unicorn20089) - Lead builder, role configuration --- **Last Updated:** March 27, 2026 **Originally Deployed By:** The Verifier (Chronicler #42) **Role Configuration Completed By:** Holly (The Catalyst) via The Herald (Chronicler #43) **Status:** Production - Fully Configured ✅ - All 10 tiers mapped, ready for Paymenter webhook integration