# ModpackChecker Development Status Report

**Date:** April 6, 2026  
**Task:** #26 - Modpack Version Checker (Blueprint Extension)  
**Status:** Development Paused — Awaiting Hybrid Detection Implementation  
**Chronicler:** #63

---

## Executive Summary

ModpackChecker is functionally complete but **not commercially viable** in its current state. The extension requires manual egg variable configuration per server, which is unacceptable for:
- Michael's 21 production servers
- BuiltByBit customers expecting plug-and-play

**Next milestone:** Implement hybrid auto-discovery system before BuiltByBit launch.

---

## What Works ✅

### Core Functionality
- **Dashboard Badge:** Colored dot next to server names (orange=update, cyan=current)
- **Console Widget:** StatBlock-style card in right column with click-to-check
- **Admin Panel:** CurseForge API key config, dark theme callouts, PRO tier badges
- **API Routes:** Clean URLs, no double-prefixing
- **4-Platform Support:** CurseForge, Modrinth, FTB, Technic
- **Rate Limiting:** 2 requests/minute per server, 429 handling in UI
- **Caching:** 60-second TTL on dashboard, 12-hour Technic build cache

### Code Quality
- Centralized `ModpackApiService` for all API calls
- Short error codes in UI ("Not configured", "Wait 60s", "API error")
- Gemini-reviewed architecture (4 batch review complete)
- Proper authorship (Firefrost Gaming / Frostystyle)

---

## What's Broken ❌

### Blueprint Packaging Issues

**Problem:** Blueprint production install behaves differently than dev mode.

| Issue | Dev Mode | Production Install |
|-------|----------|-------------------|
| `build.sh` execution | ✅ Runs | ❌ Does NOT run |
| App files (Controllers, Services, Commands) | Auto-copied via conf.yml | ❌ Stays in `.blueprint/extensions/` subfolder |
| Frontend injection | Via build.sh sed commands | ❌ Must use conf.yml wrapper fields |
| File locations | `.blueprint/dev/` | `.blueprint/extensions/modpackchecker/` (reorganized) |

**Root Cause:** Our `conf.yml` uses `requests.app: "app"` which tells Blueprint where source files are, but we relied on `build.sh` to inject React components. Blueprint doesn't run build.sh on `blueprint -install`.

**Solution Required:** Rewrite `conf.yml` to use Blueprint's native wrapper injection fields OR find the correct production deployment method.

### Manual Deployment Steps Required (Live Panel)

When installing on a fresh panel, these manual steps were required:

```bash
# 1. Copy PHP files to correct locations
cp .blueprint/extensions/modpackchecker/app/Http/Controllers/ModpackAPIController.php /var/www/pterodactyl/app/Http/Controllers/
cp .blueprint/extensions/modpackchecker/app/Services/ModpackApiService.php /var/www/pterodactyl/app/Services/
cp .blueprint/extensions/modpackchecker/app/Console/Commands/CheckModpackUpdates.php /var/www/pterodactyl/app/Console/Commands/

# 2. Copy React components
cp .blueprint/extensions/modpackchecker/views/server/wrapper.tsx /var/www/pterodactyl/resources/scripts/components/server/ModpackVersionCard.tsx
cp .blueprint/extensions/modpackchecker/views/dashboard/UpdateBadge.tsx /var/www/pterodactyl/resources/scripts/components/dashboard/UpdateBadge.tsx

# 3. Inject into AfterInformation.tsx
cat > /var/www/pterodactyl/resources/scripts/blueprint/components/Server/Terminal/AfterInformation.tsx << 'EOF'
import React from 'react';
import ModpackVersionCard from "@/components/server/ModpackVersionCard";
/* blueprint/import */
export default () => {
  return (
    <>
      {/* blueprint/react */}
      <ModpackVersionCard />
    </>
  );
};
EOF

# 4. Inject UpdateBadge into ServerRow.tsx
sed -i '1i import UpdateBadge from "@/components/dashboard/UpdateBadge";' /var/www/pterodactyl/resources/scripts/components/dashboard/ServerRow.tsx
sed -i 's|{server.name}</p>|{server.name}<UpdateBadge serverUuid={server.uuid} /></p>|' /var/www/pterodactyl/resources/scripts/components/dashboard/ServerRow.tsx

# 5. Rebuild
composer dump-autoload
php artisan optimize:clear
export NODE_OPTIONS=--openssl-legacy-provider && yarn build:production
```

### UX Blocker — Egg Variable Dependency

**The showstopper:** ModpackChecker requires these egg variables per server:
- `MODPACK_PLATFORM` (curseforge, modrinth, ftb, technic)
- `MODPACK_ID` (platform-specific ID)
- `MODPACK_CURRENT_VERSION` (optional, for update detection)

**Problem:** Standard Forge/NeoForge/Fabric eggs don't have these variables. Adding them requires:
- Modifying every egg
- Configuring every server
- Teaching customers how to find modpack IDs

This is unacceptable for commercial release.

---

## Gemini's Recommended Solution

### Hybrid Auto-Discovery + Self-Service Model

