import Link from 'next/link'; import { computeMetrics } from '@/lib/admin/metrics'; import { getSupabaseAdmin } from '@/lib/supabase/admin'; import { formatBytes, formatDate } from '@/lib/format'; export const dynamic = 'force-dynamic'; export const revalidate = 0; type OverQuotaRow = { user_id: string; subdomain: string; bytes_used: number; quota_bytes: number; }; export default async function AdminOverviewPage() { const metrics = await computeMetrics(); const admin = getSupabaseAdmin(); // Recent signups (latest 5 users). const { data: recentUsersData } = await admin.auth.admin.listUsers({ page: 1, perPage: 5, }); const recentUsers = recentUsersData?.users ?? []; // Over-quota tunnels (compute in memory). const { data: tunnelsData } = await admin .from('tunnels') .select('user_id, subdomain, bytes_used, quota_bytes'); const overQuota = ((tunnelsData ?? []) as OverQuotaRow[]) .filter((t) => t.quota_bytes > 0 && t.bytes_used >= t.quota_bytes) .slice(0, 5); const kpis: { label: string; value: string }[] = [ { label: 'Total users', value: String(metrics.totalUsers) }, { label: 'Total tunnels', value: String(metrics.totalTunnels) }, { label: 'Active tunnels', value: String(metrics.activeTunnels) }, { label: 'Inactive tunnels', value: String(metrics.inactiveTunnels) }, { label: 'Over quota', value: String(metrics.overQuota) }, { label: 'Active last 24h', value: String(metrics.recentlyActive) }, { label: 'Signups (7d)', value: String(metrics.signups7d) }, { label: 'Signups (30d)', value: String(metrics.signups30d) }, { label: 'Bandwidth used', value: formatBytes(metrics.bytesUsedTotal) }, { label: 'Total quota', value: formatBytes(metrics.quotaTotal) }, ]; return (

Overview

{kpis.map((k) => (
{k.value}
{k.label}
))}

Recent signups

{recentUsers.length === 0 ? (

No users yet.

) : ( {recentUsers.map((u) => ( ))}
Email Joined
{u.email ?? u.id} {formatDate(u.created_at)}
)}

Over-quota tunnels

{overQuota.length === 0 ? (

None over quota.

) : ( {overQuota.map((t) => ( ))}
Subdomain Usage
{t.subdomain} {formatBytes(t.bytes_used)} / {formatBytes(t.quota_bytes)}
)}
); }