---
status: complete
priority: P1
owner: Michael
created: 2026-03-31
---

# Task #90: Arbiter 2.x - Unified Access Manager

**Status:** OPEN  
**Priority:** Tier 1 - Soft Launch Blocker  
**Estimated Time:** 20-30 hours (5 phases)  
**Created:** March 31, 2026  
**Architecture Validated By:** Gemini AI

---

## Overview

Complete rewrite merging Arbiter (Discord role management) + Whitelist Manager (server access control) into single Node.js application with PostgreSQL backend.

**Goal:** Subscription-driven Minecraft server whitelist access - user subscribes → links Minecraft account → automatically whitelisted on all servers.

---

## Quick Links

- **Implementation Guide:** `IMPLEMENTATION-GUIDE.md` (complete technical spec with code examples)
- **Architecture Decision:** `../../reference/gemini-consultations/2026-03-31-arbiter-whitelist-architecture.md`
- **Implementation Details:** `../../reference/gemini-consultations/2026-03-31-arbiter-implementation-details.md`
- **Main Task:** `../../core/tasks.md#90`

---

## The Flow

1. User subscribes via Paymenter (any tier, even $1 Awakened)
2. Paymenter webhook → Arbiter assigns Discord role
3. User runs `/link <minecraft_username>` in Discord
4. Arbiter validates via Mojang API, gets UUID
5. Stores in PostgreSQL: discord_id, minecraft_username, minecraft_uuid
6. Master whitelist auto-syncs to all whitelisted servers
7. User can now join any Minecraft server

---

## Why Rewrite?

**Current Whitelist Manager is broken:**
- Hardcoded server name keywords (fails when servers change)
- WebSocket console commands (unreliable, returns "UNKNOWN")
- No subscription integration
- No master whitelist concept
- Manual-only operation

**Current Arbiter doesn't:**
- Store Minecraft usernames
- Communicate with Whitelist Manager
- Handle subscription-driven whitelist access

---

## Architecture Decisions

All validated by Gemini AI consultation (March 31, 2026):

✅ **Single unified app** - Arbiter 2.x replaces both services  
✅ **PostgreSQL** - Concurrent write safety at 500-user scale  
✅ **Discord `/link` slash command** - Mojang API validation  
✅ **Pterodactyl File Management API** - Replaces WebSocket console  
✅ **Hybrid sync** - Event-driven push + hourly cron reconciliation  
✅ **UUIDs with dashes** - Minecraft 1.8+ requirement  

---

## Implementation Phases

### Phase 1: Database Migration
- [ ] Provision PostgreSQL 15+
- [ ] Execute schema creation
- [ ] Apply indexes for 500-user scale
- [ ] Migrate legacy SQLite data

### Phase 2: Core Functions
- [ ] pg connection pool
- [ ] Mojang API validation + UUID formatting
- [ ] Pterodactyl Application API (auto-discovery)
- [ ] Pterodactyl Client API (file write, commands)

### Phase 3: Discord Integration
- [ ] `/link` slash command registration
- [ ] UUID validation flow
- [ ] Auto-DM new subscribers
- [ ] Paymenter webhook updates

### Phase 4: Sync System
- [ ] Event-driven immediate sync
- [ ] node-cron hourly reconciliation
- [ ] Sequential batch processing
- [ ] Sync logging to database

### Phase 5: Admin Panel
- [ ] server_sync_log dashboard
- [ ] Manual "Force Sync" trigger
- [ ] Linked accounts view
- [ ] Production deployment

---

## Critical Gotchas

From Gemini consultation - these will break production if missed:

1. **Content-Type: text/plain** for Panel file write (NOT application/json)
2. **Mojang UUIDs without dashes**, Minecraft needs **WITH dashes**
3. **HTTP 412 = server offline**, NOT an error (file saved for next boot)
4. **Sequential processing** prevents Panel API rate limiting
5. **Application API** for discovery, **Client API** for file operations

---

## Database Schema

```sql
CREATE TABLE users (
    discord_id VARCHAR(255) PRIMARY KEY,
    minecraft_username VARCHAR(255) UNIQUE,
    minecraft_uuid VARCHAR(255) UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE subscriptions (
    id SERIAL PRIMARY KEY,
    discord_id VARCHAR(255) REFERENCES users(discord_id),
    tier_level INT NOT NULL,
    status VARCHAR(50) NOT NULL, -- active, grace_period, cancelled
    stripe_customer_id VARCHAR(255)
);

CREATE TABLE server_sync_log (
    server_identifier VARCHAR(50) PRIMARY KEY,
    last_successful_sync TIMESTAMP,
    last_error TEXT,
    is_online BOOLEAN DEFAULT true
);

CREATE INDEX idx_users_discord_id ON users(discord_id);
CREATE INDEX idx_subscriptions_status ON subscriptions(status);
```

---

## Success Criteria

- User subscribes → links account → auto-whitelisted within 5 minutes
- Master whitelist = database (single source of truth)
- All servers sync from master (hourly reconciliation)
- Server discovery is automatic (no hardcoded names)
- Works reliably for remote RV operations
- Handles 500 subscribers by September 2027

---

## What Gets Retired

Once Arbiter 2.x is deployed:

- ❌ Old Whitelist Manager (Python Flask on Billing VPS)
- ❌ Old Arbiter 1.x (if not already migrated)
- ✅ Update all documentation to reference unified system

---

## Dependencies

- PostgreSQL 15+
- Node.js 20 LTS  
- Pterodactyl Panel v1.12.1 (Client + Application API keys)
- Mojang API (public, no auth)
- Discord Bot with slash command permissions

---

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