**Phase 1: Auto-Discovery (Cron Job)**
```
1. Check egg variables (fastest)
2. If missing → Read manifest.json via DaemonFileRepository (CurseForge)
3. If missing → Read modrinth.index.json (Modrinth)
4. Save to DB with detection_method = 'egg' | 'file' | 'manual'
```

**Phase 2: Self-Service Fallback (Console Widget)**
- If unconfigured: Show "Configure Manually" button
- Modal lets server owner select platform + paste modpack ID
- Saves to DB with `detection_method = 'manual'`
- `is_user_overridden = true` prevents cron from overwriting

### Implementation Details

**DaemonFileRepository Usage:**
```php
use Pterodactyl\Repositories\Wings\DaemonFileRepository;

private function detectCurseForge(Server $server): ?string
{
    try {
        $this->fileRepository->setServer($server);
        $content = $this->fileRepository->getContent('manifest.json');
        $manifest = json_decode($content, true);
        return $manifest['projectID'] ?? null;
    } catch (\Exception $e) {
        return null;
    }
}
```

**Database Schema Additions:**
```php
$table->string('detection_method')->default('unknown');  // egg, file, manual
$table->boolean('is_user_overridden')->default(false);   // prevents auto-overwrite
```

**Critical Warning from Gemini:**
- File detection via Wings API is a network call
- **NEVER do this on page load** — only in cron job
- CurseForge fingerprinting is **rejected** — too resource intensive

---

## File Locations

### Repository
```
firefrost-services/services/modpack-version-checker/
├── blueprint-extension/          # Source code
│   ├── conf.yml
│   ├── build.sh
│   ├── README.md
│   ├── CHANGELOG.md
│   ├── icon.png
│   ├── app/
│   │   ├── Console/Commands/CheckModpackUpdates.php
│   │   ├── Http/Controllers/ModpackAPIController.php
│   │   └── Services/ModpackApiService.php
│   ├── admin/
│   │   ├── controller.php
│   │   └── view.blade.php
│   ├── database/migrations/
│   ├── routes/client.php
│   └── views/
│       ├── server/wrapper.tsx
│       └── dashboard/UpdateBadge.tsx
└── releases/
    └── modpackchecker-1.0.0.blueprint   # Packaged (has issues)
```

### Dev Panel (64.50.188.128)
- Extension dev folder: `/var/www/pterodactyl/.blueprint/dev/`
- Works correctly in dev mode

### Live Panel (45.94.168.138)
- Extension folder: `/var/www/pterodactyl/.blueprint/extensions/modpackchecker/`
- Required manual file copying (see above)
- Panel version: 1.12.1 (dev is 1.12.2)

---

## API Endpoints

```
POST /api/client/extensions/modpackchecker/servers/{server}/check
  → Manual version check, rate limited 2/min

GET /api/client/extensions/modpackchecker/status
  → Returns cached status for all user's servers
```

---

## Testing Notes

### CurseForge Test Data
- **FTB StoneBlock 4:** Project ID `1373378`
- Latest version as of April 2026: `1.9.6`

### Modrinth Test Data (no API key needed)
- **Adrenaserver:** Slug `adrenaserver`

---

## Next Steps (Task #95)

### Priority 1: Hybrid Detection System
1. Add `detection_method` and `is_user_overridden` columns to migration
2. Inject `DaemonFileRepository` into `CheckModpackUpdates` command
3. Implement `detectCurseForge()` and `detectModrinth()` methods
4. Update cron logic: egg vars → file detection → skip if manual override
5. Test on live panel with real modpack servers

### Priority 2: Self-Service UI
1. Update `wrapper.tsx` with "Configure Manually" button
2. Create configuration modal (Platform dropdown + ID input)
3. Add new API endpoint: `POST /servers/{server}/configure`
4. Store manual config with `is_user_overridden = true`

### Priority 3: Fix Blueprint Packaging
1. Research Blueprint's native wrapper injection (`conf.yml` fields)
2. Eliminate dependency on `build.sh` for production installs
3. Re-test full install cycle on clean panel
4. Update `modpackchecker-1.0.0.blueprint` package

### Priority 4: Documentation
1. Update README with hybrid detection explanation
2. Document supported manifest file formats
3. Add troubleshooting section
4. Screenshot gallery for BuiltByBit listing

---

## Commits Today

| Hash | Message |
|------|---------|
| 35315c2 | Batch 1 fixes - routes, migration, build.sh |
| 8e37120 | Batch 2 fixes - ModpackApiService, rate limiting |
| 5a607c8 | Batch 3+4 fixes - frontend, admin, docs |
| d735e3d | Wizard review fixes - UI polish |
| c160647 | Move card to right column, StatBlock style |
| 05d2164 | Console card redesign - short error codes |
| 6e15a62 | Update website link to Discord |
| 1a3e884 | Release v1.0.0 packaged blueprint file |
| e59ee04 | Fix check_interval validation (nullable) |

---

## Gemini Consultations

All saved in `docs/consultations/`:
- `gemini-blueprint-confyml-2026-04-06.md`
- `gemini-technic-api-fix-2026-04-06.md`
- `gemini-batch1-review.md` through `gemini-batch4-review.md`
- `gemini-modpack-detection-consultation.md` (today's UX pivot)

---

*Fire + Frost + Foundation = Where Love Builds Legacy* 💙🔥❄️
