Files
firefrost-services/docs/code-bridge/archive/REQ-2026-04-16-modpack-installer.md
Claude Code 328e9ba613 Task #138: Wiki.js subscriber tier sync via GraphQL (REQ-2026-04-15-subscriber-wiki-auth)
- src/services/wikijsSync.js: GraphQL client for Wiki.js at subscribers.firefrostgaming.com
  - syncWikiUser(discordId, username, tierLevel): creates user if not exists, updates group if exists
  - demoteToAwakened(discordId): downgrades group on cancellation/chargeback/refund
  - Email convention: {discordId}@firefrost.local (unique internal addresses)
  - Tier → group mapping: 1=Awakened, 2=Elemental, 3=Knight, 4=Master, 5=Legend, 6=Sovereign
  - Silent-fail: never breaks the Stripe webhook
- src/routes/stripe.js: hooked into 4 lifecycle paths:
  - checkout.session.completed → syncWikiUser (non-blocking)
  - customer.subscription.deleted → demoteToAwakened
  - charge.dispute.created (chargeback) → demoteToAwakened
  - charge.refunded (refund ban) → demoteToAwakened
- .env.example: added WIKIJS_URL, WIKIJS_API_KEY, DISCORD_ISSUE_WEBHOOK_URL

PRE-REQ: Michael must create 6 groups in Wiki.js admin + generate API key before deploy.
2026-04-16 00:15:55 -05:00

8.9 KiB

REQ-2026-04-16-modpack-installer

From: Chronicler #93
Date: 2026-04-16
Priority: HIGH — Michael wants this done tonight
Status: PENDING
Linked Task: #101 — AI-Powered Modpack Server Installer
Architecture: Fully locked via 4-round Gemini consultation
Consultation docs:

  • firefrost-operations-manual/docs/consultations/gemini-modpack-installer-trinity-console-2026-04-15.md
  • firefrost-operations-manual/docs/consultations/gemini-modpack-installer-followup-2026-04-15.md
  • firefrost-operations-manual/docs/holly-review-modpack-installer.md

What This Is

A full modpack installer integrated into Trinity Console. Holly reviewed and approved the full feature set. Bitch Bot (the first-boot provisioning mod) is already built and compiled — this is the Arbiter/Trinity Console side that drives everything.


Database Migrations

Migration 143 — server_config updates

ALTER TABLE server_config
ADD COLUMN modpack_provider VARCHAR(50),
ADD COLUMN modpack_id VARCHAR(100),
ADD COLUMN current_version_id VARCHAR(100),
ADD COLUMN is_version_locked BOOLEAN DEFAULT FALSE,
ADD COLUMN locked_version_id VARCHAR(100) DEFAULT NULL,
ADD COLUMN lock_reason TEXT DEFAULT NULL,
ADD COLUMN spawn_verified BOOLEAN DEFAULT FALSE,
ADD COLUMN ram_allocation_mb INT NOT NULL DEFAULT 8192,
ADD COLUMN ram_ceiling_mb INT NOT NULL DEFAULT 16384,
ADD COLUMN hibernation_status VARCHAR(50) DEFAULT 'active';

Migration 144 — install_history table

CREATE TABLE install_history (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    server_id UUID REFERENCES server_config(id) ON DELETE CASCADE,
    pterodactyl_server_id VARCHAR(100),
    job_type VARCHAR(50) NOT NULL,
    target_version_id VARCHAR(100) NOT NULL,
    triggered_by VARCHAR(100) NOT NULL,
    status VARCHAR(50) NOT NULL,
    started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    completed_at TIMESTAMP WITH TIME ZONE,
    duration_seconds INT,
    mods_injected INT DEFAULT 0,
    log_output JSONB DEFAULT '{}'
);

CREATE INDEX idx_install_history_recent_failures
ON install_history(server_id, status, started_at);

Job Queue (pg-boss)

Add pg-boss as a dependency. Three queues:

  • modpack-installs — concurrency 2 (heavy file I/O)
  • maintenance-tasks — concurrency 5 (ghost updates, hibernation)
  • fast-sync — concurrency 20 (LuckPerms pings, Discord alerts)

Worker Execution Flow (modpack-installs)

  1. Job picked up → install_history status = running
  2. Pre-flight: check node RAM/disk headroom, map Java version → correct egg. Refuse with clear error if insufficient headroom.
  3. Pterodactyl server provisioned
  4. Download pack mods via provider API. Scrub client-only mods (cross-reference serverPackFileId for CurseForge; skip 403s silently).
  5. Inject Firefrost Standard Mod Stack from NextCloud (standard-mods/{mc_version}/)
  6. Drop provision.json + BitchBot-1.0.0-neoforge-1.21.1.jar into server mods folder (skip if spawn_type = skyblock or has_lobby)
  7. Stream everything to Pterodactyl via Wings SFTP
  8. Create Cloudflare A + SRV records
  9. Create Discord category + 5 channels (chat, in-game, forum, voice, status)
  10. Add to status poller
  11. Seed server_config record
  12. Power on server → set spawn_verified = false → post staff Discord ping → install_history = success

Trinity Console Pages

GET /admin/modpack-installer

Main installer page. Sections:

Provider Selection — 6 providers with logos: CurseForge, Modrinth, FTB, ATLauncher, Technic, VoidsWrath

Pack Browser (after provider selected):

  • Search box
  • Filters: category (Magic, Tech, Quests, Sci-Fi, Skyblock, Horror), mod loader (Forge, Fabric, NeoForge), MC version
  • Pack cards: name, thumbnail, mod count, mod loader, MC version, short description

