Fix Trinity Console dashboard: dynamic server/subscriber counts

Dashboard was showing hardcoded values:
- Servers Online: 12 (should be 22)
- Active Subscribers: 0
- Total MRR: $0

Now fetches live data:
- Server count from Pterodactyl API via getMinecraftServers()
- Subscriber count and MRR from arbiter_db subscriptions table

Files changed:
- src/routes/admin/index.js: async dashboard route with data fetching
- src/views/admin/dashboard.ejs: EJS variables instead of hardcoded values

Chronicler #69
This commit is contained in:
Claude
2026-04-08 08:19:10 +00:00
parent 567164ef7d
commit 3666241aac
2 changed files with 42 additions and 5 deletions

View File

@@ -1,6 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { requireTrinityAccess } = require('./middleware'); const { requireTrinityAccess } = require('./middleware');
const { getMinecraftServers } = require('../../panel/discovery');
const db = require('../../database');
// Sub-routers // Sub-routers
const playersRouter = require('./players'); const playersRouter = require('./players');
@@ -23,8 +25,43 @@ router.get('/', (req, res) => {
res.redirect('/admin/dashboard'); res.redirect('/admin/dashboard');
}); });
router.get('/dashboard', (req, res) => { router.get('/dashboard', async (req, res) => {
res.render('admin/dashboard', { title: 'Command Bridge' }); try {
// Fetch server count from Pterodactyl
const servers = await getMinecraftServers();
const serversOnline = servers.length;
// Fetch subscriber stats from database
const { rows: subStats } = await db.query(`
SELECT
COUNT(*) FILTER (WHERE status IN ('active', 'grace_period', 'lifetime')) as active_count,
COALESCE(SUM(CASE
WHEN status = 'active' AND tier_id IS NOT NULL THEN
(SELECT price FROM subscription_tiers WHERE id = tier_id)
ELSE 0
END), 0) as mrr
FROM subscriptions
`);
const activeSubscribers = parseInt(subStats[0]?.active_count || 0);
const totalMRR = parseFloat(subStats[0]?.mrr || 0);
res.render('admin/dashboard', {
title: 'Command Bridge',
serversOnline,
activeSubscribers,
totalMRR
});
} catch (error) {
console.error('Dashboard data fetch error:', error);
// Fallback to zeros on error
res.render('admin/dashboard', {
title: 'Command Bridge',
serversOnline: 0,
activeSubscribers: 0,
totalMRR: 0
});
}
}); });
router.use('/players', playersRouter); router.use('/players', playersRouter);

View File

@@ -1,15 +1,15 @@
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6"> <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="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-sm text-gray-500 dark:text-gray-400">Active Subscribers</div>
<div class="text-3xl font-bold mt-2">0</div> <div class="text-3xl font-bold mt-2"><%= activeSubscribers %></div>
</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="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-sm text-gray-500 dark:text-gray-400">Total MRR</div>
<div class="text-3xl font-bold mt-2">$0</div> <div class="text-3xl font-bold mt-2">$<%= totalMRR.toFixed(0) %></div>
</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="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-sm text-gray-500 dark:text-gray-400">Servers Online</div>
<div class="text-3xl font-bold mt-2">12</div> <div class="text-3xl font-bold mt-2"><%= serversOnline %></div>
</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="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-sm text-gray-500 dark:text-gray-400">Last Sync</div>