Files
firefrost-operations-manual/docs/planning/dynamic-servers-page-implementation.md
Claude (Chronicler #56) 7c638ee68a docs: complete dynamic Servers page implementation plan
WHAT WAS DONE:
Created comprehensive implementation plan for dynamic Servers page using
Cloudflare Workers + Pterodactyl Client API. Includes complete Gemini AI
consultation archive with architectural recommendations.

NEW DOCUMENTATION:
1. docs/planning/dynamic-servers-page-implementation.md (737 lines)
   - Executive summary and architecture overview
   - 12-day implementation timeline (April 3-15, 2026)
   - Phase-by-phase task breakdown
   - Security considerations and RV travel requirements
   - Caching strategy and performance metrics
   - Success criteria and monitoring setup

2. docs/planning/gemini-servers-consultation/
   - 01-initial-consultation.md (original prompt to Gemini)
   - 02-followup-questions.md (7 technical clarification questions)
   - 03-gemini-initial-response.md (Cloudflare Workers architecture)
   - 04-gemini-followup-response.md (implementation Q&A)

KEY ARCHITECTURAL DECISIONS:
-  Cloudflare Workers (serverless, zero maintenance, RV-ready)
-  Pterodactyl Client API (not Application API!)
-  Service Account pattern (read-only permissions)
-  Edge caching (60 seconds, protects Pterodactyl from traffic spikes)
-  Pipe-delimited naming: 'Modpack Name | vX.Y.Z'

IMPLEMENTATION PHASES:
Phase 1 (Apr 3-4): Pterodactyl Service Account setup
Phase 2 (Apr 4-6): Local Worker development with Wrangler
Phase 3 (Apr 7-9): Deploy Worker to production
Phase 4 (Apr 9-11): Frontend integration + testing
Phase 5 (Apr 11-12): Uptime Kuma monitoring setup
Phase 6 (Apr 14): DNS cutover to firefrostgaming.com

EASY WINS TO ADD:
- Copy Server IP button (clipboard.writeText)
- Auto-refresh every 60 seconds (setInterval)
- Pulse animation for online status (CSS provided)

SKIP (TOO COMPLEX):
- Historical uptime tracking (requires database)
- Live console output (security risk + WebSocket complexity)

GEMINI VALIDATION:
'Your timeline is highly realistic. Get that Service Account created
today, mock up the .dev.vars this weekend, and you'll be coasting into
April 15.'

Butter No Nutters (CEO) has granted royal approval on architecture. 😺👑

This is the final blocker before soft launch. Once implemented, Servers
page will auto-update when infrastructure changes - zero manual edits
required.

Fire + Frost + Foundation = Where Love Builds Legacy 💙

Signed-off-by: Claude (Chronicler #56) <claude@firefrostgaming.com>
2026-04-03 03:22:31 +00:00

18 KiB

Dynamic Servers Page Implementation Plan

Created: April 3, 2026
Status: Ready for Implementation
Target Launch: April 15, 2026 (12 days)
Architecture: Cloudflare Workers + Pterodactyl Client API


Executive Summary

The Problem: The Servers page is currently static HTML. Every time we add/remove/modify a Minecraft server, we must manually edit website code and redeploy. This is unsustainable for a hosting company.

The Solution: Cloudflare Workers acting as a serverless proxy between the website and Pterodactyl Panel. The Worker fetches live server status from Pterodactyl's Client API, caches at the edge for 60 seconds, and serves JSON to the frontend. Zero manual updates required.

Why This Architecture:

  • Serverless: No VPS to maintain (critical for RV travel!)
  • Secure: API keys hidden in Worker environment variables
  • Fast: Edge caching protects Pterodactyl from traffic spikes
  • Free: Cloudflare Workers free tier covers our needs
  • RV-Ready: Fully decoupled, graceful degradation if panel goes down

Architecture Overview

User Browser
    ↓
firefrostgaming.com/servers (11ty static page)
    ↓ (JavaScript fetch)
Cloudflare Worker (https://servers-api.YOUR-WORKER.workers.dev)
    ↓ (Server-side API call, API key hidden)
Pterodactyl Client API (/api/client/servers)
    ↓ (Returns server list + live status)
Worker (caches for 60 seconds at edge)
    ↓
JSON response → Browser renders

Key Insight from Gemini: If 1,000 users hit the site simultaneously, the FIRST user triggers the Worker → Pterodactyl API call (400ms). The remaining 999 users get cached data from Cloudflare's edge in ~10ms. Pterodactyl only gets hit once per minute regardless of traffic!


Critical Pterodactyl API Distinction

Two APIs, Two Purposes

Application API (Admin) - ptla_ prefix:

  • Used for administrative tasks
  • Lists ALL servers regardless of owner
  • Cannot provide real-time player counts or live stats
  • Good for: Trinity Panel monitoring, server creation/deletion

Client API (User-Facing) - ptlc_ prefix:

  • Used for end-user access
  • Only shows servers the user has access to
  • Provides /resources endpoint with live stats
  • Good for: Website status display, player counts

We need the Client API for the website!


Implementation Plan (12 Days)

Phase 1: Pterodactyl Setup (April 3-4)

Task 1.1: Check Existing API Key Type

# Look at Trinity Panel API key
# If it starts with ptla_ = Application API (wrong for this!)
# If it starts with ptlc_ = Client API (perfect!)

Task 1.2: Create Service Account

  1. Log into Pterodactyl Admin panel (https://panel.firefrostgaming.com)
  2. Go to Users → Create new user:
    • Username: website-api
    • Email: website-api@firefrostgaming.com
    • Password: (generate secure password)
  3. For EACH Minecraft server we want public:
    • Go to Servers in Admin panel
    • Click the server
    • Go to Subusers tab
    • Add website-api@firefrostgaming.com
    • Grant ONLY these permissions:
      • View Server
      • View Server Statistics
      • Everything else (no control permissions!)
  4. Log out of Admin account
  5. Log in as website-api@firefrostgaming.com
  6. Go to Account Settings → API Credentials
  7. Create new Client API key
  8. SAVE THIS KEY! It starts with ptlc_

Task 1.3: Standardize Server Descriptions Update ALL Minecraft server descriptions in Pterodactyl to follow this format:

All The Mods 10 | v1.0.9
Stoneblock 3 | v1.2.4
Project Architect 2 | v2.0.1
Society | v1.1.0
Mythcraft | v2.3.1
All The Mons | v1.0.5

Format: Modpack Name | v[Version]

Why pipe-delimited:

  • Clean, readable in Pterodactyl UI
  • Easy JavaScript parsing: const [name, version] = desc.split(' | ');
  • No special characters that break JSON

Phase 2: Local Development (April 4-6)

Task 2.1: Install Wrangler CLI

npm install -g wrangler

Task 2.2: Create Worker Project

mkdir cloudflare-workers
cd cloudflare-workers
mkdir servers-api
cd servers-api
wrangler init

Task 2.3: Create .dev.vars (Local Secrets) Create file: .dev.vars in worker directory:

PANEL_URL="https://panel.firefrostgaming.com"
CLIENT_API_KEY="ptlc_YOUR_ACTUAL_KEY_HERE"

IMPORTANT: Add .dev.vars to .gitignore - NEVER commit secrets!

Task 2.4: Write Worker Code See cloudflare-worker-code.js in this directory for complete code.

Key features:

  • Fetches from Pterodactyl Client API /api/client endpoint
  • Gets live server list
  • For each server, fetches /resources endpoint for status
  • Returns JSON with server name, status, players, description
  • Handles CORS for firefrostgaming.com
  • Edge caching: 60 seconds
  • Graceful error handling if panel is down

Task 2.5: Test Locally

wrangler dev
# Worker runs at http://localhost:8787
# Open browser, test endpoint
# Verify JSON structure matches expectations

Test cases:

  • All servers listed
  • Online/Offline status correct
  • Player counts (if available)
  • Modpack names parsed correctly
  • CORS headers present
  • Error handling works (simulate panel down)

Phase 3: Deploy to Production (April 7-9)

Task 3.1: Deploy Worker

wrangler deploy

Output will be: https://servers-api.YOUR-WORKER.workers.dev

Task 3.2: Configure Production Secrets

wrangler secret put PANEL_URL
# Enter: https://panel.firefrostgaming.com

wrangler secret put CLIENT_API_KEY
# Paste the ptlc_ key

Task 3.3: Test Production Worker

curl https://servers-api.YOUR-WORKER.workers.dev
# Should return JSON with all servers

Task 3.4: Update Cloudflare Worker Settings

  • Go to Cloudflare Dashboard → Workers
  • Click servers-api
  • Settings → Triggers → Add custom domain (optional): api.firefrostgaming.com
  • Verify CORS settings

Phase 4: Frontend Integration (April 9-11)

Task 4.1: Update servers.njk See servers-page-frontend.html in this directory for complete code.

Key features:

  • Static HTML container
  • JavaScript fetches from Worker on page load
  • Renders server cards dynamically
  • "Pulse" animation for online status (Frost cyan)
  • Offline status in Fire orange
  • Player count display (if available)
  • Error handling with friendly message
  • Auto-refresh every 60 seconds

Task 4.2: Add Easy Wins

  1. Copy IP Button:
<button onclick="navigator.clipboard.writeText('atm10.firefrostgaming.com')">
  Copy Server IP
</button>
  1. Auto-Refresh:
setInterval(() => {
  fetch(WORKER_URL).then(/* update UI */);
}, 60000); // Every 60 seconds

Task 4.3: Test on Preview

  1. Commit changes to git
  2. Push to Gitea (auto-deploys to GitHub → Cloudflare Pages)
  3. Wait 60-90 seconds
  4. Test https://firefrost-website.pages.dev/servers
  5. Verify on multiple devices:
    • Desktop (Firefox, Chrome)
    • Mobile (Michael's phone, Meg's phone)
    • Tablet

Test checklist:

  • All servers display
  • Status indicators correct (green pulse = online, red = offline)
  • Player counts showing (if Pterodactyl provides them)
  • Copy IP buttons work
  • Auto-refresh updates without page reload
  • Mobile responsive (no horizontal scroll!)
  • Error message displays if Worker fails
  • Loading state shows during fetch

Phase 5: Monitoring Setup (April 11-12)

Task 5.1: Uptime Kuma Monitoring

  1. Log into Uptime Kuma (Command Center)
  2. Add new monitor:
    • Name: "Servers API Worker"
    • Type: HTTP(s)
    • URL: https://servers-api.YOUR-WORKER.workers.dev
    • Interval: 120 seconds (2 minutes)
    • Retries: 3
  3. Set up Discord notification:
    • Webhook URL: (Trinity Discord channel)
    • Alert on: Down, Error, Recovery

Task 5.2: Worker Error Webhook (Optional) Add Discord webhook to Worker error handler:

catch (error) {
  // Alert Discord that Worker failed
  fetch('https://discord.com/api/webhooks/YOUR_WEBHOOK', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      content: '🚨 Servers API Worker failed to reach Pterodactyl Panel!'
    })
  });
  
  // Return graceful error to users
  return new Response(JSON.stringify({
    error: "Servers temporarily unreachable",
    servers: []
  }), { status: 500 });
}

Task 5.3: Cloudflare Analytics

  1. Go to Cloudflare Dashboard → Workers → servers-api
  2. View Analytics tab
  3. Monitor:
    • Request count
    • Error rate
    • CPU time usage
    • P95 response time

Target metrics:

  • Error rate: <1%
  • Response time: <500ms
  • CPU time: <5ms (network time doesn't count)

Phase 6: DNS Cutover (April 14)

CRITICAL: Do NOT attempt DNS cutover until Servers page tested thoroughly on preview!

Pre-Flight Checklist:

  • Cloudflare Worker deployed and tested
  • servers.njk updated and tested on preview
  • All 7 pages working on firefrost-website.pages.dev
  • Mobile responsive verified
  • Uptime Kuma monitoring active
  • Discord alerts tested
  • Michael + Meg + Holly have reviewed site
  • Paymenter subscription links verified
  • /discord redirect working

DNS Cutover Steps:

  1. Log into Cloudflare Dashboard
  2. Go to Workers & Pages → firefrost-website
  3. Settings → Domains → Add custom domain
  4. Enter: firefrostgaming.com
  5. Cloudflare provisions SSL certificate (1-5 minutes)
  6. Wait for edge network propagation (5-15 minutes)
  7. Test: Visit https://firefrostgaming.com
  8. Verify all pages load correctly
  9. Check Servers page specifically

Expected "routing weirdness" (Gemini's warning):

  • First 5-15 minutes: Some users may see old Ghost site, some see new 11ty site
  • After 15 minutes: All users see new site
  • This is normal edge network propagation

Rollback Plan (if needed):

  1. Remove custom domain from Cloudflare Pages
  2. Old Ghost site becomes active again
  3. Debug issue
  4. Try cutover again when ready

Player Count Nuance (Important!)

From Gemini:

The Client API does return a players integer under attributes.resources.players. However, Pterodactyl's Wings daemon gets this number by passively querying the Minecraft server. For heavily modded servers (like ATM10), the server query port sometimes hangs or reports 0 even when players are online.

Strategy:

  1. MVP (Launch): Show player counts IF Pterodactyl provides them
  2. Monitor: Watch for false zeros (server shows "0 players" but you know people are online)
  3. If unreliable: Remove player count display post-launch
  4. DO NOT: Try to build custom RCON/Query proxy 12 days before launch

Keep it simple: Online/Offline status is the MVP. Player counts are a nice-to-have.


Server Naming Convention (Enforced Standard)

Format: Modpack Name | v[Version]

Examples:

All The Mods 10 | v1.0.9
Stoneblock 3 | v1.2.4
Project Architect 2 | v2.0.1
Society | v1.1.0
Mythcraft | v2.3.1
All The Mons | v1.0.5

JavaScript parsing:

const description = "All The Mods 10 | v1.0.9";
const [modpackName, version] = description.split(' | ');
// modpackName = "All The Mods 10"
// version = "v1.0.9"

Where to store: Pterodactyl Server Description field (visible in Client API)

Maintenance: When adding new servers, Michael MUST follow this format for automatic website updates!


Caching Strategy

Cache-Control Header:

'Cache-Control': 'public, s-maxage=60, max-age=60'

What this means:

  • public: Anyone can cache this
  • s-maxage=60: Cloudflare Edge caches for 60 seconds
  • max-age=60: User's browser caches for 60 seconds

Traffic pattern example:

Time 00:00 - User A visits → Worker executes → Pterodactyl queried → Result cached
Time 00:15 - User B visits → Cloudflare Edge returns cached data (no Worker execution!)
Time 00:30 - User C visits → Cloudflare Edge returns cached data (no Worker execution!)
Time 00:45 - User D visits → Cloudflare Edge returns cached data (no Worker execution!)
Time 01:01 - User E visits → Cache expired → Worker executes → Pterodactyl queried → New cache

Result: Pterodactyl only gets hit ONCE per minute, regardless of website traffic!

Why 60 seconds is acceptable: Minecraft server status doesn't change rapidly. If a server goes down, users will see the old "Online" status for up to 60 seconds max. This is totally fine for this use case.


Future Enhancements (Post-Launch)

Easy Wins (Add These!)

  1. Copy IP Button - One line of JavaScript
  2. Auto-Refresh - setInterval every 60 seconds
  3. Status Pulse Animation - CSS keyframe already provided

⚠️ Possible But Complex

  1. Modpack logos - Would need image hosting, careful sizing
  2. Server tags - Requires Pterodactyl custom fields
  3. "Last seen online" - Requires tracking state changes

Architectural Nightmares (Skip!)

  1. Historical uptime tracking - Needs database (kills static site)
  2. Live console output - Security risk + WebSocket complexity
  3. Custom RCON integration - Over-engineering for MVP

Philosophy: Ship the MVP. Add features iteratively after launch based on actual user feedback.


Security Considerations

API Key Protection

  • Client API key stored in Cloudflare Worker environment variables
  • Never exposed to browser
  • .dev.vars file in .gitignore
  • Service Account has minimal permissions (read-only)

CORS Configuration

  • Only allows https://firefrostgaming.com origin
  • Rejects requests from other domains
  • Handles OPTIONS preflight requests

Rate Limiting

  • Edge caching prevents API abuse
  • Pterodactyl only hit once per minute max
  • No user can DOS the panel through the website

Error Disclosure

  • Generic error messages to users ("Servers temporarily unreachable")
  • Never expose API endpoints or keys in error messages
  • Detailed errors logged to Cloudflare Analytics only

RV Travel Considerations

Why this architecture works for remote operation:

  1. Zero VPS dependencies: Worker is serverless, no SSH needed
  2. Automatic recovery: If panel goes down temporarily, Worker error handling keeps site usable
  3. Push notifications: Discord webhooks alert Michael/Meg immediately
  4. Edge monitoring: Uptime Kuma on Command Center watches Worker health
  5. Simple troubleshooting: Only 3 moving parts (Worker, Pterodactyl, Frontend)

Troubleshooting from the road:

  • Panel down? Uptime Kuma + Discord alert
  • Worker failing? Cloudflare Dashboard shows errors
  • Website broken? Cloudflare Pages deployment logs
  • All accessible via phone/tablet over cellular!

Timeline & Milestones

April 3 (Today):

  • Check existing API key type
  • Create Service Account in Pterodactyl
  • Standardize server descriptions

April 4-6 (Weekend):

  • Install Wrangler CLI
  • Build Worker locally
  • Test with real Pterodactyl API

April 7-9:

  • Deploy Worker to production
  • Configure secrets
  • Test Worker endpoint

April 9-11:

  • Update servers.njk frontend
  • Add Copy IP + Auto-refresh features
  • Test on preview extensively

April 11-12:

  • Set up Uptime Kuma monitoring
  • Configure Discord alerts
  • Final QA testing

April 14:

  • Pre-flight checklist verification
  • DNS cutover to firefrostgaming.com
  • 🎉 SOFT LAUNCH!

April 15:

  • Buffer day for unexpected issues
  • Monitor analytics closely
  • Celebrate! 🔥❄️

Success Metrics (Post-Launch)

Week 1 (April 15-21):

  • Worker uptime: >99%
  • Page load time: <2 seconds
  • Error rate: <1%
  • Zero manual server list updates needed

Month 1 (April-May):

  • Player count accuracy verified
  • Auto-refresh working smoothly
  • Mobile traffic analytics reviewed
  • User feedback collected (Discord)

Long-term:

  • Add/remove servers without touching website code
  • Update modpack versions by changing Pterodactyl description only
  • Infrastructure "just works" from anywhere in the USA

Contacts & Resources

Gemini AI Consultation:

  • Session 1: Initial architecture recommendation (Cloudflare Workers)
  • Session 2: Implementation details and Q&A
  • Both consultations saved in docs/planning/gemini-servers-consultation/

Cloudflare Resources:

Pterodactyl Resources:

Team:

  • Michael "Frostystyle" - Technical implementation
  • Claude (Chronicler #56) - Documentation and pair programming
  • Gemini AI - Architectural guidance and code review
  • Butter No Nutters - CEO approval (royal seal granted! 😺👑)

Conclusion

This implementation transforms the Servers page from a static, manually-maintained list into a living, self-updating system that reflects reality automatically. When we add a new Minecraft server, we:

  1. Create it in Pterodactyl
  2. Add Service Account as subuser
  3. Set description to Modpack Name | vX.Y.Z
  4. DONE! Website updates automatically within 60 seconds.

Zero code changes. Zero deployments. Zero manual updates.

That's the vision: Build it once, run it forever.

Fire + Frost + Foundation = Where Love Builds Legacy 💙


Document Status: Complete and ready for implementation
Last Updated: April 3, 2026
Next Review: April 15, 2026 (post-launch retrospective)