The top subscription tier is Sovereign, not Founder. This has been corrected multiple times across sessions — fixing at source. FILES UPDATED: - docs/core/tasks.md - docs/core/project-scope.md - docs/tasks/rank-system-deployment/rank-structure.md - docs/tasks/paymenter-pterodactyl-integration/README.md - docs/archive/2026-02-09-consolidation/luckperms-structure.md - docs/planning/subscription-tiers.md - docs/planning/awakened-gateway.md - docs/guides/subscription-automation-guide.md - docs/guides/holly-discord-roles-setup.md - docs/guides/holly-wanderer-permissions-setup.md - docs/systems/arbiter-discord-role-mappings.md - docs/branding/trinity-leadership-artwork.md NOTE: References to 'founders' meaning Michael/Meg/Holly as company founders were intentionally preserved. Only tier name updated. Signed-off-by: claude@firefrostgaming.com
1931 lines
50 KiB
Markdown
1931 lines
50 KiB
Markdown
# Firefrost Gaming - Subscription Automation Guide
|
|
|
|
**Version:** 1.0
|
|
**Date:** March 23, 2026
|
|
**Author:** Chronicler #40
|
|
**Audience:** Holly (Lead Builder) + Michael (for Discord bot setup)
|
|
**Purpose:** Automate subscriber tier assignment from Paymenter purchase to in-game ranks
|
|
|
|
---
|
|
|
|
## 📋 TABLE OF CONTENTS
|
|
|
|
1. [Overview](#overview)
|
|
2. [Architecture](#architecture)
|
|
3. [Prerequisites](#prerequisites)
|
|
4. [Part 1: Discord Bot Setup](#part-1-discord-bot-setup)
|
|
5. [Part 2: Discord Roles Configuration](#part-2-discord-roles-configuration)
|
|
6. [Part 3: LuckPerms Groups & Permissions](#part-3-luckperms-groups-permissions)
|
|
7. [Part 4: LuckPerms Discord Integration](#part-4-luckperms-discord-integration)
|
|
8. [Part 5: Paymenter Webhook Configuration](#part-5-paymenter-webhook-configuration)
|
|
9. [Testing & Verification](#testing-verification)
|
|
10. [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## 🎯 OVERVIEW
|
|
|
|
### What This Guide Does
|
|
|
|
This guide sets up **fully automated subscription management**:
|
|
|
|
1. User purchases subscription in Paymenter
|
|
2. Paymenter sends webhook to Discord bot
|
|
3. Discord bot assigns appropriate role to user
|
|
4. LuckPerms detects Discord role and syncs to in-game rank
|
|
5. Player automatically gets correct permissions on all 13 servers
|
|
|
|
**No manual work required after setup.**
|
|
|
|
### The Flow
|
|
|
|
```
|
|
User Subscribes ($1-$499)
|
|
↓
|
|
Paymenter (billing.firefrostgaming.com)
|
|
↓
|
|
Webhook fires (new purchase detected)
|
|
↓
|
|
Discord Bot receives webhook
|
|
↓
|
|
Bot assigns Discord role (The Awakened, Fire Elemental, etc.)
|
|
↓
|
|
LuckPerms syncs Discord role → In-game group
|
|
↓
|
|
Player gets permissions on all 13 servers instantly
|
|
↓
|
|
Player can join servers, claim chunks, set homes (based on tier)
|
|
```
|
|
|
|
### Time Estimate
|
|
|
|
- **Discord Bot Setup:** 1-2 hours (Michael + Holly)
|
|
- **Discord Roles:** 30 minutes (Holly)
|
|
- **LuckPerms Configuration:** 2-3 hours (Holly, across all 13 servers)
|
|
- **Paymenter Webhooks:** 1 hour (Michael + Holly testing)
|
|
|
|
**Total:** 4-6 hours
|
|
|
|
---
|
|
|
|
## 🏗️ ARCHITECTURE
|
|
|
|
### Components
|
|
|
|
1. **Paymenter** (billing.firefrostgaming.com) - Billing system
|
|
2. **Discord Server** - Community hub
|
|
3. **Discord Bot** - Automation middleman
|
|
4. **LuckPerms** - Permission management (all 13 game servers)
|
|
5. **MySQL Database** - Shared permission storage
|
|
|
|
### Why This Design?
|
|
|
|
**Why not direct Paymenter → LuckPerms?**
|
|
- Discord is the community hub - subscribers want Discord access too
|
|
- Discord roles provide social status and channel access
|
|
- Discord bot can handle complex logic (upgrades, downgrades, cancellations)
|
|
- Easier to troubleshoot (can see Discord roles visually)
|
|
|
|
**Why LuckPerms syncs FROM Discord?**
|
|
- Industry standard approach
|
|
- Discord becomes "source of truth" for subscriber status
|
|
- If someone loses subscriber role in Discord, they automatically lose in-game perks
|
|
- Prevents desync between Discord and game servers
|
|
|
|
---
|
|
|
|
## ✅ PREREQUISITES
|
|
|
|
### Before You Start
|
|
|
|
**Complete these first:**
|
|
|
|
- [ ] **Server-Side Mod Deployment Guide** completed on ALL 13 servers
|
|
- [ ] LuckPerms installed and connected to MySQL on all servers
|
|
- [ ] Michael has created MySQL database and provided credentials
|
|
- [ ] You have admin access to Firefrost Gaming Discord server
|
|
- [ ] You have access to Paymenter admin panel
|
|
|
|
### What You'll Need
|
|
|
|
**From Michael:**
|
|
- Discord bot token (Michael will create this)
|
|
- Paymenter admin credentials
|
|
- MySQL database credentials (already provided for LuckPerms)
|
|
|
|
**Access Required:**
|
|
- Discord server admin permissions
|
|
- Pterodactyl panel access (to restart servers)
|
|
- SSH access to game servers (for LuckPerms testing)
|
|
- **Admin panel access** (for managing Discord role mappings) - see `docs/guides/discord-bot-admin-panel.md`
|
|
|
|
---
|
|
|
|
## 🤖 PART 1: DISCORD BOT SETUP
|
|
|
|
---
|
|
|
|
## 🔧 MICHAEL'S PRE-SETUP (Complete BEFORE Holly Starts)
|
|
|
|
**STOP: Michael must complete this entire section BEFORE handing the guide to Holly.**
|
|
|
|
### Task 1: Create Discord Application & Bot
|
|
|
|
**Michael's steps:**
|
|
|
|
1. Go to https://discord.com/developers/applications
|
|
2. Click **New Application**
|
|
3. Name: "Firefrost Subscription Manager"
|
|
4. Click **Create**
|
|
|
|
### Task 2: Configure Bot Settings
|
|
|
|
1. In the application, go to **Bot** tab (left sidebar)
|
|
2. Click **Add Bot** → **Yes, do it!**
|
|
3. Under **Privileged Gateway Intents**, enable:
|
|
- ✅ **Server Members Intent** (REQUIRED - bot needs to assign roles)
|
|
- ✅ **Message Content Intent** (REQUIRED - bot needs to read webhook data)
|
|
4. Click **Save Changes**
|
|
|
|
### Task 3: Get Bot Token
|
|
|
|
1. Under **Bot** tab, find **Token** section
|
|
2. Click **Reset Token** (confirm if asked)
|
|
3. Click **Copy** to copy the token
|
|
4. **SAVE THIS TOKEN SECURELY** - you'll give it to Holly later
|
|
|
|
**The token looks like:**
|
|
```
|
|
MTxxxxxxxxxxxxxxxxxxxxxx.xxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
```
|
|
|
|
**⚠️ NEVER share this token publicly or commit it to git!**
|
|
|
|
### Task 4: Invite Bot to Discord Server
|
|
|
|
1. Go to **OAuth2** tab → **URL Generator** (left sidebar)
|
|
2. Under **Scopes**, select:
|
|
- ✅ `bot`
|
|
- ✅ `applications.commands`
|
|
3. Under **Bot Permissions**, select:
|
|
- ✅ **Manage Roles** (REQUIRED - assigns subscriber roles)
|
|
- ✅ **Send Messages** (for welcome DMs)
|
|
- ✅ **Read Message History** (optional)
|
|
- ✅ **Use Slash Commands** (future-proofing)
|
|
4. Scroll down and **Copy** the generated URL
|
|
5. Open the URL in a new browser tab
|
|
6. Select **Firefrost Gaming** server from dropdown
|
|
7. Click **Authorize**
|
|
8. Complete the CAPTCHA
|
|
|
|
**The bot should now appear in your Discord server's member list (offline status is normal - it's not running yet).**
|
|
|
|
### Task 5: Get Discord Server ID (Guild ID)
|
|
|
|
1. Open Discord
|
|
2. Go to **User Settings** (gear icon)
|
|
3. Go to **Advanced** (left sidebar)
|
|
4. Enable **Developer Mode** ✅
|
|
5. Close settings
|
|
6. Right-click your **Firefrost Gaming** server icon
|
|
7. Click **Copy Server ID**
|
|
8. **Save this ID** - you'll give it to Holly
|
|
|
|
**The ID looks like:**
|
|
```
|
|
123456789012345678
|
|
```
|
|
|
|
### Task 6: Deploy Bot Code on Command Center
|
|
|
|
**SSH to Command Center:**
|
|
|
|
```bash
|
|
ssh root@63.143.34.217
|
|
```
|
|
|
|
**Install Node.js (if not already installed):**
|
|
|
|
```bash
|
|
# Check if Node.js is installed
|
|
node --version
|
|
|
|
# If not installed or version < 18, install Node.js 20:
|
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
apt-get install -y nodejs
|
|
|
|
# Verify
|
|
node --version # Should show v20.x.x
|
|
npm --version # Should show 10.x.x
|
|
```
|
|
|
|
**Create bot directory:**
|
|
|
|
```bash
|
|
mkdir -p /opt/firefrost-discord-bot
|
|
cd /opt/firefrost-discord-bot
|
|
```
|
|
|
|
**Create package.json:**
|
|
|
|
```bash
|
|
cat > package.json << 'EOF'
|
|
{
|
|
"name": "firefrost-discord-bot",
|
|
"version": "1.0.0",
|
|
"description": "Firefrost Gaming subscription automation bot",
|
|
"main": "bot.js",
|
|
"scripts": {
|
|
"start": "node bot.js"
|
|
},
|
|
"dependencies": {
|
|
"discord.js": "^14.14.1",
|
|
"express": "^4.18.2",
|
|
"body-parser": "^1.20.2"
|
|
}
|
|
}
|
|
EOF
|
|
```
|
|
|
|
**Install dependencies:**
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
**Create bot.js file:**
|
|
|
|
```bash
|
|
cat > bot.js << 'EOF'
|
|
// Firefrost Gaming - Discord Subscription Bot
|
|
// Handles Paymenter webhooks and assigns Discord roles
|
|
|
|
const { Client, GatewayIntentBits } = require('discord.js');
|
|
const express = require('express');
|
|
const bodyParser = require('body-parser');
|
|
|
|
// Configuration - REPLACE THESE VALUES
|
|
const DISCORD_TOKEN = 'YOUR_BOT_TOKEN_HERE';
|
|
const GUILD_ID = 'YOUR_GUILD_ID_HERE';
|
|
|
|
// Product ID to Role ID mapping (from Paymenter)
|
|
// Holly will fill these in after creating Discord roles
|
|
const PRODUCT_ROLE_MAP = {
|
|
'2': 'AWAKENED_ROLE_ID',
|
|
'3': 'FIRE_ELEMENTAL_ROLE_ID',
|
|
'4': 'FROST_ELEMENTAL_ROLE_ID',
|
|
'5': 'FIRE_KNIGHT_ROLE_ID',
|
|
'6': 'FROST_KNIGHT_ROLE_ID',
|
|
'7': 'FIRE_MASTER_ROLE_ID',
|
|
'8': 'FROST_MASTER_ROLE_ID',
|
|
'9': 'FIRE_LEGEND_ROLE_ID',
|
|
'10': 'FROST_LEGEND_ROLE_ID',
|
|
'11': 'SOVEREIGN_ROLE_ID'
|
|
};
|
|
|
|
// Initialize Discord client
|
|
const client = new Client({
|
|
intents: [
|
|
GatewayIntentBits.Guilds,
|
|
GatewayIntentBits.GuildMembers
|
|
]
|
|
});
|
|
|
|
// Initialize Express for webhook receiver
|
|
const app = express();
|
|
app.use(bodyParser.json());
|
|
|
|
// Discord bot ready event
|
|
client.once('ready', () => {
|
|
console.log(`✅ Bot logged in as ${client.user.tag}`);
|
|
console.log(`🔗 Connected to ${client.guilds.cache.size} server(s)`);
|
|
});
|
|
|
|
// Webhook endpoint - Paymenter sends POST here
|
|
app.post('/webhook/paymenter', async (req, res) => {
|
|
try {
|
|
console.log('📬 Received webhook from Paymenter');
|
|
console.log('Payload:', JSON.stringify(req.body, null, 2));
|
|
|
|
const { event, product_id, user_email, discord_id } = req.body;
|
|
|
|
// Validate webhook
|
|
if (!event || !product_id) {
|
|
console.error('❌ Invalid webhook data - missing event or product_id');
|
|
return res.status(400).json({ error: 'Missing required fields' });
|
|
}
|
|
|
|
if (!discord_id) {
|
|
console.error('⚠️ No discord_id provided - cannot assign role');
|
|
return res.status(400).json({ error: 'Missing discord_id' });
|
|
}
|
|
|
|
console.log(`📦 Event: ${event}, Product: ${product_id}, Discord ID: ${discord_id}`);
|
|
|
|
// Get Discord guild
|
|
const guild = client.guilds.cache.get(GUILD_ID);
|
|
if (!guild) {
|
|
console.error('❌ Guild not found');
|
|
return res.status(500).json({ error: 'Guild not found' });
|
|
}
|
|
|
|
// Get member
|
|
const member = await guild.members.fetch(discord_id);
|
|
if (!member) {
|
|
console.error('❌ Member not found in Discord server');
|
|
return res.status(404).json({ error: 'Member not found' });
|
|
}
|
|
|
|
// Get role ID for this product
|
|
const roleId = PRODUCT_ROLE_MAP[product_id];
|
|
if (!roleId || roleId.includes('ROLE_ID')) {
|
|
console.error(`❌ No role mapped for product ${product_id} (or role ID not configured)`);
|
|
return res.status(400).json({ error: 'Unknown product or role not configured' });
|
|
}
|
|
|
|
// Handle event
|
|
if (event === 'subscription.created' || event === 'payment.completed') {
|
|
// Add role
|
|
await member.roles.add(roleId);
|
|
console.log(`✅ Added role ${roleId} to ${member.user.tag}`);
|
|
|
|
// Send welcome DM
|
|
try {
|
|
await member.send(`🎉 Welcome to Firefrost Gaming! Your subscription is now active. Check out the server - your perks are ready!`);
|
|
console.log(`📨 Sent welcome DM to ${member.user.tag}`);
|
|
} catch (err) {
|
|
console.log('⚠️ Could not send DM (user has DMs disabled)');
|
|
}
|
|
|
|
} else if (event === 'subscription.cancelled' || event === 'subscription.expired') {
|
|
// Remove role
|
|
await member.roles.remove(roleId);
|
|
console.log(`❌ Removed role ${roleId} from ${member.user.tag}`);
|
|
|
|
} else {
|
|
console.log(`⚠️ Unknown event type: ${event}`);
|
|
}
|
|
|
|
res.status(200).json({ success: true });
|
|
|
|
} catch (error) {
|
|
console.error('❌ Webhook processing error:', error);
|
|
res.status(500).json({ error: 'Internal server error', details: error.message });
|
|
}
|
|
});
|
|
|
|
// Health check endpoint
|
|
app.get('/health', (req, res) => {
|
|
res.status(200).json({
|
|
status: 'healthy',
|
|
bot: client.user ? client.user.tag : 'disconnected',
|
|
uptime: process.uptime()
|
|
});
|
|
});
|
|
|
|
// Start Express server
|
|
const PORT = 3100;
|
|
app.listen(PORT, () => {
|
|
console.log(`🌐 Webhook server listening on port ${PORT}`);
|
|
console.log(`📍 Webhook URL: http://localhost:${PORT}/webhook/paymenter`);
|
|
});
|
|
|
|
// Start Discord bot
|
|
client.login(DISCORD_TOKEN);
|
|
EOF
|
|
```
|
|
|
|
**Edit bot.js and add your credentials:**
|
|
|
|
```bash
|
|
nano bot.js
|
|
```
|
|
|
|
**Find these lines:**
|
|
```javascript
|
|
const DISCORD_TOKEN = 'YOUR_BOT_TOKEN_HERE';
|
|
const GUILD_ID = 'YOUR_GUILD_ID_HERE';
|
|
```
|
|
|
|
**Replace with:**
|
|
```javascript
|
|
const DISCORD_TOKEN = 'MTxxxx...'; // Your actual bot token from Task 3
|
|
const GUILD_ID = '123456789012345678'; // Your actual server ID from Task 5
|
|
```
|
|
|
|
**Save and exit** (Ctrl+X, Y, Enter)
|
|
|
|
**Create systemd service:**
|
|
|
|
```bash
|
|
cat > /etc/systemd/system/firefrost-discord-bot.service << 'EOF'
|
|
[Unit]
|
|
Description=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
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
```
|
|
|
|
**Enable and start the bot:**
|
|
|
|
```bash
|
|
# Reload systemd
|
|
systemctl daemon-reload
|
|
|
|
# Enable auto-start on boot
|
|
systemctl enable firefrost-discord-bot
|
|
|
|
# Start the bot
|
|
systemctl start firefrost-discord-bot
|
|
|
|
# Check status
|
|
systemctl status firefrost-discord-bot
|
|
```
|
|
|
|
**You should see:**
|
|
```
|
|
● firefrost-discord-bot.service - Firefrost Gaming Discord Bot
|
|
Loaded: loaded
|
|
Active: active (running)
|
|
```
|
|
|
|
**View logs to confirm it's working:**
|
|
|
|
```bash
|
|
journalctl -u firefrost-discord-bot -f
|
|
```
|
|
|
|
**You should see:**
|
|
```
|
|
✅ Bot logged in as Firefrost Subscription Manager#1234
|
|
🔗 Connected to 1 server(s)
|
|
🌐 Webhook server listening on port 3100
|
|
```
|
|
|
|
**If you see errors about invalid token:**
|
|
- Double-check you copied the token correctly
|
|
- Make sure there are no extra spaces
|
|
- Verify the token hasn't been reset/revoked
|
|
|
|
**Press Ctrl+C to exit log view when done.**
|
|
|
|
### Task 7: Set Up DNS (Cloudflare)
|
|
|
|
**Before setting up Nginx, add DNS record:**
|
|
|
|
1. Go to https://dash.cloudflare.com
|
|
2. Select **firefrostgaming.com** domain
|
|
3. Go to **DNS** → **Records**
|
|
4. Click **Add record**
|
|
5. Configure:
|
|
- **Type:** A
|
|
- **Name:** webhook
|
|
- **IPv4 address:** 63.143.34.217 (Command Center IP)
|
|
- **Proxy status:** 🟠 DNS only (turn OFF the orange cloud)
|
|
- **TTL:** Auto
|
|
6. Click **Save**
|
|
|
|
**Wait 1-2 minutes for DNS to propagate.**
|
|
|
|
**Verify DNS is working:**
|
|
|
|
```bash
|
|
# Test DNS resolution
|
|
dig webhook.firefrostgaming.com
|
|
|
|
# Should show:
|
|
# webhook.firefrostgaming.com. 300 IN A 63.143.34.217
|
|
```
|
|
|
|
### Task 8: Set Up Nginx Reverse Proxy
|
|
|
|
**Still on Command Center, configure Nginx:**
|
|
|
|
```bash
|
|
cat > /etc/nginx/sites-available/discord-webhook << 'EOF'
|
|
server {
|
|
listen 80;
|
|
server_name webhook.firefrostgaming.com;
|
|
|
|
location / {
|
|
proxy_pass http://localhost:3100;
|
|
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_cache_bypass $http_upgrade;
|
|
}
|
|
}
|
|
EOF
|
|
```
|
|
|
|
**Enable the site:**
|
|
|
|
```bash
|
|
ln -s /etc/nginx/sites-available/discord-webhook /etc/nginx/sites-enabled/
|
|
nginx -t
|
|
systemctl reload nginx
|
|
```
|
|
|
|
**Get SSL certificate:**
|
|
|
|
```bash
|
|
certbot --nginx -d webhook.firefrostgaming.com
|
|
```
|
|
|
|
**Test the webhook endpoint:**
|
|
|
|
```bash
|
|
curl https://webhook.firefrostgaming.com/health
|
|
```
|
|
|
|
**Should return:**
|
|
```json
|
|
{"status":"healthy","bot":"Firefrost Subscription Manager#1234","uptime":123.456}
|
|
```
|
|
|
|
### Task 9: Set Up Discord Bot Admin Panel
|
|
|
|
**PURPOSE:** Deploy web interface so Holly can manage Discord role mappings herself (no SSH access needed).
|
|
|
|
**⚠️ IMPORTANT:** Complete admin panel setup is documented in a separate guide.
|
|
|
|
**See:** `docs/guides/discord-bot-admin-panel.md`
|
|
|
|
**Quick Overview:**
|
|
|
|
The admin panel allows Holly to:
|
|
- Log in via Discord OAuth (no passwords)
|
|
- Update all 10 product → Discord role ID mappings
|
|
- Save changes instantly (no bot restart needed)
|
|
- View bot status and recent webhooks
|
|
|
|
**Setup Steps (High-Level):**
|
|
|
|
1. Create dedicated `firefrost-bot` Linux user (security - don't run as root)
|
|
2. Set up Discord OAuth2 application
|
|
3. Deploy backend code (provided by Gemini/Google AI)
|
|
4. Deploy frontend code (provided by Gemini/Google AI)
|
|
5. Configure Nginx reverse proxy + SSL
|
|
6. Give Holly admin panel URL and walk through usage
|
|
|
|
**Time Required:** 2-3 hours (one-time setup)
|
|
|
|
**Once Complete:**
|
|
|
|
Holly will access admin panel at:
|
|
```
|
|
https://discord-bot.firefrostgaming.com/admin
|
|
```
|
|
|
|
**Status:** Full implementation guide available at `docs/guides/discord-bot-admin-panel.md`
|
|
|
|
**For now, continue with manual method below (Holly gives you role IDs, you update bot.js). We'll migrate to admin panel later.**
|
|
|
|
---
|
|
|
|
### Task 9 (ALTERNATIVE - MANUAL METHOD)
|
|
|
|
**If admin panel isn't set up yet, use this manual approach:**
|
|
|
|
Create a credentials file for Holly:
|
|
|
|
```bash
|
|
cat > /root/holly-bot-credentials.txt << EOF
|
|
Firefrost Discord Bot - Credentials for Holly
|
|
|
|
Bot Name: Firefrost Subscription Manager
|
|
Guild ID: $(grep "const GUILD_ID" /opt/firefrost-discord-bot/bot.js | cut -d"'" -f2)
|
|
|
|
Webhook URL: https://webhook.firefrostgaming.com/webhook/paymenter
|
|
|
|
Next Steps:
|
|
1. Holly creates Discord roles (Part 2 of guide)
|
|
2. Holly gets role IDs and sends them to Michael
|
|
3. Michael updates bot.js PRODUCT_ROLE_MAP with role IDs
|
|
4. Michael restarts bot: systemctl restart firefrost-discord-bot
|
|
5. Test webhook flow
|
|
|
|
NOTE: Once admin panel is deployed, Holly can update role IDs herself.
|
|
See: docs/guides/discord-bot-admin-panel.md
|
|
|
|
---
|
|
Generated: $(date)
|
|
EOF
|
|
|
|
cat /root/holly-bot-credentials.txt
|
|
```
|
|
|
|
**Save this output - you'll give it to Holly.**
|
|
|
|
---
|
|
|
|
## ✅ MICHAEL'S PRE-SETUP COMPLETE
|
|
|
|
**Checklist before handing to Holly:**
|
|
|
|
- [ ] Discord bot created and invited to server
|
|
- [ ] Bot token saved securely
|
|
- [ ] Guild ID recorded
|
|
- [ ] Node.js installed on Command Center
|
|
- [ ] Bot code deployed to /opt/firefrost-discord-bot/
|
|
- [ ] Bot service running successfully
|
|
- [ ] Nginx reverse proxy configured
|
|
- [ ] SSL certificate obtained
|
|
- [ ] Webhook endpoint accessible at https://webhook.firefrostgaming.com
|
|
- [ ] Credentials file created for Holly
|
|
|
|
**If all checked, proceed to Part 2 and hand the guide to Holly.**
|
|
|
|
---
|
|
|
|
## 👥 HOLLY'S TASKS START HERE
|
|
|
|
**At this point, Michael has:**
|
|
- ✅ Created the Discord bot application
|
|
- ✅ Deployed bot code to Command Center
|
|
- ✅ Set up Nginx reverse proxy
|
|
- ✅ Bot is running and accessible at https://webhook.firefrostgaming.com
|
|
|
|
**Holly, you now need to:**
|
|
1. Create Discord roles (Part 2)
|
|
2. **EITHER:**
|
|
- **Option A (Recommended):** Use Discord Bot Admin Panel at `discord-bot.firefrostgaming.com/admin` to update role IDs
|
|
- **Option B (Manual):** Give role IDs to Michael, he updates bot.js via SSH
|
|
3. Configure LuckPerms groups and permissions (Part 3)
|
|
4. Set up LuckPerms Discord integration (Part 4)
|
|
5. Configure Paymenter webhooks (Part 5)
|
|
6. Test the complete flow
|
|
|
|
**Note:** If admin panel is set up (Option A), you can update role mappings yourself anytime. If not (Option B), you'll need Michael's help each time roles change.
|
|
|
|
**Admin panel documentation:** `docs/guides/discord-bot-admin-panel.md`
|
|
|
|
---
|
|
|
|
## 👥 PART 2: DISCORD ROLES CONFIGURATION
|
|
|
|
### Step 1: Create Discord Roles (Holly's Task)
|
|
|
|
**In your Discord server:**
|
|
|
|
1. Right-click server icon → **Server Settings**
|
|
2. Click **Roles**
|
|
3. Click **Create Role** for each tier
|
|
|
|
**Create these roles (in order, top to bottom):**
|
|
|
|
#### Role 1: Sovereign
|
|
- **Name:** `⚡ Sovereign`
|
|
- **Color:** `#FFD600` (Amber Gold)
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
- **Mentionable:** ✅ Yes
|
|
|
|
#### Role 2: Fire Legend
|
|
- **Name:** `🔥 Fire Legend`
|
|
- **Color:** `#FF3D00` (Deep Orange/Red)
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 3: Frost Legend
|
|
- **Name:** `❄️ Frost Legend`
|
|
- **Color:** `#00E5FF` (Electric Cyan)
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 4: Fire Master
|
|
- **Name:** `🔥 Fire Master`
|
|
- **Color:** `#FF3D00`
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 5: Frost Master
|
|
- **Name:** `❄️ Frost Master`
|
|
- **Color:** `#00E5FF`
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 6: Fire Knight
|
|
- **Name:** `🔥 Fire Knight`
|
|
- **Color:** `#FF3D00`
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 7: Frost Knight
|
|
- **Name:** `❄️ Frost Knight`
|
|
- **Color:** `#00E5FF`
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 8: Fire Elemental
|
|
- **Name:** `🔥 Fire Elemental`
|
|
- **Color:** `#FF3D00`
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 9: Frost Elemental
|
|
- **Name:** `❄️ Frost Elemental`
|
|
- **Color:** `#00E5FF`
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 10: The Awakened
|
|
- **Name:** `The Awakened`
|
|
- **Color:** `#FFFFFF` (White)
|
|
- **Permissions:** (default member permissions)
|
|
- **Display separately:** ✅ Yes
|
|
|
|
#### Role 11: Wanderer (Free)
|
|
- **Name:** `Wanderer`
|
|
- **Color:** `#99AAB5` (Gray)
|
|
- **Permissions:** Read messages only (restrict Send Messages in channels)
|
|
- **Display separately:** No
|
|
|
|
### Step 2: Get Role IDs
|
|
|
|
**For each role you just created:**
|
|
|
|
1. Right-click the role in Server Settings → Roles
|
|
2. Click **Copy ID** (if you don't see this, enable Developer Mode in Discord settings)
|
|
3. Paste the ID somewhere - you'll need them
|
|
|
|
**Create a mapping:**
|
|
```
|
|
The Awakened: 123456789012345678
|
|
Fire Elemental: 234567890123456789
|
|
Frost Elemental: 345678901234567890
|
|
Fire Knight: 456789012345678901
|
|
Frost Knight: 567890123456789012
|
|
Fire Master: 678901234567890123
|
|
Frost Master: 789012345678901234
|
|
Fire Legend: 890123456789012345
|
|
Frost Legend: 901234567890123456
|
|
Sovereign: 012345678901234567
|
|
```
|
|
|
|
### Step 3: Update Role Mappings in Bot
|
|
|
|
**After creating all Discord roles (Step 2), you need to tell the bot which role ID corresponds to which subscription tier.**
|
|
|
|
**You have TWO options:**
|
|
|
|
---
|
|
|
|
#### **OPTION A: Use Discord Bot Admin Panel** (RECOMMENDED)
|
|
|
|
**If admin panel is deployed** (see `docs/guides/discord-bot-admin-panel.md`):
|
|
|
|
**Holly can do this herself:**
|
|
|
|
1. Open admin panel: `https://discord-bot.firefrostgaming.com/admin`
|
|
2. Click **Login with Discord** (OAuth2 - no password needed)
|
|
3. You'll see a form with 10 product tiers
|
|
4. For each product, paste the Discord role ID you copied in Step 2
|
|
5. Click **Save** for each row (validates and saves instantly)
|
|
6. **No bot restart needed** - changes take effect immediately
|
|
7. Check `#bot-audit-logs` in Discord to see confirmation embed
|
|
|
|
**Example workflow:**
|
|
```
|
|
Product 2 (The Awakened) → Paste role ID → Click Save → ✅ Green confirmation
|
|
Product 3 (Fire Elemental) → Paste role ID → Click Save → ✅ Green confirmation
|
|
... (repeat for all 10 products)
|
|
```
|
|
|
|
**Status indicator:**
|
|
- 🟢 Green dot = Bot connected and working
|
|
- 🔴 Red dot = Bot offline (contact Michael)
|
|
|
|
**Complete guide:** `docs/guides/discord-bot-admin-panel.md`
|
|
|
|
---
|
|
|
|
#### **OPTION B: Manual Method** (If admin panel not deployed yet)
|
|
|
|
**Holly:** Copy all your role IDs and send them to Michael in this format:
|
|
|
|
```
|
|
The Awakened: 123456789012345678
|
|
Fire Elemental: 234567890123456789
|
|
Frost Elemental: 345678901234567890
|
|
Fire Knight: 456789012345678901
|
|
Frost Knight: 567890123456789012
|
|
Fire Master: 678901234567890123
|
|
Frost Master: 789012345678901234
|
|
Fire Legend: 890123456789012345
|
|
Frost Legend: 901234567890123456
|
|
Sovereign: 012345678901234567
|
|
```
|
|
|
|
**Michael:** Holly will give you the list above. SSH to Command Center and update the bot:
|
|
|
|
```bash
|
|
ssh root@63.143.34.217
|
|
nano /opt/firefrost-discord-bot/bot.js
|
|
```
|
|
|
|
Find the `PRODUCT_ROLE_MAP` or config.json section and update the role IDs.
|
|
|
|
Save, then restart:
|
|
|
|
```bash
|
|
systemctl restart firefrost-discord-bot
|
|
systemctl status firefrost-discord-bot
|
|
```
|
|
|
|
**Note:** This manual method requires bot restart and Michael's SSH access. **Option A (admin panel) is much better** - Holly can update roles anytime without waiting for Michael.
|
|
|
|
---
|
|
|
|
**After updating role mappings (either method), proceed to Step 4.**
|
|
|
|
### Step 4: Configure Channel Permissions
|
|
|
|
**Create private channels for Fire/Frost paths:**
|
|
|
|
#### Fire Path Channels
|
|
- `#🔥-fire-general` - Only visible to Fire Elemental+ roles
|
|
- `#🔥-fire-builds` - Only visible to Fire Elemental+ roles
|
|
- `#🔥-fire-strategy` - Only visible to Fire Elemental+ roles
|
|
|
|
**Permissions:**
|
|
- Deny: `@everyone` - View Channel
|
|
- Allow: `@🔥 Fire Elemental`, `@🔥 Fire Knight`, `@🔥 Fire Master`, `@🔥 Fire Legend`, `@⚡ Sovereign`
|
|
|
|
#### Frost Path Channels
|
|
- `#❄️-frost-general` - Only visible to Frost Elemental+ roles
|
|
- `#❄️-frost-builds` - Only visible to Frost Elemental+ roles
|
|
- `#❄️-frost-strategy` - Only visible to Frost Elemental+ roles
|
|
|
|
**Permissions:**
|
|
- Deny: `@everyone` - View Channel
|
|
- Allow: `@❄️ Frost Elemental`, `@❄️ Frost Knight`, `@❄️ Frost Master`, `@❄️ Frost Legend`, `@⚡ Sovereign`
|
|
|
|
#### The Nexus (Sovereign Only)
|
|
- `#⚡-the-nexus` - Only visible to Sovereign
|
|
|
|
**Permissions:**
|
|
- Deny: `@everyone` - View Channel
|
|
- Allow: `@⚡ Sovereign` only
|
|
|
|
---
|
|
|
|
## ⚙️ PART 3: LUCKPERMS GROUPS & PERMISSIONS
|
|
|
|
**This is the most important section - you'll configure 13 groups (11 subscriber tiers + 2 staff ranks) that control all in-game permissions.**
|
|
|
|
**⚠️ IMPORTANT:** Because all 13 servers connect to the SAME MySQL database, you only need to do this ONCE. Changes sync automatically to all servers.
|
|
|
|
---
|
|
|
|
## 🎯 CHOOSE YOUR METHOD
|
|
|
|
You have **two ways** to create LuckPerms groups:
|
|
|
|
### Method A: Web Editor (RECOMMENDED - Fast & Visual)
|
|
- ✅ **Time:** 30-45 minutes
|
|
- ✅ **Difficulty:** Easy (point and click)
|
|
- ✅ **Visual interface** - see group hierarchy, drag-and-drop permissions
|
|
- ✅ **Color picker** for chat prefixes
|
|
- ✅ **Built-in validation** - prevents mistakes
|
|
- ✅ **Better for learning** - understand the structure visually
|
|
- ⚠️ **Requires:** Server running, able to join in-game
|
|
|
|
**Best for:** Holly (Lead Builder) who might need to adjust permissions later
|
|
|
|
### Method B: Console Commands (Alternative - Exact & Reproducible)
|
|
- ⏱️ **Time:** 2-3 hours
|
|
- 📝 **Difficulty:** Moderate (lots of copy/paste)
|
|
- ✅ **Exact commands** - reproducible script
|
|
- ✅ **No internet upload** - stays on your servers
|
|
- ✅ **Good documentation** - can see exactly what was configured
|
|
- ⚠️ **Tedious:** ~150+ commands to paste one by one
|
|
|
|
**Best for:** Documentation purposes, automated deployment, or if you prefer terminal
|
|
|
|
---
|
|
|
|
**Choose one method below and follow those instructions:**
|
|
|
|
---
|
|
|
|
## 🌐 METHOD A: WEB EDITOR (RECOMMENDED)
|
|
|
|
### Step 1: Access the Web Editor
|
|
|
|
1. **Join any Minecraft server** (doesn't matter which - they all share the database)
|
|
2. **Run this command in-game:**
|
|
```
|
|
/lp editor
|
|
```
|
|
3. **Click the link** that appears in chat (looks like `https://luckperms.net/editor/xxxxxxxx`)
|
|
4. **Web editor opens** in your browser
|
|
|
|
**What you'll see:**
|
|
- Left sidebar: List of groups
|
|
- Main panel: Selected group's permissions and settings
|
|
- Top toolbar: Save, create group, import/export
|
|
|
|
---
|
|
|
|
### Step 2: Create Subscriber Groups
|
|
|
|
**Create these groups in order. For each group:**
|
|
1. Click **"Create Group"** button (top left)
|
|
2. Fill in the settings as shown below
|
|
3. Move to next group
|
|
|
|
---
|
|
|
|
#### Group 1: Wanderer (Free)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `wanderer`
|
|
- **Weight:** `10`
|
|
- **Display Name:** Wanderer
|
|
- **Parents:** None
|
|
|
|
**Prefix:**
|
|
- Click **"Add Prefix"**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&7[Wanderer] ` (gray color)
|
|
- Use color picker or type `&7` for gray
|
|
|
|
**Permissions:** None needed
|
|
|
|
**Notes:** Default group for non-subscribers. No server access.
|
|
|
|
---
|
|
|
|
#### Group 2: The Awakened ($1 one-time)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `awakened`
|
|
- **Weight:** `20`
|
|
- **Parents:** Click "Add Parent" → Select `wanderer`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&f[The Awakened] ` (`&f` = white)
|
|
|
|
**Permissions:**
|
|
- Click **"Add Permission"**
|
|
- Add: `ftbessentials.home.set` → Set to `true`
|
|
- Add: `ftbessentials.home.teleport` → Set to `true`
|
|
|
|
**Meta (Data):**
|
|
- Click **"Add Meta"**
|
|
- **Key:** `max-homes` | **Value:** `1`
|
|
|
|
**Notes:** Entry tier. Gets server whitelist access and 1 home only.
|
|
|
|
---
|
|
|
|
#### Group 3: Fire Elemental ($5/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `fire_elemental`
|
|
- **Weight:** `30`
|
|
- **Parents:** `awakened`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&c[🔥 Fire Elemental] ` (`&c` = red/fire orange)
|
|
- You can paste the 🔥 emoji directly
|
|
|
|
**Permissions:**
|
|
- `ftbchunks.claim` → `true`
|
|
- `ftbessentials.rtp` → `true`
|
|
|
|
**Meta:**
|
|
- `max-homes` → `5`
|
|
- `max-claimed-chunks` → `25`
|
|
- `rtp-cooldown` → `3600` (60 minutes in seconds)
|
|
|
|
---
|
|
|
|
#### Group 4: Frost Elemental ($5/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `frost_elemental`
|
|
- **Weight:** `30`
|
|
- **Parents:** `awakened`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&b[❄️ Frost Elemental] ` (`&b` = cyan/frost blue)
|
|
|
|
**Permissions:**
|
|
- `ftbchunks.claim` → `true`
|
|
- `ftbessentials.rtp` → `true`
|
|
|
|
**Meta:**
|
|
- `max-homes` → `5`
|
|
- `max-claimed-chunks` → `25`
|
|
- `rtp-cooldown` → `3600`
|
|
|
|
**Notes:** Same perks as Fire Elemental, different path/color.
|
|
|
|
---
|
|
|
|
#### Group 5: Fire Knight ($10/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `fire_knight`
|
|
- **Weight:** `40`
|
|
- **Parents:** `fire_elemental`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&c[🔥 Fire Knight] `
|
|
|
|
**Meta:**
|
|
- `max-homes` → `10`
|
|
- `max-claimed-chunks` → `49`
|
|
- `max-force-loaded-chunks` → `4`
|
|
- `rtp-cooldown` → `1800` (30 minutes)
|
|
|
|
**Permissions:** Inherits from Fire Elemental (no new permissions needed)
|
|
|
|
---
|
|
|
|
#### Group 6: Frost Knight ($10/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `frost_knight`
|
|
- **Weight:** `40`
|
|
- **Parents:** `frost_elemental`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&b[❄️ Frost Knight] `
|
|
|
|
**Meta:**
|
|
- `max-homes` → `10`
|
|
- `max-claimed-chunks` → `49`
|
|
- `max-force-loaded-chunks` → `4`
|
|
- `rtp-cooldown` → `1800`
|
|
|
|
---
|
|
|
|
#### Group 7: Fire Master ($15/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `fire_master`
|
|
- **Weight:** `50`
|
|
- **Parents:** `fire_knight`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&c[🔥 Fire Master] `
|
|
|
|
**Meta:**
|
|
- `max-homes` → `20`
|
|
- `max-claimed-chunks` → `100`
|
|
- `max-force-loaded-chunks` → `9`
|
|
- `rtp-cooldown` → `900` (15 minutes)
|
|
|
|
---
|
|
|
|
#### Group 8: Frost Master ($15/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `frost_master`
|
|
- **Weight:** `50`
|
|
- **Parents:** `frost_knight`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&b[❄️ Frost Master] `
|
|
|
|
**Meta:**
|
|
- `max-homes` → `20`
|
|
- `max-claimed-chunks` → `100`
|
|
- `max-force-loaded-chunks` → `9`
|
|
- `rtp-cooldown` → `900`
|
|
|
|
---
|
|
|
|
#### Group 9: Fire Legend ($20/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `fire_legend`
|
|
- **Weight:** `60`
|
|
- **Parents:** `fire_master`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&c[🔥 Fire Legend] `
|
|
|
|
**Meta:**
|
|
- `max-homes` → `35`
|
|
- `max-claimed-chunks` → `121`
|
|
- `max-force-loaded-chunks` → `16`
|
|
- `rtp-cooldown` → `600` (10 minutes)
|
|
|
|
---
|
|
|
|
#### Group 10: Frost Legend ($20/month)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `frost_legend`
|
|
- **Weight:** `60`
|
|
- **Parents:** `frost_master`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&b[❄️ Frost Legend] `
|
|
|
|
**Meta:**
|
|
- `max-homes` → `35`
|
|
- `max-claimed-chunks` → `121`
|
|
- `max-force-loaded-chunks` → `16`
|
|
- `rtp-cooldown` → `600`
|
|
|
|
---
|
|
|
|
#### Group 11: Sovereign ($499 lifetime)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `sovereign`
|
|
- **Weight:** `100`
|
|
- **Parents:** `awakened` (not Legend - Sovereign is separate from paths)
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&6[⚡ Sovereign] ` (`&6` = gold/amber)
|
|
|
|
**Permissions:**
|
|
- `ftbessentials.rtp` → `true`
|
|
- `ftbchunks.claim` → `true`
|
|
|
|
**Meta:**
|
|
- `max-homes` → `50`
|
|
- `max-claimed-chunks` → `225`
|
|
- `max-force-loaded-chunks` → `81`
|
|
- **No rtp-cooldown meta** (unlimited /rtp for Sovereign)
|
|
|
|
**Notes:** Sovereign gets BOTH Fire + Frost path access (configured in Discord, not LuckPerms).
|
|
|
|
---
|
|
|
|
### Step 3: Create Staff Groups
|
|
|
|
**CRITICAL: WorldEdit is powerful. Only staff should have access.**
|
|
|
|
#### Group 12: Builder (Holly - Lead Builder)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `builder`
|
|
- **Weight:** `1000`
|
|
- **Parents:** `default` (or none)
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&6[🔨 Builder] `
|
|
|
|
**Permissions:**
|
|
- `worldedit.*` → `true` (gives ALL WorldEdit permissions)
|
|
- `minecraft.command.gamemode` → `true`
|
|
- `ftbchunks.*` → `true`
|
|
|
|
**Meta:**
|
|
- `max-homes` → `100`
|
|
- `max-claimed-chunks` → `1000`
|
|
- `max-force-loaded-chunks` → `100`
|
|
|
|
---
|
|
|
|
#### Group 13: Owner (Michael/Frostystyle)
|
|
|
|
**Basic Settings:**
|
|
- **Name:** `owner`
|
|
- **Weight:** `10000`
|
|
- **Parents:** `builder`
|
|
|
|
**Prefix:**
|
|
- **Priority:** 100
|
|
- **Prefix:** `&c[👑 Owner] ` (`&c` = red)
|
|
|
|
**Permissions:**
|
|
- `*` → `true` (ALL permissions - full admin)
|
|
|
|
**Notes:** Owner inherits Builder's WorldEdit access plus everything else.
|
|
|
|
---
|
|
|
|
### Step 4: Deny WorldEdit to ALL Subscribers
|
|
|
|
**CRITICAL SECURITY STEP:**
|
|
|
|
For **each subscriber group** (wanderer through sovereign), add this permission:
|
|
- **Permission:** `worldedit.*`
|
|
- **Value:** `false` (red X)
|
|
|
|
**Groups to set this on:**
|
|
- wanderer
|
|
- awakened
|
|
- fire_elemental
|
|
- frost_elemental
|
|
- fire_knight
|
|
- frost_knight
|
|
- fire_master
|
|
- frost_master
|
|
- fire_legend
|
|
- frost_legend
|
|
- sovereign
|
|
|
|
**Why:** Prevents subscribers (even $499 Sovereign) from using WorldEdit to duplicate items, grief, or bypass protections.
|
|
|
|
---
|
|
|
|
### Step 5: Save and Apply
|
|
|
|
1. **Click "Save" button** (top right)
|
|
2. **Web editor generates a command** that starts with `/lp applyedits`
|
|
3. **Copy the entire command**
|
|
4. **Go back to Minecraft**
|
|
5. **Paste the command in console** (or in-game chat if you have permission)
|
|
6. **Press Enter**
|
|
|
|
**You'll see:**
|
|
```
|
|
[LuckPerms] Applied changes from editor session.
|
|
```
|
|
|
|
**Done! All 13 groups are now created and synced across all servers.**
|
|
|
|
---
|
|
|
|
### Step 6: Assign Users to Groups
|
|
|
|
**Still in Minecraft console, assign Holly and yourself:**
|
|
|
|
```
|
|
/lp user unicorn20089 parent set builder
|
|
/lp user Frostystyle parent set owner
|
|
```
|
|
|
|
**Replace `Frostystyle` with your actual Minecraft username.**
|
|
|
|
---
|
|
|
|
### Step 7: Verify Groups Exist
|
|
|
|
```
|
|
/lp listgroups
|
|
```
|
|
|
|
**You should see all 13 groups listed with their weights.**
|
|
|
|
---
|
|
|
|
## 📝 METHOD B: CONSOLE COMMANDS (ALTERNATIVE)
|
|
|
|
**If you prefer console commands over the web editor, use these commands instead.**
|
|
|
|
### Step 1: Access Server Console
|
|
|
|
1. Go to Pterodactyl Panel: https://panel.firefrostgaming.com
|
|
2. Click on any server (doesn't matter which)
|
|
3. Click **Console** tab
|
|
4. Make sure server is **running**
|
|
|
|
---
|
|
|
|
### Step 2: Run These Commands (Copy/Paste Each One)
|
|
|
|
**All commands must be run in the server console. They will sync to all 13 servers automatically via MySQL.**
|
|
|
|
---
|
|
|
|
#### Create Wanderer Group (Free Tier)
|
|
|
|
```
|
|
/lp creategroup wanderer
|
|
/lp group wanderer setweight 10
|
|
/lp group wanderer meta setprefix "&7[Wanderer] "
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Awakened Group ($1 Tier)
|
|
|
|
```
|
|
/lp creategroup awakened
|
|
/lp group awakened parent add wanderer
|
|
/lp group awakened setweight 20
|
|
/lp group awakened meta setprefix "&f[The Awakened] "
|
|
/lp group awakened permission set ftbessentials.home.set true
|
|
/lp group awakened permission set ftbessentials.home.teleport true
|
|
/lp group awakened meta setmeta max-homes 1
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Fire Elemental Group ($5/mo)
|
|
|
|
```
|
|
/lp creategroup fire_elemental
|
|
/lp group fire_elemental parent add awakened
|
|
/lp group fire_elemental setweight 30
|
|
/lp group fire_elemental meta setprefix "&c[🔥 Fire Elemental] "
|
|
/lp group fire_elemental meta setmeta max-homes 5
|
|
/lp group fire_elemental permission set ftbchunks.claim true
|
|
/lp group fire_elemental meta setmeta max-claimed-chunks 25
|
|
/lp group fire_elemental permission set ftbessentials.rtp true
|
|
/lp group fire_elemental meta setmeta rtp-cooldown 3600
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Frost Elemental Group ($5/mo)
|
|
|
|
```
|
|
/lp creategroup frost_elemental
|
|
/lp group frost_elemental parent add awakened
|
|
/lp group frost_elemental setweight 30
|
|
/lp group frost_elemental meta setprefix "&b[❄️ Frost Elemental] "
|
|
/lp group frost_elemental meta setmeta max-homes 5
|
|
/lp group frost_elemental permission set ftbchunks.claim true
|
|
/lp group frost_elemental meta setmeta max-claimed-chunks 25
|
|
/lp group frost_elemental permission set ftbessentials.rtp true
|
|
/lp group frost_elemental meta setmeta rtp-cooldown 3600
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Fire Knight Group ($10/mo)
|
|
|
|
```
|
|
/lp creategroup fire_knight
|
|
/lp group fire_knight parent add fire_elemental
|
|
/lp group fire_knight setweight 40
|
|
/lp group fire_knight meta setprefix "&c[🔥 Fire Knight] "
|
|
/lp group fire_knight meta setmeta max-homes 10
|
|
/lp group fire_knight meta setmeta max-claimed-chunks 49
|
|
/lp group fire_knight meta setmeta max-force-loaded-chunks 4
|
|
/lp group fire_knight meta setmeta rtp-cooldown 1800
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Frost Knight Group ($10/mo)
|
|
|
|
```
|
|
/lp creategroup frost_knight
|
|
/lp group frost_knight parent add frost_elemental
|
|
/lp group frost_knight setweight 40
|
|
/lp group frost_knight meta setprefix "&b[❄️ Frost Knight] "
|
|
/lp group frost_knight meta setmeta max-homes 10
|
|
/lp group frost_knight meta setmeta max-claimed-chunks 49
|
|
/lp group frost_knight meta setmeta max-force-loaded-chunks 4
|
|
/lp group frost_knight meta setmeta rtp-cooldown 1800
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Fire Master Group ($15/mo)
|
|
|
|
```
|
|
/lp creategroup fire_master
|
|
/lp group fire_master parent add fire_knight
|
|
/lp group fire_master setweight 50
|
|
/lp group fire_master meta setprefix "&c[🔥 Fire Master] "
|
|
/lp group fire_master meta setmeta max-homes 20
|
|
/lp group fire_master meta setmeta max-claimed-chunks 100
|
|
/lp group fire_master meta setmeta max-force-loaded-chunks 9
|
|
/lp group fire_master meta setmeta rtp-cooldown 900
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Frost Master Group ($15/mo)
|
|
|
|
```
|
|
/lp creategroup frost_master
|
|
/lp group frost_master parent add frost_knight
|
|
/lp group frost_master setweight 50
|
|
/lp group frost_master meta setprefix "&b[❄️ Frost Master] "
|
|
/lp group frost_master meta setmeta max-homes 20
|
|
/lp group frost_master meta setmeta max-claimed-chunks 100
|
|
/lp group frost_master meta setmeta max-force-loaded-chunks 9
|
|
/lp group frost_master meta setmeta rtp-cooldown 900
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Fire Legend Group ($20/mo)
|
|
|
|
```
|
|
/lp creategroup fire_legend
|
|
/lp group fire_legend parent add fire_master
|
|
/lp group fire_legend setweight 60
|
|
/lp group fire_legend meta setprefix "&c[🔥 Fire Legend] "
|
|
/lp group fire_legend meta setmeta max-homes 35
|
|
/lp group fire_legend meta setmeta max-claimed-chunks 121
|
|
/lp group fire_legend meta setmeta max-force-loaded-chunks 16
|
|
/lp group fire_legend meta setmeta rtp-cooldown 600
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Frost Legend Group ($20/mo)
|
|
|
|
```
|
|
/lp creategroup frost_legend
|
|
/lp group frost_legend parent add frost_master
|
|
/lp group frost_legend setweight 60
|
|
/lp group frost_legend meta setprefix "&b[❄️ Frost Legend] "
|
|
/lp group frost_legend meta setmeta max-homes 35
|
|
/lp group frost_legend meta setmeta max-claimed-chunks 121
|
|
/lp group frost_legend meta setmeta max-force-loaded-chunks 16
|
|
/lp group frost_legend meta setmeta rtp-cooldown 600
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Sovereign Group ($499 Lifetime)
|
|
|
|
```
|
|
/lp creategroup sovereign
|
|
/lp group sovereign parent add awakened
|
|
/lp group sovereign setweight 100
|
|
/lp group sovereign meta setprefix "&6[⚡ Sovereign] "
|
|
/lp group sovereign meta setmeta max-homes 50
|
|
/lp group sovereign meta setmeta max-claimed-chunks 225
|
|
/lp group sovereign meta setmeta max-force-loaded-chunks 81
|
|
/lp group sovereign permission set ftbessentials.rtp true
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Builder Staff Group (Holly)
|
|
|
|
```
|
|
/lp creategroup builder
|
|
/lp group builder setweight 1000
|
|
/lp group builder meta setprefix "&6[🔨 Builder] "
|
|
/lp group builder permission set worldedit.* true
|
|
/lp group builder permission set worldedit.navigation.* true
|
|
/lp group builder permission set worldedit.selection.* true
|
|
/lp group builder permission set worldedit.region.* true
|
|
/lp group builder permission set worldedit.clipboard.* true
|
|
/lp group builder permission set worldedit.generation.* true
|
|
/lp group builder permission set worldedit.history.* true
|
|
/lp group builder permission set worldedit.schematic.* true
|
|
/lp group builder permission set worldedit.brush.* true
|
|
/lp group builder permission set worldedit.tool.* true
|
|
/lp group builder permission set minecraft.command.gamemode true
|
|
/lp group builder permission set ftbchunks.* true
|
|
/lp group builder meta setmeta max-homes 100
|
|
/lp group builder meta setmeta max-claimed-chunks 1000
|
|
/lp group builder meta setmeta max-force-loaded-chunks 100
|
|
```
|
|
|
|
---
|
|
|
|
#### Create Owner Group (Michael/Frostystyle)
|
|
|
|
```
|
|
/lp creategroup owner
|
|
/lp group owner parent add builder
|
|
/lp group owner setweight 10000
|
|
/lp group owner meta setprefix "&c[👑 Owner] "
|
|
/lp group owner permission set * true
|
|
```
|
|
|
|
---
|
|
|
|
#### Deny WorldEdit to ALL Subscriber Groups (CRITICAL)
|
|
|
|
```
|
|
/lp group wanderer permission set worldedit.* false
|
|
/lp group awakened permission set worldedit.* false
|
|
/lp group fire_elemental permission set worldedit.* false
|
|
/lp group frost_elemental permission set worldedit.* false
|
|
/lp group fire_knight permission set worldedit.* false
|
|
/lp group frost_knight permission set worldedit.* false
|
|
/lp group fire_master permission set worldedit.* false
|
|
/lp group frost_master permission set worldedit.* false
|
|
/lp group fire_legend permission set worldedit.* false
|
|
/lp group frost_legend permission set worldedit.* false
|
|
/lp group sovereign permission set worldedit.* false
|
|
```
|
|
|
|
---
|
|
|
|
#### Assign Users to Groups
|
|
|
|
```
|
|
/lp user unicorn20089 parent set builder
|
|
/lp user Frostystyle parent set owner
|
|
```
|
|
|
|
**Replace `Frostystyle` with your actual Minecraft username.**
|
|
|
|
---
|
|
|
|
### Step 3: Verify Groups Created
|
|
|
|
```
|
|
/lp listgroups
|
|
```
|
|
|
|
**You should see all 13 groups listed.**
|
|
|
|
---
|
|
|
|
## ✅ NEXT STEP (AFTER EITHER METHOD)
|
|
|
|
Once groups are created (via web editor OR console commands), proceed to **Part 4: LuckPerms Discord Integration** to connect Discord roles to in-game groups.
|
|
|
|
---
|
|
|
|
## 🔗 PART 4: LUCKPERMS DISCORD INTEGRATION
|
|
|
|
**This connects Discord roles to LuckPerms groups.**
|
|
|
|
### Step 1: Enable Discord Integration in LuckPerms
|
|
|
|
**On EVERY server, edit `/config/luckperms/luckperms.conf`:**
|
|
|
|
**Find the section:**
|
|
```conf
|
|
# Discord integration
|
|
discord-integration {
|
|
enabled = false
|
|
}
|
|
```
|
|
|
|
**Change to:**
|
|
```conf
|
|
discord-integration {
|
|
enabled = true
|
|
|
|
# Role to group mappings
|
|
role-mappings {
|
|
# Format: "discord-role-id" = "luckperms-group"
|
|
|
|
"123456789012345678" = "awakened" # The Awakened
|
|
"234567890123456789" = "fire_elemental" # Fire Elemental
|
|
"345678901234567890" = "frost_elemental" # Frost Elemental
|
|
"456789012345678901" = "fire_knight" # Fire Knight
|
|
"567890123456789012" = "frost_knight" # Frost Knight
|
|
"678901234567890123" = "fire_master" # Fire Master
|
|
"789012345678901234" = "frost_master" # Frost Master
|
|
"890123456789012345" = "fire_legend" # Fire Legend
|
|
"901234567890123456" = "frost_legend" # Frost Legend
|
|
"012345678901234567" = "sovereign" # Sovereign
|
|
}
|
|
}
|
|
```
|
|
|
|
**Replace role IDs with the ACTUAL role IDs you copied in Part 2.**
|
|
|
|
**Save the file.**
|
|
|
|
### Step 2: Restart All Servers
|
|
|
|
**Via Pterodactyl Panel:**
|
|
|
|
1. Open each server's console
|
|
2. Click **Restart**
|
|
3. Wait for server to come back online
|
|
|
|
**Repeat for all 13 servers.**
|
|
|
|
### Step 3: Test Discord → LuckPerms Sync
|
|
|
|
**Manual test:**
|
|
|
|
1. Go to Discord
|
|
2. Manually assign yourself `The Awakened` role (right-click your name → Roles)
|
|
3. Join a Minecraft server
|
|
4. Run `/lp user YourUsername info`
|
|
5. Should show you're in the `awakened` group
|
|
|
|
**If it doesn't work:**
|
|
- Check LuckPerms config for typos in role IDs
|
|
- Check that Discord integration is enabled
|
|
- Restart the server
|
|
|
|
---
|
|
|
|
## 🪝 PART 5: PAYMENTER WEBHOOK CONFIGURATION
|
|
|
|
**This connects Paymenter to the Discord bot.**
|
|
|
|
### Step 1: Set Up Nginx Proxy (Michael's Task)
|
|
|
|
**On Command Center (where Discord bot runs):**
|
|
|
|
**Create file: `/etc/nginx/sites-available/discord-bot-webhook`**
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name webhook.firefrostgaming.com;
|
|
|
|
location / {
|
|
proxy_pass http://localhost:3100;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection 'upgrade';
|
|
proxy_set_header Host $host;
|
|
proxy_cache_bypass $http_upgrade;
|
|
}
|
|
}
|
|
```
|
|
|
|
**Enable the site:**
|
|
|
|
```bash
|
|
ln -s /etc/nginx/sites-available/discord-bot-webhook /etc/nginx/sites-enabled/
|
|
nginx -t
|
|
systemctl reload nginx
|
|
```
|
|
|
|
**Get SSL certificate:**
|
|
|
|
```bash
|
|
certbot --nginx -d webhook.firefrostgaming.com
|
|
```
|
|
|
|
**Now the webhook endpoint is:**
|
|
```
|
|
https://webhook.firefrostgaming.com/webhook/paymenter
|
|
```
|
|
|
|
### Step 2: Configure Paymenter Webhooks (Michael + Holly)
|
|
|
|
**In Paymenter admin panel:**
|
|
|
|
1. Go to **Settings** → **Webhooks**
|
|
2. Click **Add Webhook**
|
|
3. Configure:
|
|
- **URL:** `https://webhook.firefrostgaming.com/webhook/paymenter`
|
|
- **Events:**
|
|
- ✅ `subscription.created`
|
|
- ✅ `payment.completed`
|
|
- ✅ `subscription.cancelled`
|
|
- ✅ `subscription.expired`
|
|
- **Payload Format:** JSON
|
|
4. Click **Save**
|
|
|
|
### Step 3: Test Webhook
|
|
|
|
**Create a test purchase in Paymenter (use test mode if available).**
|
|
|
|
**Watch Discord bot logs:**
|
|
|
|
```bash
|
|
journalctl -u firefrost-discord-bot -f
|
|
```
|
|
|
|
**You should see:**
|
|
```
|
|
📬 Received webhook from Paymenter
|
|
📦 Event: subscription.created, Product: 2, User: 123456789012345678
|
|
✅ Added role 123456789012345678 to TestUser#1234
|
|
```
|
|
|
|
**If it works, the user should now have The Awakened role in Discord.**
|
|
|
|
**If it doesn't work:**
|
|
- Check webhook URL is correct
|
|
- Check Paymenter is sending the correct payload format
|
|
- Check Discord bot logs for errors
|
|
|
|
---
|
|
|
|
## ✅ TESTING & VERIFICATION
|
|
|
|
### End-to-End Test
|
|
|
|
**Complete flow test:**
|
|
|
|
1. **Create test user in Discord**
|
|
2. **Purchase Awakened tier ($1) in Paymenter**
|
|
3. **Verify webhook fires** (check Discord bot logs)
|
|
4. **Verify Discord role assigned** (check Discord - user should have "The Awakened" role)
|
|
5. **Join Minecraft server**
|
|
6. **Run `/lp user TestUser info`** - Should show `awakened` group
|
|
7. **Test permissions:**
|
|
- `/sethome test` - Should work (1 home allowed)
|
|
- `/sethome test2` - Should FAIL (only 1 home for Awakened)
|
|
- Try claiming chunks - Should FAIL (Awakened has 0 chunk claims)
|
|
- Try `/rtp` - Should FAIL (Awakened has no /rtp access)
|
|
|
|
**If all these work correctly, the automation is functioning!**
|
|
|
|
### Upgrade Test
|
|
|
|
**Test tier upgrade:**
|
|
|
|
1. Upgrade test user to Fire Elemental ($5/mo) in Paymenter
|
|
2. Verify Discord role changes (old role removed, new role added)
|
|
3. Join Minecraft server
|
|
4. Run `/lp user TestUser info` - Should show `fire_elemental` group
|
|
5. Test new permissions:
|
|
- `/sethome` - Should work (5 homes allowed)
|
|
- Claim chunks - Should work (25 chunks allowed)
|
|
- `/rtp` - Should work (60 minute cooldown)
|
|
|
|
### Cancellation Test
|
|
|
|
**Test subscription cancellation:**
|
|
|
|
1. Cancel test user's subscription in Paymenter
|
|
2. Verify Discord role removed
|
|
3. Join Minecraft server
|
|
4. Run `/lp user TestUser info` - Should show `wanderer` or default group
|
|
5. Test permissions:
|
|
- `/sethome` - Should FAIL (no subscription)
|
|
- Try joining server - Should be DENIED (whitelist = Awakened+ only)
|
|
|
|
---
|
|
|
|
## 🔧 TROUBLESHOOTING
|
|
|
|
### Discord Role Not Assigned After Purchase
|
|
|
|
**Symptoms:** User purchases subscription but doesn't get Discord role.
|
|
|
|
**Check:**
|
|
1. **Webhook logs:** `journalctl -u firefrost-discord-bot -f`
|
|
- Are webhooks being received?
|
|
2. **Paymenter webhook config:** Is webhook URL correct?
|
|
3. **Discord bot permissions:** Does bot have "Manage Roles" permission?
|
|
4. **Role position:** Bot's role must be ABOVE subscriber roles in Discord role hierarchy
|
|
|
|
**Solution:**
|
|
- Move bot's role to the top of the role list in Discord Server Settings
|
|
- Restart Discord bot: `systemctl restart firefrost-discord-bot`
|
|
|
|
---
|
|
|
|
### LuckPerms Not Syncing Discord Roles
|
|
|
|
**Symptoms:** User has Discord role but no in-game permissions.
|
|
|
|
**Check:**
|
|
1. **LuckPerms config:** Is Discord integration enabled?
|
|
2. **Role IDs:** Are Discord role IDs correct in luckperms.conf?
|
|
3. **Server restart:** Did you restart server after config change?
|
|
|
|
**Solution:**
|
|
- Double-check role IDs match (right-click role in Discord → Copy ID)
|
|
- Ensure luckperms.conf has correct mapping
|
|
- Restart all game servers
|
|
|
|
---
|
|
|
|
### User Can't Join Server After Subscribing
|
|
|
|
**Symptoms:** User purchased subscription, has Discord role, but can't join server.
|
|
|
|
**Check:**
|
|
1. **Whitelist status:** Is whitelist enabled on server?
|
|
2. **LuckPerms sync:** Run `/whitelist add Username` manually as test
|
|
3. **Server online:** Is server actually running?
|
|
|
|
**Solution:**
|
|
- Ensure LuckPerms-based whitelist is configured (see Server-Side Mod Deployment Guide)
|
|
- Check server console for "User not whitelisted" messages
|
|
- Manually add to whitelist temporarily while debugging
|
|
|
|
---
|
|
|
|
### Webhook Endpoint Returns 500 Error
|
|
|
|
**Symptoms:** Paymenter shows webhook failed with 500 error.
|
|
|
|
**Check:**
|
|
1. **Bot running:** `systemctl status firefrost-discord-bot`
|
|
2. **Bot logs:** `journalctl -u firefrost-discord-bot -f` for errors
|
|
3. **Nginx proxy:** Is Nginx running and proxying correctly?
|
|
|
|
**Solution:**
|
|
- Restart Discord bot
|
|
- Check bot code for syntax errors
|
|
- Test webhook manually with curl:
|
|
```bash
|
|
curl -X POST https://webhook.firefrostgaming.com/webhook/paymenter \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"event":"subscription.created","product_id":"2","discord_id":"YOUR_DISCORD_ID"}'
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 REFERENCE
|
|
|
|
### Quick Command Reference
|
|
|
|
#### Discord Bot Management
|
|
|
|
```bash
|
|
# Start bot
|
|
systemctl start firefrost-discord-bot
|
|
|
|
# Stop bot
|
|
systemctl stop firefrost-discord-bot
|
|
|
|
# Restart bot
|
|
systemctl restart firefrost-discord-bot
|
|
|
|
# View logs
|
|
journalctl -u firefrost-discord-bot -f
|
|
|
|
# Check status
|
|
systemctl status firefrost-discord-bot
|
|
```
|
|
|
|
#### LuckPerms Commands
|
|
|
|
```bash
|
|
# View user's groups
|
|
/lp user <username> info
|
|
|
|
# Manually add user to group
|
|
/lp user <username> parent add <groupname>
|
|
|
|
# Remove user from group
|
|
/lp user <username> parent remove <groupname>
|
|
|
|
# View group permissions
|
|
/lp group <groupname> permission info
|
|
|
|
# List all groups
|
|
/lp listgroups
|
|
```
|
|
|
|
---
|
|
|
|
### Subscriber Tier → Discord Role → LuckPerms Group Mapping
|
|
|
|
| Tier | Price | Discord Role | LuckPerms Group |
|
|
|------|-------|--------------|-----------------|
|
|
| Wanderer | Free | `Wanderer` | `wanderer` |
|
|
| Awakened | $1 | `The Awakened` | `awakened` |
|
|
| Fire Elemental | $5/mo | `🔥 Fire Elemental` | `fire_elemental` |
|
|
| Frost Elemental | $5/mo | `❄️ Frost Elemental` | `frost_elemental` |
|
|
| Fire Knight | $10/mo | `🔥 Fire Knight` | `fire_knight` |
|
|
| Frost Knight | $10/mo | `❄️ Frost Knight` | `frost_knight` |
|
|
| Fire Master | $15/mo | `🔥 Fire Master` | `fire_master` |
|
|
| Frost Master | $15/mo | `❄️ Frost Master` | `frost_master` |
|
|
| Fire Legend | $20/mo | `🔥 Fire Legend` | `fire_legend` |
|
|
| Frost Legend | $20/mo | `❄️ Frost Legend` | `frost_legend` |
|
|
| Sovereign | $499 | `⚡ Sovereign` | `sovereign` |
|
|
|
|
---
|
|
|
|
### File Locations Quick Reference
|
|
|
|
```
|
|
Command Center (63.143.34.217)
|
|
└── /opt/firefrost-discord-bot/
|
|
├── bot.js
|
|
├── package.json
|
|
└── node_modules/
|
|
|
|
Game Servers (TX1/NC1)
|
|
└── /config/luckperms/
|
|
└── luckperms.conf (Discord integration config)
|
|
|
|
Nginx
|
|
└── /etc/nginx/sites-available/
|
|
└── discord-bot-webhook
|
|
```
|
|
|
|
---
|
|
|
|
**End of Subscription Automation Guide**
|
|
|
|
**You've now completed the full automation setup! Users can subscribe in Paymenter and automatically get:**
|
|
- Discord role assignment
|
|
- In-game rank sync
|
|
- Correct permissions on all 13 servers
|
|
- Channel access based on Fire/Frost path
|
|
|
|
**Fire + Frost + Foundation = Where Love Builds Legacy** 🔥❄️
|
|
|
|
---
|
|
|
|
**Document Version:** 1.0
|
|
**Last Updated:** March 23, 2026
|
|
**Maintained By:** Firefrost Gaming Infrastructure Team
|