docs: Gemini consult — ModpackChecker UX overhaul, 10 questions

Most detailed consult ever. Covers:
- Seeding problem (all servers falsely show up_to_date)
- Messy CurseForge version strings
- Console widget UX redesign
- Non-modpack server detection
- Proactive notifications
- Version history architecture
- Multi-panel cloud opportunity
- Monetization angles
This commit is contained in:
Claude
2026-04-13 04:14:47 +00:00
parent 979ff403ed
commit eb5e1feb82

View File

@@ -0,0 +1,290 @@
# Gemini Consultation: ModpackChecker UX Overhaul — Console Widget, Version Detection & Future Architecture
**Date:** April 1213, 2026 (late night session)
**From:** Michael (The Wizard) + Claude (Chronicler #84 — The Meridian)
**To:** Gemini (Architectural Partner)
**Re:** ModpackChecker v1.0.0 is live but the UX isn't what we hoped — we need your wildest ideas for v1.1.0+
---
## Hey Gemini! 👋
Long night. We shipped ModpackChecker v1.0.0 to the live Pterodactyl panel tonight after an epic debugging marathon. The good news: it's installed, the background cron detects all 22 servers via the `modpack_installations` table, and the dashboard badges are compiling. The less good news: when Michael clicked the console widget button, it worked — but it didn't feel right. We want your help designing what "right" actually looks like, and we're explicitly asking for wild ideas. Nothing is off the table.
We're 46 hours from soft launch on April 15, so some of this is v1.1.0+ thinking. But if something is quick to implement, we'll do it tonight.
---
## The Product
**ModpackChecker** is a commercial Blueprint extension for Pterodactyl Panel 1.12.2. It monitors Minecraft modpack servers for updates across 4 platforms: CurseForge, Modrinth, FTB, and Technic. It's being sold on BuiltByBit at $14.99 (Standard) and $24.99 (Professional).
**The vision:** Panel admins with 10-50 Minecraft servers should never have to manually check if their modpacks are out of date. It should just... tell them. Automatically. Beautifully.
**Our customers:** Minecraft hosting providers, server network owners, and serious hobbyists who run multiple servers. Michael is our first real customer — he runs 22 servers on his own Firefrost Gaming panel.
---
## Current Architecture
### Detection Pipeline (Background Cron)
`php artisan modpackchecker:check` runs on a cron schedule (daily or every 6/12 hours for Pro). Detection priority:
1. **`modpack_installations` table** — Pterodactyl's own install records (provider + modpack_id). Works for ~60-70% of servers that were installed via the panel's modpack installer.
2. **Egg variables**`MODPACK_PLATFORM` + `MODPACK_ID` in server startup variables. Works if the admin configured them manually.
3. **File detection**`DaemonFileRepository` reads `manifest.json` (CurseForge) or `modrinth.index.json` (Modrinth) from `/home/container/`. In practice this rarely works because the modpack installer extracts files and discards the manifest.
### Version Tracking
- **First run:** Seeds `current_version = latest_version` (assumes freshly installed = current)
- **Subsequent runs:** If CurseForge/Modrinth returns a newer `latest_version` than the stored `current_version`, status becomes `update_available`
- **Problem:** The seeding assumption is often wrong. Michael KNOWS some of his servers are behind, but since we seeded them as current tonight, they all show "up to date."
### Database Schema (`modpackchecker_servers`)
```sql
server_uuid VARCHAR
platform VARCHAR (curseforge, modrinth, ftb, technic)
modpack_id VARCHAR
modpack_name VARCHAR
current_version VARCHAR (what we think the server is running)
latest_version VARCHAR (latest from the platform API)
status VARCHAR (up_to_date, update_available, unconfigured, error)
detection_method VARCHAR (installer, egg, file, manual)
is_user_overridden BOOLEAN
last_checked TIMESTAMP
error_message TEXT
```
### The Console Widget (Current State)
A React TSX component injected into Pterodactyl's server console page. Currently shows:
- **Idle:** "Click to check"
- **Loading:** "Checking..."
- **Success:** Shows `latest_version` string (e.g., "All the Mods 10-6.6")
- **Update available:** Orange background
- **Error:** Red text with error code
**What it doesn't show:** Current version, comparison, when it was last checked, whether the cron has run yet, or any context about what the version string means.
### The Dashboard Badge (Current State)
A small colored dot injected next to the server name on the panel dashboard:
- 🟠 Orange = update available
- 🟢 Green = up to date
- No dot = unconfigured or not yet checked
**Works when yarn build compiles.** Currently blocked by Blueprint beta CSS module issue on some Node versions (v1.1.0 fix planned with `--openssl-legacy-provider`).
---
## What "Worked But Not The Way We Hoped" Means
When Michael clicked the console widget button on a server tonight, it showed him the latest version string — something like "All the Mods 10-6.6". That's technically correct. But here's what felt wrong:
1. **It just shows a version string with no context.** "All the Mods 10-6.6" — is that good? Is that the latest? Is HIS server on that version? There's no comparison shown.
2. **All 22 servers show "up to date" even though Michael knows some aren't.** This is the seeding problem: we set current_version = latest_version on first run, so everything looks current until CurseForge releases a newer version.
3. **The UX requires clicking.** You have to click the widget button to trigger a live API check. Michael expected it to proactively show him the status without having to click.
4. **Version strings from CurseForge are messy.** CurseForge's `displayName` field returns things like:
- "All the Mods 10-6.6"
- "Society - Capital Hill - 0.20.0"
- "All the Mons-0.18.0-beta"
- "Homestead-1.2.0.zip"
These are human-readable titles, not clean semantic versions. Comparing "ATM10-6.5" to "ATM10-6.6" is easy, but "Homestead-1.2.0.zip" vs "Homestead-1.3.0.zip" requires parsing.
5. **The console widget is in the wrong place.** It's in the server console "right column" alongside CPU/memory/disk stats. But version checking isn't something you want while actively managing a running server. It feels misplaced.
---
## Full Current Code
### ModpackVersionCard.tsx (Console Widget)
```tsx
import React, { useState } from 'react';
import { ServerContext } from '@/state/server';
import http from '@/api/http';
import { faCube } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
interface VersionData {
success: boolean;
platform?: string;
modpack_id?: string;
modpack_name?: string;
current_version?: string;
latest_version?: string;
status?: string;
message?: string;
error?: string;
}
const ModpackVersionCard: React.FC = () => {
const uuid = ServerContext.useStoreState((state) => state.server.data?.uuid);
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const [data, setData] = useState<VersionData | null>(null);
const checkForUpdates = async () => {
if (!uuid) return;
setStatus('loading');
try {
const response = await http.post(`/api/client/extensions/modpackchecker/servers/${uuid}/check`);
setData(response.data);
setStatus(response.data.success ? 'success' : 'error');
} catch (error: any) {
if (error.response?.status === 429) {
setData({ success: false, error: 'rate_limited' });
} else if (error.response?.status === 404) {
setData({ success: false, error: 'not_found' });
} else {
setData({ success: false, error: 'api_error' });
}
setStatus('error');
}
};
const getBgColor = () => {
if (status === 'success' && data?.status === 'update_available') return 'bg-orange-500';
if (status === 'success' && data?.success) return 'bg-cyan-500';
return 'bg-gray-700';
};
return (
<div onClick={status !== 'loading' ? checkForUpdates : undefined}>
{/* ... renders latest_version string only ... */}
</div>
);
};
```
### manualCheck() in ModpackAPIController.php
```php
public function manualCheck(Request $request, Server $server): JsonResponse
{
// Rate limiting: 2/min per server
// Detection: egg vars → modpack_installations → file detection → cached DB
// Returns: success, platform, modpack_id, modpack_name,
// current_version (from DB cache), latest_version (from API), update_available
}
```
### CheckModpackUpdates.php (Cron) — Key Logic
```php
// Version seeding on first detection:
if (!$existing) {
// First time seeing this server — seed current = latest
$currentVersion = $versionData['version'];
} else {
// Preserve existing current_version
$currentVersion = $existing->current_version ?? $versionData['version'];
}
$updateAvailable = $currentVersion !== $versionData['version'];
$status = $updateAvailable ? 'update_available' : 'up_to_date';
```
---
## The Core Problems We Want to Solve
### Problem 1: The Seeding Assumption
**"First run = current"** is almost always wrong for panels that have been running modpack servers for months before installing ModpackChecker. We need a way to know what version is ACTUALLY running on the server, not just assume it's the latest.
### Problem 2: Messy Version Strings
CurseForge returns display names like "All the Mods 10-6.6" not semantic versions like "6.6.0". Comparing these is unreliable and the strings look ugly in the UI.
### Problem 3: The Widget UX
The console widget shows a version string only after clicking. It should show more context — current vs latest, when last checked, the platform — proactively, not reactively.
### Problem 4: "Not Configured" Servers
3 of 22 servers have no detection data at all (FoundryVTT, Hytale, Vanilla — obviously not modpack servers). But ModpackChecker doesn't know that. These just sit in `unconfigured` status forever and pollute the view.
### Problem 5: Update Notifications
An update badge is good. But how does the admin KNOW they got an update? There's no notification — they have to visit the panel and see the orange dot. For a 22-server panel, that requires scanning the whole dashboard.
---
## Specific Questions
1. **Seeding problem — how do we know the actual current version?**
We have Wings access to the server filesystem. For CurseForge packs installed via the modpack installer, is there any file left behind that contains the installed version? We checked `manifest.json` — it's not there post-install. Is there a `minecraftinstance.json`? A `packinfo` file? Anything in the `config/` folder? What about reading from the server's startup command arguments?
2. **Alternative version sources — what are we missing?**
We've tried: egg variables, manifest.json, modrinth.index.json, modpack_installations table. What other sources exist on a running Minecraft server that could tell us the installed modpack version? Think: server logs on startup, JVM arguments, mod metadata files, world data, Forge/NeoForge version files. Wild ideas welcome.
3. **Semantic version extraction — best approach?**
Given messy version strings like "All the Mods 10-6.6", "Society - Capital Hill - 0.20.0", "Homestead-1.2.0.zip" — what's the most reliable regex or parsing strategy to extract a clean comparable version number? Should we normalize to semver? Store both the raw display name AND an extracted version number?
4. **Widget redesign — what should it actually show?**
The current widget shows a version string on click. What would an ideal modpack status widget look like in the Pterodactyl server console? Should it:
- Load the cached DB status automatically (no click required)?
- Show current vs latest side by side?
- Show the platform logo/icon?
- Show time since last check?
- Have a "Force Check Now" button that bypasses cache?
We're redesigning this for v1.1.0 — no constraints, what's the ideal UX?
5. **"Not a modpack" detection — how do we handle non-modpack servers?**
FoundryVTT and Hytale servers will never have modpack data. Right now they just show "unconfigured" forever. Should we:
- Show nothing for unconfigured servers (hide the widget entirely)?
- Let the admin mark a server as "not a modpack server" to dismiss it?
- Auto-detect server type from the egg name and skip non-Minecraft eggs?
- Something else?
6. **Proactive notifications — what's the right channel?**
When an update is detected, how should we notify the admin? Options:
- Discord webhook (already planned for Pro tier)
- Email via Pterodactyl's mail config?
- In-panel notification (Pterodactyl has a notification system)?
- An "Update Digest" email showing all pending updates once a week?
- SMS via Twilio for critical servers?
What would you actually USE as a busy server admin?
7. **The "known outdated" problem — how do we help admins with servers they know are behind?**
Michael knows several servers are running old versions. Right now the only way to fix the false "up to date" status is to manually edit `current_version` in the DB. For a BuiltByBit product, that's unacceptable. What's the right UX for an admin to say "this server is running version X"?
- Input field in the admin extension page?
- A "Recalibrate" button that triggers a fresh comparison?
- Accept a version number in the console widget directly?
8. **Long-term architecture — should we store version history?**
Right now we only store current + latest. Should we log every detected version change? Benefits: admins could see "this pack was updated 3 times since I last looked." Costs: more DB storage, more complex queries. Is a `modpackchecker_version_history` table worth building?
9. **Multi-panel support — wild idea or real opportunity?**
ModpackChecker currently only works on the panel it's installed on. But many hosting providers run multiple Pterodactyl panels. Could there be a "ModpackChecker Cloud" service — a central dashboard that aggregates update status from multiple panels? Is this a real product opportunity or scope creep?
10. **Monetization angle — are there API opportunities we're missing?**
We're currently selling detection + monitoring. Are there adjacent features that would justify higher tiers or a subscription model?
- Automatic update execution (trigger a server update with one click)?
- Changelogs pulled from CurseForge/Modrinth and displayed in-panel?
- "Smart update" that checks if the new version breaks any custom configs?
- Integration with backup systems to auto-backup before updating?
---
## Context That Might Help
- **Pterodactyl Panel 1.12.2** — this is the specific version we target. Blueprint beta-2026-01 for extension framework.
- **Wings daemon** — gives us sandboxed filesystem access to `/home/container/` via `DaemonFileRepository`. Network calls to Wings are expensive — Gemini previously told us never do this on page load, only in background cron.
- **CurseForge API** — uses `x-api-key` header. Returns `displayName` (messy) and `dateModified`. No clean semver.
- **Modrinth API** — cleaner data, uses project slugs, returns semantic versions.
- **FTB API** — `https://api.modpacks.ch/public/modpack/{id}` — returns clean version numbers.
- **Technic API** — `https://api.technicpack.net/modpack/{slug}` — returns build numbers.
- **`modpack_installations` table** — this is actually from a DIFFERENT Blueprint extension ("Modpack Installer") that Michael already has installed. We're reading its data. We don't own this table. It could change between Pterodactyl versions or installer extension updates.
- **22 servers** — Michael's panel. About 19 are CurseForge, 0 currently Modrinth, 0 FTB (they show as CurseForge because FTB packs are also on CurseForge), 0 Technic.
- **BuiltByBit market** — our target customers are Minecraft hosting companies. The average customer probably has 10-100 servers. Some large hosts have 500+.
- **We cannot require egg changes** — this was Gemini's own guidance from the April 6 hybrid detection consultation. Egg changes require customer cooperation and break plug-and-play.
- **No real-time data** — the background cron is the only way to get data. The console widget triggers a live API call but only to the platform (CurseForge/Modrinth), not to the server itself.
---
## What We're Hoping For
Gemini, we want your best thinking on this. Not just incremental improvements — if you see a fundamentally different architecture that would make this product 10x better, tell us. Michael has been working on this for 6+ hours tonight and he's frustrated that it "worked but not the way he hoped." We want to end this session with a clear v1.1.0 vision that we're genuinely excited to build.
Wild ideas are explicitly welcome. If you think we're solving the wrong problem entirely, tell us that too.
---
Thanks Gemini! This one's a meaty one and we appreciate you. 🔥❄️
— Michael (The Wizard) + Claude (Chronicler #84 — The Meridian)
**Firefrost Gaming | Fire + Frost + Foundation = Where Love Builds Legacy** 💙🔥❄️