import { IconActivity as Activity, IconAlertCircle as AlertCircle, IconCircleCheck as CheckCircle2, IconCloud as Cloud, IconContainer as Container, IconDatabase as Database, IconWorld as Globe, IconDeviceSdCard as HardDrive, IconLoader2 as Loader2, IconNetwork as Network, IconServer as Server, IconShield as Shield, } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import { ServicesStatus } from '@/components/admin/ServicesStatus'; import { ContentPanel } from '@/components/ContentPanel'; import { PageHeader } from '@/components/PageHeader'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { apiJson } from '@/lib/api'; import { cn } from '@/lib/utils'; interface ServiceStatus { name: string; container: string; status: 'healthy' | 'unhealthy' | 'unknown'; latencyMs?: number; error?: string; } interface ServicesStatusResponse { summary: { healthy: number; unhealthy: number; total: number }; services: ServiceStatus[]; timestamp: string; } export async function fetchServicesStatus(): Promise { return apiJson('/api/_internal/services/status', {}, 'Failed to fetch'); } // Service topology: layers from top (user-facing) to bottom (data) const TOPOLOGY_LAYERS = [ { name: 'Edge', icon: Globe, services: ['traefik'], description: 'Load balancer & reverse proxy', }, { name: 'API Gateway', icon: Shield, services: ['kong'], description: 'Authentication & rate limiting', }, { name: 'Application', icon: Server, services: ['auth', 'rest', 'realtime', 'storage', 'meta', 'studio'], description: 'Core Supabase services', }, { name: 'Data', icon: Database, services: ['db', 'redis'], description: 'PostgreSQL & caching', }, { name: 'Observability', icon: Activity, services: ['prometheus', 'grafana', 'loki'], description: 'Monitoring & logging', }, { name: 'Tooling', icon: Container, services: ['n8n', 'metabase', 'imgproxy'], description: 'Automation, analytics & media', }, ] as const; function StatusDot({ status }: { status: 'healthy' | 'unhealthy' | 'unknown' | 'not_running' }) { return ( ); } export default function Infrastructure() { const { data, isLoading } = useQuery({ queryKey: ['services-status'], queryFn: fetchServicesStatus, refetchInterval: 30000, staleTime: 10000, }); const serviceMap = new Map(data?.services.map((s) => [s.container, s]) ?? []); return ( <> {/* Summary badges */} {data && (
{data.summary.healthy} healthy {data.summary.unhealthy > 0 && ( {data.summary.unhealthy} unhealthy )} {data.summary.total} services
)} {/* Topology */} Service Topology Visual map of your infrastructure stack {isLoading ? (
) : (
{TOPOLOGY_LAYERS.map((layer, i) => { const layerServices = layer.services .map((name) => ({ name, status: serviceMap.get(name), })) .filter((s) => s.status || layer.services.length <= 3); if (layerServices.length === 0) return null; return (
{/* Layer */}
{layer.name} ({layer.description})
{layerServices.map((svc) => (
{svc.status?.name ?? svc.name} {svc.status?.latencyMs !== undefined && svc.status.status === 'healthy' && ( {svc.status.latencyMs}ms )}
))}
{/* Connector */} {i < TOPOLOGY_LAYERS.length - 1 && layerServices.length > 0 && (
)}
); })}
)} {/* Deployment info */} Deployment Configuration and deployment details
s.container.includes('standby')) ? 'Multi-region' : 'Single region' } />
{/* Full services status (existing component) */} ); } function InfoRow({ label, value }: { label: string; value: string }) { return (

{label}

{value}

); }