Files
firefrost-services/services/arbiter/DEPLOYMENT.md
Claude (The Golden Chronicler #50) 04e9b407d5 feat: Migrate Arbiter and Modpack Version Checker to monorepo
WHAT WAS DONE:
- Migrated Arbiter (discord-oauth-arbiter) code to services/arbiter/
- Migrated Modpack Version Checker code to services/modpack-version-checker/
- Created .env.example for Arbiter with all required environment variables
- Moved systemd service file to services/arbiter/deploy/
- Organized directory structure per Gemini monorepo recommendations

WHY:
- Consolidate all service code in one repository
- Prepare for Gemini code review (Panel v1.12 compatibility check)
- Enable service-prefixed Git tagging (arbiter-v2.1.0, modpack-v1.0.0)
- Support npm workspaces for shared dependencies

SERVICES MIGRATED:
1. Arbiter (Discord OAuth bot) - Originally written by Gemini + Claude
   - Full source code from ops-manual docs/implementation/
   - Created comprehensive .env.example
   - Ready for Panel v1.12 compatibility verification

2. Modpack Version Checker (Python CLI tool)
   - Full source code from ops-manual docs/tasks/
   - Written for Panel v1.11, needs Gemini review for v1.12
   - Never had code review before

STILL TODO:
- Whitelist Manager - Pull from Billing VPS (38.68.14.188)
  - Currently deployed and running
  - Needs Panel v1.12 API compatibility fix (Task #86)
  - Requires SSH access to pull code

NEXT STEPS:
- Gemini code review for Panel v1.12 API compatibility
- Create package.json for each service
- Test npm workspaces integration
- Deploy after verification

FILES:
- services/arbiter/ (25 new files, full application)
- services/modpack-version-checker/ (21 new files, full application)

Signed-off-by: The Golden Chronicler <claude@firefrostgaming.com>
2026-03-31 21:52:42 +00:00

579 lines
13 KiB
Markdown

# Firefrost Arbiter - Complete Deployment Guide
**Target Server:** Command Center (63.143.34.217, Dallas)
**Date:** March 30, 2026
**Prepared by:** Claude (Chronicler #49)
---
## 📋 Pre-Deployment Checklist
### Discord Configuration
- [ ] Discord Application created at discord.com/developers/applications
- [ ] Bot token generated and saved securely
- [ ] Client ID and Client Secret obtained
- [ ] Server Members Intent enabled
- [ ] Redirect URIs added:
- [ ] `https://discord-bot.firefrostgaming.com/auth/callback`
- [ ] `https://discord-bot.firefrostgaming.com/admin/callback`
- [ ] Bot invited to server with "Manage Roles" permission
- [ ] Bot role positioned ABOVE all subscription tier roles in hierarchy
### Ghost CMS Configuration
- [ ] Custom field `discord_id` created (Settings → Membership → Custom Fields)
- [ ] Custom Integration created: "Firefrost Arbiter"
- [ ] Admin API Key copied (format: `key_id:secret`)
### Server Configuration
- [ ] Node.js 18.x installed
- [ ] Nginx installed and running
- [ ] UFW firewall configured (ports 80, 443, 3500 if needed)
- [ ] Let's Encrypt SSL certificate obtained for `discord-bot.firefrostgaming.com`
- [ ] User `architect` exists with sudo privileges
### Credentials Prepared
- [ ] Discord Bot Token
- [ ] Discord Client ID
- [ ] Discord Client Secret
- [ ] Discord Guild ID (server ID)
- [ ] Trinity Discord IDs (Michael, Meg, Holly)
- [ ] Ghost CMS URL
- [ ] Ghost Admin API Key
- [ ] Mailcow SMTP password
- [ ] Paymenter webhook secret
- [ ] SESSION_SECRET generated (32-byte random)
---
## 🚀 Phase 1: Initial Setup
### Step 1: Connect to Server
```bash
ssh architect@63.143.34.217
```
### Step 2: Create Application Directory
```bash
cd /home/architect
mkdir -p arbiter
cd arbiter
```
### Step 3: Upload Application Files
**From your local machine:**
```bash
# If using git
git clone <repository-url> /home/architect/arbiter
# Or if uploading manually via scp
scp -r discord-oauth-implementation/* architect@63.143.34.217:/home/architect/arbiter/
```
### Step 4: Install Dependencies
```bash
cd /home/architect/arbiter
npm install
```
**Expected output:**
```
added 87 packages in 12s
```
### Step 5: Create Environment File
```bash
cp .env.example .env
nano .env
```
**Fill in ALL values:**
```bash
NODE_ENV=production
PORT=3500
APP_URL=https://discord-bot.firefrostgaming.com
SESSION_SECRET=<generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))">
DISCORD_BOT_TOKEN=<from Discord Developer Portal>
DISCORD_CLIENT_ID=<from Discord Developer Portal>
DISCORD_CLIENT_SECRET=<from Discord Developer Portal>
GUILD_ID=<your Discord server ID>
ADMIN_DISCORD_IDS=<michael_id>,<meg_id>,<holly_id>
CMS_URL=https://firefrostgaming.com
CMS_ADMIN_KEY=<from Ghost Integrations>
SMTP_HOST=38.68.14.188
SMTP_USER=noreply@firefrostgaming.com
SMTP_PASS=<from Mailcow>
WEBHOOK_SECRET=<from Paymenter>
```
**Generate SESSION_SECRET:**
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```
**Save and exit:** `Ctrl+X`, `Y`, `Enter`
### Step 6: Configure Discord Role Mapping
```bash
nano config/roles.json
```
**Get Discord Role IDs:**
1. Go to Discord server
2. Settings → Roles
3. Right-click each role → Copy ID
**Fill in the file:**
```json
{
"awakened": "1234567890123456789",
"fire_elemental": "2345678901234567890",
"frost_elemental": "3456789012345678901",
"fire_knight": "4567890123456789012",
"frost_knight": "5678901234567890123",
"fire_master": "6789012345678901234",
"frost_master": "7890123456789012345",
"fire_legend": "8901234567890123456",
"frost_legend": "9012345678901234567",
"sovereign": "0123456789012345678"
}
```
**Save and exit**
### Step 7: Set Permissions
```bash
chmod 600 .env
chmod +x backup.sh
```
---
## 🌐 Phase 2: Nginx Configuration
### Step 1: Copy Nginx Config
```bash
sudo cp nginx.conf /etc/nginx/sites-available/arbiter
sudo ln -s /etc/nginx/sites-available/arbiter /etc/nginx/sites-enabled/
```
### Step 2: Test Nginx Configuration
```bash
sudo nginx -t
```
**Expected output:**
```
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
### Step 3: Reload Nginx
```bash
sudo systemctl reload nginx
```
---
## ⚙️ Phase 3: Systemd Service Setup
### Step 1: Copy Service File
```bash
sudo cp arbiter.service /etc/systemd/system/
```
### Step 2: Reload Systemd
```bash
sudo systemctl daemon-reload
```
### Step 3: Enable Service (Start on Boot)
```bash
sudo systemctl enable arbiter
```
### Step 4: Start Service
```bash
sudo systemctl start arbiter
```
### Step 5: Check Status
```bash
sudo systemctl status arbiter
```
**Expected output:**
```
● arbiter.service - Firefrost Arbiter - Discord Role Management System
Loaded: loaded (/etc/systemd/system/arbiter.service; enabled)
Active: active (running) since Sun 2026-03-30 10:00:00 CDT; 5s ago
Main PID: 12345 (node)
Tasks: 11 (limit: 9830)
Memory: 45.2M
CGroup: /system.slice/arbiter.service
└─12345 /usr/bin/node src/index.js
Mar 30 10:00:00 command-center systemd[1]: Started Firefrost Arbiter.
Mar 30 10:00:00 command-center arbiter[12345]: [Server] Listening on port 3500
Mar 30 10:00:01 command-center arbiter[12345]: [Discord] Bot logged in as ArbiterBot#1234
Mar 30 10:00:01 command-center arbiter[12345]: [Database] Cleaned up 0 expired tokens.
```
**If status shows "failed":**
```bash
sudo journalctl -u arbiter -n 50
```
---
## ✅ Phase 4: Validation & Testing
### Step 1: Check Application Logs
```bash
sudo journalctl -u arbiter -f
```
**Look for:**
- `[Server] Listening on port 3500`
- `[Discord] Bot logged in as <BotName>`
- `[Database] Cleaned up X expired tokens`
**Press Ctrl+C to exit**
### Step 2: Test Health Endpoint
```bash
curl https://discord-bot.firefrostgaming.com/health
```
**Expected response:**
```json
{
"uptime": 123.456,
"discord": "ok",
"database": "ok",
"timestamp": "2026-03-30T15:00:00.000Z"
}
```
**If you get 502 Bad Gateway:**
- Check application is running: `sudo systemctl status arbiter`
- Check application logs: `sudo journalctl -u arbiter -n 50`
- Check Nginx is running: `sudo systemctl status nginx`
### Step 3: Test Webhook Reception (Local)
```bash
curl -X POST http://localhost:3500/webhook/billing \
-H "Content-Type: application/json" \
-d '{
"event": "subscription.created",
"customer_email": "test@firefrostgaming.com",
"customer_name": "Test User",
"tier": "awakened",
"subscription_id": "test_sub_123"
}'
```
**Check logs:**
```bash
sudo journalctl -u arbiter -n 20
```
**Look for:**
- `[Webhook] Received subscription.created for test@firefrostgaming.com`
- `[Webhook] Sent linking email to test@firefrostgaming.com`
**Check database:**
```bash
sqlite3 linking.db "SELECT * FROM link_tokens;"
```
Should show newly created token.
### Step 4: Test Admin OAuth Login
1. Visit `https://discord-bot.firefrostgaming.com/admin/login` in browser
2. Should redirect to Discord OAuth
3. Authorize with Trinity Discord account
4. Should redirect to admin panel
5. Verify search, assign functions work
### Step 5: End-to-End OAuth Test
**Create test member in Ghost CMS:**
1. Ghost Admin → Members → New Member
2. Email: `test@firefrostgaming.com`
3. Name: "Test User"
**Trigger webhook:**
```bash
curl -X POST http://localhost:3500/webhook/billing \
-H "Content-Type: application/json" \
-d '{
"event": "subscription.created",
"customer_email": "test@firefrostgaming.com",
"customer_name": "Test User",
"tier": "awakened",
"subscription_id": "test_001"
}'
```
**Check Mailcow logs for sent email:**
```bash
ssh root@38.68.14.188
docker logs -f --tail 50 mailcowdockerized_postfix-mailcow_1
```
**Copy linking URL from email (or get from database):**
```bash
sqlite3 linking.db "SELECT token FROM link_tokens WHERE email='test@firefrostgaming.com';"
```
**Build link:**
```
https://discord-bot.firefrostgaming.com/link?token=<token>
```
**Test flow:**
1. Visit link in browser
2. Should redirect to Discord OAuth
3. Authorize with test Discord account
4. Should show success page
5. Check Discord - test account should have "The Awakened" role
6. Check Ghost Admin - test member should have `discord_id` populated
---
## 💾 Phase 5: Backup Configuration
### Step 1: Create Backup Directory
```bash
mkdir -p /home/architect/backups/arbiter
chmod 700 /home/architect/backups/arbiter
```
### Step 2: Test Backup Script
```bash
cd /home/architect/arbiter
./backup.sh
```
**Check output:**
```bash
cat /home/architect/backups/arbiter/backup_log.txt
```
Should show:
```
--- Backup Started: 20260330_100000 ---
Backup completed successfully.
```
**Verify backup files exist:**
```bash
ls -lh /home/architect/backups/arbiter/
```
Should show:
```
-rw-r--r-- 1 architect architect 12K Mar 30 10:00 linking_20260330_100000.db
-rw-r--r-- 1 architect architect 4.0K Mar 30 10:00 sessions_20260330_100000.db
-rw------- 1 architect architect 892 Mar 30 10:00 env_20260330_100000.bak
-rw-r--r-- 1 architect architect 421 Mar 30 10:00 roles_20260330_100000.json
```
### Step 3: Schedule Daily Backups
```bash
crontab -e
```
**Add this line:**
```
0 4 * * * /home/architect/arbiter/backup.sh >> /home/architect/backups/arbiter/cron_error.log 2>&1
```
**Save and exit**
**Verify cron job:**
```bash
crontab -l
```
Should show the backup line.
---
## 🔗 Phase 6: Paymenter Integration
### Step 1: Configure Paymenter Webhook
1. Log in to Paymenter admin panel
2. Navigate to: System → Webhooks
3. Click "Add Webhook"
4. **URL:** `https://discord-bot.firefrostgaming.com/webhook/billing`
5. **Secret:** (use value from `.env` WEBHOOK_SECRET)
6. **Events:** Select:
- `subscription.created`
- `subscription.upgraded`
- `subscription.downgraded`
- `subscription.cancelled`
7. Save webhook
### Step 2: Test Paymenter Webhook
**From Paymenter admin:**
1. Find webhook in list
2. Click "Test Webhook"
3. Should show successful delivery
**Or manually trigger:**
```bash
curl -X POST https://discord-bot.firefrostgaming.com/webhook/billing \
-H "Content-Type: application/json" \
-H "x-signature: <generate_valid_hmac>" \
-d '{
"event": "subscription.created",
"customer_email": "real_customer@example.com",
"customer_name": "Real Customer",
"tier": "awakened",
"subscription_id": "sub_real_123"
}'
```
---
## 📊 Phase 7: Monitoring Setup
### Step 1: Set Up Log Rotation
```bash
sudo nano /etc/logrotate.d/arbiter
```
**Add:**
```
/var/log/nginx/arbiter-*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
systemctl reload nginx > /dev/null
endscript
}
```
### Step 2: Create Monitoring Script (Optional)
```bash
nano /home/architect/arbiter/monitor.sh
```
**Add:**
```bash
#!/bin/bash
STATUS=$(curl -s https://discord-bot.firefrostgaming.com/health | jq -r '.discord')
if [ "$STATUS" != "ok" ]; then
echo "Arbiter health check failed at $(date)" >> /home/architect/arbiter/monitor.log
sudo systemctl restart arbiter
fi
```
**Make executable:**
```bash
chmod +x /home/architect/arbiter/monitor.sh
```
**Schedule (every 5 minutes):**
```bash
crontab -e
```
**Add:**
```
*/5 * * * * /home/architect/arbiter/monitor.sh
```
---
## 🎉 Deployment Complete!
### Final Checklist
- [ ] Application running (`sudo systemctl status arbiter`)
- [ ] Health check returns "ok" for all services
- [ ] Test webhook received and logged
- [ ] Test OAuth flow completes successfully
- [ ] Admin panel accessible and functional
- [ ] Backups scheduled and tested
- [ ] Paymenter webhook configured
- [ ] Logs rotating properly
### Next Steps
1. **Monitor for 24 hours** before announcing to users
2. **Create test subscription** with real Paymenter flow
3. **Verify email delivery** reaches inbox (not spam)
4. **Test all subscription events** (upgrade, downgrade, cancel)
5. **Train Trinity members** on admin panel usage
6. **Update documentation** with any deployment-specific notes
### Rollback Plan (If Issues Occur)
```bash
# Stop service
sudo systemctl stop arbiter
# Disable service
sudo systemctl disable arbiter
# Remove Nginx config
sudo rm /etc/nginx/sites-enabled/arbiter
sudo systemctl reload nginx
# Application files remain in /home/architect/arbiter for debugging
```
---
## 📞 Support Contacts
**System Administrator:** Michael (The Wizard)
**Implementation Partner:** Claude (Chronicler #49)
**Architecture Consultant:** Gemini AI
**Documentation:** `/home/architect/arbiter/README.md`
**Troubleshooting:** `/home/architect/arbiter/TROUBLESHOOTING.md`
---
**🔥❄️ Deployment completed by Chronicler #49 on March 30, 2026 💙**