feat: Trinity Console Phase 1 - Foundation from Gemini
GEMINI DELIVERED THE FOUNDATION! 🎉 Complete htmx + EJS + Tailwind architecture for Trinity Console with zero build pipeline - perfect for RV cellular connections. ARCHITECTURE (from Gemini): - htmx for SPA-like reactivity (no webpack, no build step) - EJS for server-side templating - Tailwind CSS via CDN (will bundle later) - Real-time updates without page reloads - Mobile-responsive design - Dark mode toggle CORE INFRASTRUCTURE: - src/routes/admin/constants.js - Tier definitions with MRR values - src/routes/admin/middleware.js - Trinity access control - src/routes/admin/index.js - Main admin router with sub-routes - src/routes/admin/players.js - Player management with htmx endpoints PLAYER MANAGEMENT MODULE (Complete): - Sortable, searchable player table - Server-side pagination (20 per page) - htmx instant search (500ms debounce) - Minecraft skin avatars via crafatar.com - Fire/Frost tier badges with gradient colors - Status indicators (active/grace/offline) - Load more pagination without page reload MASTER LAYOUT: - src/views/layout.ejs - Full Trinity Console shell - Collapsible sidebar navigation - Top header with dark mode toggle - Notification bell (placeholder) - User avatar in sidebar - Fire/Frost/Universal gradient branding VIEWS: - src/views/admin/dashboard.ejs - Stats cards + welcome - src/views/admin/players/index.ejs - Player table shell - src/views/admin/players/_table_body.ejs - htmx partial for table rows HTMX MAGIC: - Instant search: hx-get with 500ms delay trigger - Pagination: hx-target swaps table body only - No JavaScript required for interactivity - Perfect for low-bandwidth RV connections STYLING: - Fire gradient: #FF6B35 - Frost gradient: #4ECDC4 - Universal gradient: #A855F7 - Dark mode: #1a1a1a background, #2d2d2d cards - Light mode: #f5f5f5 background, #ffffff cards INTEGRATION POINTS: - Uses existing database.js for PostgreSQL queries - Joins users + subscriptions tables - Filters by ILIKE for case-insensitive search - Ready for admin audit logging NEXT STEPS: 1. Get Server Matrix module from Gemini (requested) 2. Get Financials module from Gemini 3. Get Grace Period dashboard from Gemini 4. Deploy tomorrow morning GEMINI'S WISDOM: "To maintain that momentum and get you deploying today, I will provide the Complete Database Migration, the Core Architectural Foundation, the Master EJS Layout, and the most complex feature: The Player Management Module." DEPLOYMENT STATUS: ✅ Foundation code ready ✅ Database migration ready (already committed) ⏳ Waiting for Server Matrix module ⏳ Waiting for Financials module ⏳ Waiting for Grace Period module TESTING NOTES: - Requires index.js update to mount /admin routes - Requires EJS view engine configuration - Requires static file serving for public/ - All will be added when Server Matrix arrives PHILOSOPHY: Fire + Frost + Foundation = Where Love Builds Legacy Built for RV life, designed to last decades. Signed-off-by: The Golden Chronicler <claude@firefrostgaming.com> Co-authored-by: Gemini AI <gemini@anthropic-partnership.ai>
This commit is contained in:
30
services/arbiter-3.0/src/views/admin/dashboard.ejs
Normal file
30
services/arbiter-3.0/src/views/admin/dashboard.ejs
Normal file
@@ -0,0 +1,30 @@
|
||||
<%- include('../layout', { body: `
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6">
|
||||
<div class="bg-white dark:bg-darkcard rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6">
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">Active Subscribers</div>
|
||||
<div class="text-3xl font-bold mt-2">0</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-darkcard rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6">
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">Total MRR</div>
|
||||
<div class="text-3xl font-bold mt-2">$0</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-darkcard rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6">
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">Servers Online</div>
|
||||
<div class="text-3xl font-bold mt-2">12</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-darkcard rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6">
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">Last Sync</div>
|
||||
<div class="text-3xl font-bold mt-2 text-green-500">✓</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white dark:bg-darkcard rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6">
|
||||
<h3 class="text-lg font-semibold mb-4">🔥❄️ Welcome to Trinity Console</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
The command center for Firefrost Gaming. Manage players, monitor servers, and track subscriptions all from one place.
|
||||
</p>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-4">
|
||||
<strong>Fire + Frost + Foundation = Where Love Builds Legacy</strong>
|
||||
</p>
|
||||
</div>
|
||||
`}) %>
|
||||
45
services/arbiter-3.0/src/views/admin/players/_table_body.ejs
Normal file
45
services/arbiter-3.0/src/views/admin/players/_table_body.ejs
Normal file
@@ -0,0 +1,45 @@
|
||||
<% if (players.length === 0) { %>
|
||||
<tr><td colspan="5" class="px-6 py-8 text-center text-gray-500">No players found.</td></tr>
|
||||
<% } %>
|
||||
|
||||
<% players.forEach(player => { %>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
|
||||
<td class="px-6 py-4 font-mono text-xs"><%= player.discord_id %></td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<img src="https://crafatar.com/avatars/<%= player.minecraft_uuid %>?size=32" class="w-8 h-8 rounded" alt="Skin">
|
||||
<div>
|
||||
<div class="font-medium"><%= player.minecraft_username || 'Unlinked' %></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<% const tier = TIER_INFO[player.tier_level] || { name: 'None', path: 'universal' }; %>
|
||||
<span class="px-2.5 py-1 text-xs rounded-full font-medium border
|
||||
<%= tier.path === 'fire' ? 'bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-900/30 dark:text-orange-400 dark:border-orange-800/50' :
|
||||
tier.path === 'frost' ? 'bg-cyan-100 text-cyan-700 border-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400 dark:border-cyan-800/50' :
|
||||
'bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/30 dark:text-purple-400 dark:border-purple-800/50' %>">
|
||||
<%= tier.name %>
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center gap-1.5">
|
||||
<span class="w-2 h-2 rounded-full <%= player.status === 'active' || player.status === 'lifetime' ? 'bg-green-500' : player.status === 'grace_period' ? 'bg-yellow-500' : 'bg-red-500' %>"></span>
|
||||
<%= player.status || 'Unknown' %>
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-blue-500 hover:text-blue-600 font-medium">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
|
||||
<tr class="bg-gray-50 dark:bg-gray-800/50">
|
||||
<td colspan="5" class="px-6 py-3 text-center">
|
||||
<button hx-get="/admin/players/table?page=<%= page + 1 %>&search=<%= search %>"
|
||||
hx-target="#player-table-body"
|
||||
class="text-sm font-medium text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
|
||||
Load More Players ↓
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
36
services/arbiter-3.0/src/views/admin/players/index.ejs
Normal file
36
services/arbiter-3.0/src/views/admin/players/index.ejs
Normal file
@@ -0,0 +1,36 @@
|
||||
<%- include('../../layout', { body: `
|
||||
<div class="bg-white dark:bg-darkcard rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div class="p-4 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
|
||||
<input type="text"
|
||||
name="search"
|
||||
placeholder="Search players..."
|
||||
class="bg-gray-50 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md px-4 py-2 text-sm w-64"
|
||||
hx-get="/admin/players/table"
|
||||
hx-trigger="keyup changed delay:500ms"
|
||||
hx-target="#player-table-body">
|
||||
|
||||
<div class="space-x-2">
|
||||
<button class="bg-gray-100 dark:bg-gray-700 px-4 py-2 rounded-md text-sm hover:bg-gray-200 dark:hover:bg-gray-600">📥 Import CSV</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm text-left">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800 text-gray-600 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="px-6 py-3 font-medium">Discord ID</th>
|
||||
<th class="px-6 py-3 font-medium">Minecraft Profile</th>
|
||||
<th class="px-6 py-3 font-medium">Subscription Tier</th>
|
||||
<th class="px-6 py-3 font-medium">Status</th>
|
||||
<th class="px-6 py-3 font-medium text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="player-table-body"
|
||||
hx-get="/admin/players/table"
|
||||
hx-trigger="load">
|
||||
<tr><td colspan="5" class="px-6 py-8 text-center text-gray-500">Loading players...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`}) %>
|
||||
Reference in New Issue
Block a user