Pack Details + Version Selection (after pack selected):

  • Full description, screenshots if available
  • Version dropdown (default: latest)
  • Resource estimates: recommended RAM, disk based on mod count/pack size
  • Smart node recommendation: query existing servers' RAM usage, recommend best node

Install Form:

  • Short name / subdomain (auto-suggested from pack name, slugified) — becomes Discord prefix + Cloudflare subdomain + DB short_name
  • Display name
  • Node selector (TX1 Dallas / NC1 Charlotte) — pre-filled from recommendation, overridable
  • RAM allocation (pre-filled from estimate, adjustable)
  • Spawn type: Standard / Skyblock / Has Lobby
  • Confirm button → enqueues job → redirects to install status page

GET /admin/modpack-installer/status/:job_id

Live install progress page. Shows:

  • Current step (streaming via SSE or polling)
  • Log output
  • Success/failure state
  • Link to server card on completion

GET /admin/modpack-installer/history

Install history table. Columns: server, job type, version, triggered by, status, duration, started at. Filterable by status and server.

GET /admin/modpack-installer/pending-spawns

Holly's queue. Lists all servers where spawn_verified = false. Each row: server name, installed date, "Mark Verified" button. This is Holly's only job after an install — log in, confirm spawn looks right, click verified.


Pre-Flight Mod Loader Check

During step 2 of the worker flow, after downloading mods:

  • Crack open each mod jar
  • Read META-INF/mods.toml (NeoForge/Forge) or fabric.mod.json (Fabric)
  • Verify loader matches the selected egg
  • Log mismatches as warnings, don't hard-fail (some jars are multi-loader)
  • If >20% of mods are wrong-loader, hard-fail with clear error before touching Pterodactyl

provision.json Structure (Bitch Bot input)

Arbiter generates and drops this into the server root during step 6:

{
  "version": "1.0",
  "schematic_name": "firefrost-spawn-v1.schem",
  "schematic_url": "https://downloads.firefrostgaming.com/Firefrost-Schematics/firefrost-spawn-v1.schem",
  "schematic_hash": "REAL_SHA256_GOES_HERE",
  "spawn_type": "standard",
  "spawn_coords": { "x": -5000, "y": 64, "z": -5000 },
  "paste_origin": "center",
  "worldspawn_offset": { "x": 0, "y": 1, "z": 0 },
  "command_blocks": [
    { "position": { "x": -4998, "y": 65, "z": -4998 }, "facing": "up" },
    { "position": { "x": -5002, "y": 65, "z": -4998 }, "facing": "up" },
    { "position": { "x": -4998, "y": 65, "z": -5002 }, "facing": "up" },
    { "position": { "x": -5002, "y": 65, "z": -5002 }, "facing": "up" }
  ],
  "rules_signs": [
    {
      "position": { "x": -4999, "y": 65, "z": -5005 },
      "lines": ["Welcome to", "Firefrost!", "Read /rules", "Have fun!"]
    }
  ],
  "yawp_region": {
    "name": "spawn",
    "min": { "x": -5050, "y": 0, "z": -5050 },
    "max": { "x": -4950, "y": 255, "z": -4950 },
    "flags": ["no-pvp", "no-mob-spawning", "break-blocks", "place-blocks"]
  },
  "self_destruct_on_success": true
}

Note: schematic_hash is a placeholder until Holly exports the real schematic. The installer should store this in .env or a config table so it can be updated without a code change.


.env additions

CURSEFORGE_API_KEY=your_key_here
WIKIJS_API_KEY=your_key_here
BITCH_BOT_SCHEMATIC_HASH=placeholder_until_holly_exports
BITCH_BOT_SCHEMATIC_URL=https://downloads.firefrostgaming.com/Firefrost-Schematics/firefrost-spawn-v1.schem

Files to Create/Modify

New:

  • migrations/143_server_config_modpack.sql
  • migrations/144_install_history.sql
  • src/services/modpackInstaller.js — job worker, provider API clients, install orchestration
  • src/services/providerApi/curseforge.js — CurseForge API client
  • src/services/providerApi/modrinth.js — Modrinth API client
  • src/services/providerApi/ftb.js — FTB API client (stub ATLauncher/Technic/VoidsWrath for now)
  • src/routes/admin/modpack-installer.js — all installer routes
  • src/views/admin/modpack-installer/index.ejs
  • src/views/admin/modpack-installer/status.ejs
  • src/views/admin/modpack-installer/history.ejs
  • src/views/admin/modpack-installer/pending-spawns.ejs

Modify:

  • src/index.js — register pg-boss, mount installer routes
  • src/views/layout.ejs — sidebar link to installer + pending spawns badge
  • package.json — add pg-boss

Scope Notes

In scope for tonight:

  • Full installer flow (CurseForge + Modrinth primary, FTB stub)
  • DB migrations
  • pg-boss queue
  • Pre-flight mod loader check
  • Holly's pending spawns queue
  • Install history

Defer to follow-up tasks:

  • Ghost updates (zero-downtime staging)
  • Hibernation/wake-up system
  • Dynamic RAM scaling
  • Crash loop sentinel
  • Cursed Modpack Roulette
  • Clone to dev
  • AI patch notes
  • Auto-tier syncing (Redis/LuckPerms messaging)

These are all in the Gemini consultation and have approved architecture. They become separate tasks after #101 ships.


Deploy Steps (after build)

Standard Arbiter deployment pattern:

  1. Run migrations 143 + 144 on Command Center
  2. npm install (picks up pg-boss)
  3. Copy files to /opt/arbiter-3.0
  4. Restart arbiter-3
  5. Verify sidebar link appears
  6. Test with a real CurseForge pack ID