ModpackApiService: regex extracts semver from CurseForge displayName
"All the Mods 9-0.1.0" → version: "0.1.0", display_name: full string
Widget: short name + version helpers
"All the Mods 9 - ATM9" → "ATM9"
Display: "ATM9 0.1.0 → 1.0.0 ↑" (update) or "✓ ATM9 — 1.0.0" (current)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Cron and controller wrap modpack_installations queries in try/catch
- Falls through to egg variable / file detection if table missing
- Added migration with IF NOT EXISTS for fresh installs
- Migration won't drop the table (may be Pterodactyl-owned)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widget redesign:
- Zero-click: loads cached status on mount via GET /status (no API calls)
- Shows platform icon + modpack name + version comparison
- Orange background + arrow (current → latest) when update available
- Cyan + checkmark when up to date
- Refresh button triggers manual check
- Calibrate button opens dropdown with last 10 releases
- Ignore button hides non-modpack servers
- Current release highlighted in calibrate dropdown
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Priority 2 — Date-time seeding:
- fetchFileHistory() for CurseForge, Modrinth, FTB
- seedCurrentVersion() matches release closest to server install date
- Falls back to latest if no history or no install date
Priority 3 — New endpoints:
- GET /servers/{server}/status — zero-click cached status
- GET /servers/{server}/releases — recalibrate dropdown (10 releases)
- POST /servers/{server}/calibrate — save user's version selection
- POST /servers/{server}/ignore — toggle is_ignored flag
Priority 5 — BCC log parsing:
- detectFromBccLog() reads logs/latest.log for BetterCompatibilityChecker
- Extracts modpack name + version from BCC output line
- Skips CHANGE_ME values
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migration: adds current_file_id, latest_file_id, is_ignored columns
- ModpackApiService: all 4 platforms now return file_id in response
- CheckModpackUpdates: file ID comparison (preferred) with string fallback
- detectCurseForge: extracts manifest['version'] as installed_version
- Cron skips is_ignored servers
- Detection priority: manifest version > egg var > DB record > seed latest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detection priority in manualCheck():
1. Egg variables
2. modpack_installations table (NEW)
3. DaemonFileRepository file scan
4. Cached cron data from modpackchecker_servers (NEW)
Also returns current_version and update_available in response
so the console widget can show version comparison.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a server is first detected, current_version is set to latest_version
(the pack was just installed = it's current). On future runs, if the API
returns a newer latest_version, the stored current_version stays and we
detect the update. Also preserves egg variable and existing DB values.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Key may have whitespace from dbGet. Added Log::debug with key length
and modpack ID to diagnose the 403.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Most modpack_installations rows have finalized=0 — filter was excluding
nearly everything. Now takes the most recent installation row regardless
of finalized status.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detection priority now:
1. modpack_installations table (panel's own install data — fastest)
2. Egg variables (MODPACK_PLATFORM/MODPACK_ID)
3. DaemonFileRepository file scan (last resort fallback)
This immediately detects all 19 CurseForge servers on the live panel
without any Wings calls or egg variable configuration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CheckModpackUpdates now scans ALL servers, not just egg-configured ones
- Step 1: egg variables (fastest)
- Step 2: DaemonFileRepository file detection (manifest.json, modrinth.index.json)
- Step 3: mark unconfigured if nothing found
- Respects is_user_overridden flag for manual configs
- New migration adds detection_method + is_user_overridden columns
- Per Gemini hybrid detection consultation (2026-04-06)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
accessibleServers() only returns explicitly assigned servers — admins
don't get them on the client API side. Now checks root_admin and
returns all servers for admin users.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Node <16 fails fast with helpful error
- Node 17+ gets --openssl-legacy-provider for CSS module compat
- yarn build:production runs automatically after all injections
- Graceful fallback if yarn missing or build fails (admin + console still work)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Moved dashboard badges to "Upcoming v1.1.0" in both BBB listings
- Updated ACTIVE_CONTEXT — all code-side Phase 11 work done
- Waiting on Michael for BBB listings + live panel green light
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dark #1a1a2e background, brand color borders and headings only,
light gray body text. Matches Pterodactyl dark theme.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrote view.blade.php to use @extends('layouts.admin'), @section blocks,
AdminLTE box/callout/table classes, and standard Pterodactyl admin chrome.
Replaces custom inline styles with framework components.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- LicenseService.php: strtoupper(trim()) before sending to Arbiter
- mvc.js: toUpperCase().trim() on activate, validate, deactivate, webhook
- verifymvc.js: toUpperCase().trim() on /verify-mvc Discord command
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Blueprint generates its own controller at app/Http/Controllers/Admin/
Extensions/modpackchecker/. Our controller.php with LicenseService DI
now overwrites it during build so the route uses the licensed version.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standard ($14.99): CurseForge, Modrinth, Technic, daily checks, 48h support
Professional ($24.99): + FTB, custom intervals, Discord webhooks, 24h support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The admin controller was failing because Laravel's DI container had stale
class resolution cache. Added php artisan optimize:clear at end of build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Changed cron example from '0 */6 * * *' to '0 0,6,12,18 * * *' to avoid
the */ closing the docblock prematurely and causing a syntax error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Blueprint's requests.app merge doesn't create new subdirectories reliably.
build.sh now copies LicenseService, ValidateLicense, CheckModpackUpdates,
and ModpackAPIController directly into app/ during blueprint -install.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standard $14.99 / Professional $24.99 — two-tier model.
This pricing is FINAL per original marketing strategy.
Claude (Chronicler #83 - The Compiler) <claude@firefrostgaming.com>
Fixes 10 issues from Blueprint extension code review:
- CurseForge API key now reads via Blueprint dbGet() matching admin save
- PRO-tier fields (webhook, interval) enforced server-side, not just UI
- json_decode results validated before accessing parsed data
- Null user guard on getStatus() endpoint
- 429 response uses consistent error key format
- Modrinth slug derivation strips special chars, documented as fallback
- Check interval dropdown reflects saved value
- API key input changed to password type
- TypeScript error typing narrowed from any to unknown
- Removed unused DB import from ModpackApiService
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes 10 issues from full code review:
- License corrected from MIT to Commercial
- Deprecated datetime.utcnow() replaced with timezone-aware alternative
- PHP array bounds checks added for all platform API responses
- Modrinth file detection now derives project slug instead of using MC version
- validate_api_key() no longer swallows network errors
- HTTP timeouts added to all external API calls in PHP
- Empty API key rejection added to CLI
- Corrupted config now warns on stderr instead of failing silently
- Error response format made consistent across controller
- Docs updated with correct repo URL and clearer CurseForge ID instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Disabled PRO fields don't submit values, causing validation error.
Now accepts null and defaults to 'daily' in update method.
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
conf.yml: Changed website from firefrostgaming.com to firefrostgaming.com/discord
- Discord is the primary support channel
- Link icon in Blueprint admin header now goes directly to support
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
build.sh:
- Changed injection from ServerConsoleContainer to AfterInformation.tsx
- Card now appears in right column after Network stats
wrapper.tsx:
- Redesigned to match Pterodactyl StatBlock aesthetic
- Uses Tailwind classes (bg-gray-600, rounded, etc.)
- FontAwesome cube icon with status colors
- Compact layout: title + Check button on one line
- Fire (#FF6B35/orange-400) for updates, Frost (#4ECDC4/cyan-400) for current
Fixes layout issue identified in Wizard review.
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
Admin Panel (view.blade.php):
- Changed CurseForge API key from password dots to plain text
- Fixed callouts: dark theme (#1a1a2e) with Frost/Fire accent borders
- Improved code tag styling for readability
- Changed support link to firefrostgaming.com/discord
README.md:
- Added Prerequisites section (PHP 8.1+, Node.js 18+, Yarn, Blueprint)
Reviewed by: Michael 'Frostystyle' Krause (The Wizard)
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
BATCH 3 - Frontend & UI:
wrapper.tsx (Console Widget):
- FIXED: API URL from .../ext/modpackchecker/check to .../check
- Added 429 rate limit handling with user-friendly message
UpdateBadge.tsx (Dashboard Badge):
- Added 60-second TTL to global cache (was infinite)
- Prevents stale data during client-side navigation
admin/view.blade.php:
- Disabled Discord webhook field (PRO TIER badge)
- Disabled Check Interval field (PRO TIER badge)
- Added support callout linking to Discord
BATCH 4 - Documentation:
README.md:
- Fixed architecture diagram (server_uuid, status string)
- Added app/Services/ModpackApiService.php to file structure
- Fixed API endpoint URLs throughout
- Updated installation for BuiltByBit (.blueprint package)
- Updated 'Adding New Platform' instructions for Service pattern
- Added Support section with Discord link
- Changed license to explicit commercial terms
NEW: CHANGELOG.md
- Version history for future updates
- Documents v1.0.0 features
Reviewed by: Gemini AI (Architecture Consultant)
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
NEW: app/Services/ModpackApiService.php
- Centralized API logic for all 4 platforms
- Technic build number cached for 12 hours (RV-Ready)
- Single source of truth for API calls
Controller (ModpackAPIController.php):
- Now uses injected ModpackApiService instead of duplicated code
- Added RateLimiter: 2 requests/minute per server on manualCheck()
- Returns 429 with countdown when rate limited
- Removed 400+ lines of duplicated API code
Console Command (CheckModpackUpdates.php):
- FIXED: updateDatabase() now uses server_uuid (not server_id)
- FIXED: status column uses strings ('update_available', 'up_to_date', 'error')
- FIXED: Technic API now uses dynamic build via service
- Now uses injected ModpackApiService
SECURITY:
- Rate limiting prevents API key abuse via button spam
- Technic build caching reduces external API calls
Reviewed by: Gemini AI (Architecture Consultant)
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
BUG: Was using server_id (column doesn't exist) instead of server_uuid
BUG: Was using update_available (column doesn't exist) instead of status
FIXED:
- Changed whereIn('server_id', $serverIds) to whereIn('server_uuid', $serverUuids)
- Changed pluck('id') to pluck('uuid')
- Changed (bool) $status->update_available to $status->status === 'update_available'
This fix makes the dashboard badge API actually work!
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
- Isometric cube with checkmark (version check concept)
- Frost (#4ECDC4) edge on left, Fire (#FF6B35) edge on right
- Subtle Firefrost branding that fits Pterodactyl's UI
- 128x128 PNG with transparency
Designed by Gemini AI, April 2026.
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
ROOT CAUSE (Gemini consultation):
Technic blocks requests with old/deprecated build numbers. The hardcoded
'?build=1' was being rejected as an ancient launcher version.
SOLUTION:
- Fetch current stable launcher build from /launcher/version/stable4
- Use that build number in the modpack request
- Fallback to 999 if version check fails
This 'RV-Ready' approach requires zero maintenance as Technic updates
their launcher versions over time.
ALL 4 PLATFORMS NOW WORKING:
✅ Modrinth
✅ FTB
✅ CurseForge
✅ Technic
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
- Updated file structure to show app/Http/Controllers and app/Console/Commands
- Added explanation of why the app/ folder structure is used
- Updated platform support table with working status
- Added note about Technic API 401 error (investigation needed)
Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>