Spaces:
Runtime error
Runtime error
| import React, { useState, useEffect, useRef } from 'react'; | |
| import { | |
| Activity, | |
| ShieldAlert, | |
| Terminal, | |
| Settings, | |
| TrendingUp, | |
| Database, | |
| Network, | |
| Flame, | |
| History, | |
| Map, | |
| Info, | |
| RefreshCw, | |
| Zap, | |
| CheckCircle, | |
| XCircle, | |
| AlertTriangle, | |
| LogOut, | |
| ArrowRight, | |
| Shield, | |
| Lock, | |
| Globe, | |
| Server, | |
| Award | |
| } from 'lucide-react'; | |
| import { | |
| AreaChart, | |
| Area, | |
| XAxis, | |
| YAxis, | |
| CartesianGrid, | |
| Tooltip, | |
| ResponsiveContainer, | |
| BarChart, | |
| Bar, | |
| Legend | |
| } from 'recharts'; | |
| // Dynamically resolve API and WebSocket endpoints to support network sharing and tunnels | |
| const getBackendUrls = () => { | |
| const protocol = window.location.protocol; | |
| const hostname = window.location.hostname; | |
| const port = window.location.port; | |
| // Check if env variable is defined (e.g. on Vercel deployment) | |
| const envApiUrl = import.meta.env.VITE_API_URL; | |
| if (envApiUrl) { | |
| return { | |
| api: envApiUrl, | |
| ws: envApiUrl.replace('http', 'ws') + '/ws' | |
| }; | |
| } | |
| // If accessed directly via Vite dev server port, use port 8000 for backend | |
| if (port === '5173' || port === '5174') { | |
| return { | |
| api: `${protocol}//${hostname}:8000`, | |
| ws: `${protocol === 'https:' ? 'wss:' : 'ws:'}//${hostname}:8000/ws` | |
| }; | |
| } else { | |
| // If accessed via Nginx gateway (port 8080) or public tunnel (port 80/443), use relative host/port | |
| const host = window.location.host; // includes port if present (like :8080) | |
| return { | |
| api: `${protocol}//${host}`, | |
| ws: `${protocol === 'https:' ? 'wss:' : 'ws:'}//${host}/ws` | |
| }; | |
| } | |
| }; | |
| const urls = getBackendUrls(); | |
| const API_URL = urls.api; | |
| const WS_URL = urls.ws; | |
| // Interactive Playground Widget for Marketing page | |
| function InteractivePlayground() { | |
| const [crashed, setCrashed] = useState(false); | |
| const [rateLimit, setRateLimit] = useState(100); | |
| const [cbState, setCbState] = useState("CLOSED"); | |
| useEffect(() => { | |
| let t; | |
| if (crashed) { | |
| setCbState("OPEN"); | |
| setRateLimit(10); | |
| } else { | |
| setCbState("HALF_OPEN"); | |
| t = setTimeout(() => { | |
| setCbState("CLOSED"); | |
| setRateLimit(100); | |
| }, 3000); | |
| } | |
| return () => clearTimeout(t); | |
| }, [crashed]); | |
| return ( | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-2xl relative overflow-hidden"> | |
| <div className="absolute top-0 right-0 w-32 h-32 bg-emerald-500/5 rounded-full filter blur-xl" /> | |
| <h4 className="text-white font-bold text-sm tracking-wider uppercase mb-4 flex items-center gap-2 font-mono"> | |
| <Zap className="h-4 w-4 text-emerald-400" /> | |
| Interactive Resiliency Simulator | |
| </h4> | |
| <p className="text-slate-400 text-xs mb-6"> | |
| Simulate downstream failures to observe automatic circuit breaker state changes and rate limit clamping. | |
| </p> | |
| <div className="flex justify-between items-center py-6 relative"> | |
| <div className="flex gap-4 items-center w-full justify-around z-10"> | |
| <div className="text-center"> | |
| <div className="h-14 w-14 rounded-full border-2 border-emerald-500 bg-darkCard/80 flex items-center justify-center shadow-lg shadow-emerald-500/10"> | |
| <span className="text-xs font-mono font-bold text-white">Svc A</span> | |
| </div> | |
| <p className="text-[10px] text-slate-500 font-mono mt-2">Rate: {rateLimit} RPS</p> | |
| </div> | |
| <div className="w-8 h-0.5 bg-slate-800" /> | |
| <div className="text-center"> | |
| <div className={`h-14 w-14 rounded-full border-2 bg-darkCard/80 flex items-center justify-center shadow-lg transition-all ${cbState === 'CLOSED' ? 'border-emerald-500 shadow-emerald-500/10' : cbState === 'OPEN' ? 'border-red-500 shadow-red-500/10' : 'border-blue-400 shadow-blue-400/10'}`}> | |
| <span className="text-xs font-mono font-bold text-white">Svc B</span> | |
| </div> | |
| <p className="text-[10px] text-slate-500 font-mono mt-2">CB: {cbState}</p> | |
| </div> | |
| <div className="w-8 h-0.5 bg-slate-800" /> | |
| <div className="text-center"> | |
| <div className={`h-14 w-14 rounded-full border-2 bg-darkCard/80 flex items-center justify-center shadow-lg transition-all ${crashed ? 'border-red-500 shadow-red-500/20' : 'border-emerald-500 shadow-emerald-500/10'}`}> | |
| <span className="text-xs font-mono font-bold text-white">Svc C</span> | |
| </div> | |
| <p className="text-[10px] text-slate-500 font-mono mt-2">{crashed ? "CRASHED" : "HEALTHY"}</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="flex gap-4 mt-4"> | |
| <button | |
| onClick={() => setCrashed(!crashed)} | |
| className={`w-full py-2.5 rounded-lg text-xs font-bold font-mono transition-all duration-300 ${crashed ? 'bg-emerald-500 text-slate-900 shadow-lg shadow-emerald-500/20 hover:bg-emerald-400' : 'bg-rose-500 text-white shadow-lg shadow-rose-500/20 hover:bg-rose-400'}`} | |
| > | |
| {crashed ? "Recover Service C" : "Simulate Service C Crash"} | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default function App() { | |
| const [isLoggedIn, setIsLoggedIn] = useState(() => { | |
| return localStorage.getItem('pulseguard_logged_in') === 'true'; | |
| }); | |
| const [activeTab, setActiveTab] = useState('landing'); | |
| const [connected, setConnected] = useState(false); | |
| const [data, setData] = useState({ | |
| services: { | |
| "service-a": { limit_capacity: 100, limit_rate: 100, circuit_state: "CLOSED", status: "HEALTHY", rps: 0, error_rate: 0, p50: 0, p95: 0, p99: 0, total_requests: 0 }, | |
| "service-b": { limit_capacity: 100, limit_rate: 100, circuit_state: "CLOSED", status: "HEALTHY", rps: 0, error_rate: 0, p50: 0, p95: 0, p99: 0, total_requests: 0 }, | |
| "service-c": { limit_capacity: 100, limit_rate: 100, circuit_state: "CLOSED", status: "HEALTHY", rps: 0, error_rate: 0, p50: 0, p95: 0, p99: 0, total_requests: 0 } | |
| }, | |
| events: [], | |
| audits: [] | |
| }); | |
| const [benchmarks, setBenchmarks] = useState([]); | |
| const [benchmarkLoading, setBenchmarkLoading] = useState(false); | |
| const [chaosState, setChaosState] = useState({ | |
| "service-a": { delay: 0, error_rate: 0, crash: false, cpu_load: 0, memory_load: 0, packet_loss: 0 }, | |
| "service-b": { delay: 0, error_rate: 0, crash: false, cpu_load: 0, memory_load: 0, packet_loss: 0 }, | |
| "service-c": { delay: 0, error_rate: 0, crash: false, cpu_load: 0, memory_load: 0, packet_loss: 0 } | |
| }); | |
| const [generatorRps, setGeneratorRps] = useState(50); | |
| const [history, setHistory] = useState([]); // Real-time charting history | |
| const socketRef = useRef(null); | |
| // Connect to websocket when logged in | |
| useEffect(() => { | |
| if (!isLoggedIn) return; | |
| const connectWS = () => { | |
| socketRef.current = new WebSocket(WS_URL); | |
| socketRef.current.onopen = () => { | |
| setConnected(true); | |
| console.log('WebSocket Connected'); | |
| }; | |
| socketRef.current.onmessage = (event) => { | |
| try { | |
| const payload = JSON.parse(event.data); | |
| setData(payload); | |
| // Push to charting history | |
| setHistory(prev => { | |
| const newHistory = [...prev, { | |
| time: new Date().toLocaleTimeString(), | |
| "Service A Latency": (payload.services["service-a"]?.p95 || 0) * 1000, | |
| "Service B Latency": (payload.services["service-b"]?.p95 || 0) * 1000, | |
| "Service C Latency": (payload.services["service-c"]?.p95 || 0) * 1000, | |
| "Service A RPS": payload.services["service-a"]?.rps || 0, | |
| "Service B RPS": payload.services["service-b"]?.rps || 0, | |
| "Service C RPS": payload.services["service-c"]?.rps || 0 | |
| }]; | |
| if (newHistory.length > 20) newHistory.shift(); | |
| return newHistory; | |
| }); | |
| } catch (err) { | |
| console.error('Error parsing websocket payload:', err); | |
| } | |
| }; | |
| socketRef.current.onclose = () => { | |
| setConnected(false); | |
| console.log('WebSocket Disconnected. Reconnecting...'); | |
| setTimeout(connectWS, 3000); | |
| }; | |
| }; | |
| connectWS(); | |
| return () => { | |
| if (socketRef.current) socketRef.current.close(); | |
| }; | |
| }, [isLoggedIn]); | |
| // Fetch benchmarks and chaos configurations when logged in | |
| const fetchBenchmarks = async () => { | |
| try { | |
| const res = await fetch(`${API_URL}/api/benchmarks`); | |
| const body = await res.json(); | |
| setBenchmarks(body); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| }; | |
| const fetchChaosStatus = async () => { | |
| try { | |
| const res = await fetch(`${API_URL}/api/chaos/status`); | |
| const body = await res.json(); | |
| setChaosState(body); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| }; | |
| useEffect(() => { | |
| if (!isLoggedIn) return; | |
| fetchBenchmarks(); | |
| fetchChaosStatus(); | |
| const interval = setInterval(() => { | |
| fetchBenchmarks(); | |
| fetchChaosStatus(); | |
| }, 5000); | |
| return () => clearInterval(interval); | |
| }, [isLoggedIn]); | |
| const triggerChaos = async (service, type, val) => { | |
| const current = chaosState[service] || { delay: 0, error_rate: 0, crash: false, cpu_load: 0, memory_load: 0, packet_loss: 0 }; | |
| const payload = { ...current, [type]: val }; | |
| try { | |
| await fetch(`${API_URL}/api/chaos/inject/${service}`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(payload) | |
| }); | |
| fetchChaosStatus(); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| }; | |
| const clearChaos = async (service) => { | |
| try { | |
| await fetch(`${API_URL}/api/chaos/clear/${service}`, { | |
| method: 'POST' | |
| }); | |
| fetchChaosStatus(); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| }; | |
| const updateGeneratorRps = async (rps) => { | |
| setGeneratorRps(rps); | |
| try { | |
| await fetch(`${API_URL}/api/generator/rps?rps=${rps}`, { | |
| method: 'POST' | |
| }); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| }; | |
| const runResilienceBenchmark = async (hasProtection) => { | |
| setBenchmarkLoading(true); | |
| try { | |
| await fetch(`${API_URL}/api/benchmark/start?test_name=${hasProtection ? "With PulseGuard Protection" : "Without Protection"}&has_protection=${hasProtection}`, { | |
| method: 'POST' | |
| }); | |
| alert("Benchmark started! It will run in the background for 30s. Observe metrics live."); | |
| setTimeout(() => { | |
| fetchBenchmarks(); | |
| setBenchmarkLoading(false); | |
| }, 28000); | |
| } catch (err) { | |
| console.error(err); | |
| setBenchmarkLoading(false); | |
| } | |
| }; | |
| const handleLogin = () => { | |
| setIsLoggedIn(true); | |
| localStorage.setItem('pulseguard_logged_in', 'true'); | |
| }; | |
| const handleLogout = () => { | |
| setIsLoggedIn(false); | |
| localStorage.setItem('pulseguard_logged_in', 'false'); | |
| }; | |
| const getStatusColor = (status) => { | |
| if (status === 'HEALTHY') return 'text-emerald-400'; | |
| if (status === 'DEGRADED') return 'text-amber-400'; | |
| if (status === 'CRITICAL') return 'text-red-400'; | |
| return 'text-blue-400'; | |
| }; | |
| const getStatusBg = (status) => { | |
| if (status === 'HEALTHY') return 'glass-panel-glow-green border-emerald-500/20'; | |
| if (status === 'DEGRADED') return 'bg-amber-500/5 border-amber-500/20 shadow-glow-yellow'; | |
| if (status === 'CRITICAL') return 'glass-panel-glow-red border-red-500/20'; | |
| return 'glass-panel-glow-blue border-blue-500/20'; | |
| }; | |
| const getCircuitColor = (state) => { | |
| if (state === 'CLOSED') return 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30'; | |
| if (state === 'OPEN') return 'bg-rose-500/20 text-rose-400 border border-rose-500/30'; | |
| return 'bg-blue-500/20 text-blue-400 border border-blue-500/30'; | |
| }; | |
| // 1. PUBLIC MARKETING LANDING PAGE | |
| if (!isLoggedIn) { | |
| return ( | |
| <div className="min-h-screen bg-[#06090D] text-slate-100 flex flex-col font-sans"> | |
| {/* Navbar */} | |
| <header className="h-20 border-b border-slate-900 px-8 flex items-center justify-between bg-darkCard/30 backdrop-blur sticky top-0 z-50"> | |
| <div className="flex items-center gap-3"> | |
| <div className="h-9 w-9 rounded-lg bg-emerald-500 flex items-center justify-center shadow-lg shadow-emerald-500/20"> | |
| <Activity className="h-5 w-5 text-slate-900" /> | |
| </div> | |
| <div> | |
| <h1 className="font-bold text-lg tracking-wider text-white">PULSEGUARD X</h1> | |
| <p className="text-[10px] text-slate-500 font-mono tracking-widest uppercase">Self-Healing Plane</p> | |
| </div> | |
| </div> | |
| <nav className="hidden md:flex gap-8 text-sm font-medium text-slate-400"> | |
| <a href="#features" className="hover:text-white transition-colors">Features</a> | |
| <a href="#simulator" className="hover:text-white transition-colors">Interactive Demo</a> | |
| <a href="#pricing" className="hover:text-white transition-colors">Pricing</a> | |
| <a href="https://localhost.run/docs/" target="_blank" rel="noreferrer" className="hover:text-white transition-colors">Docs</a> | |
| </nav> | |
| <button | |
| onClick={handleLogin} | |
| className="px-5 py-2.5 rounded-lg bg-emerald-500 text-slate-950 font-bold text-sm hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/20 flex items-center gap-2" | |
| > | |
| Enter Cockpit | |
| <ArrowRight className="h-4 w-4" /> | |
| </button> | |
| </header> | |
| {/* Hero Section */} | |
| <section className="py-20 px-8 max-w-6xl mx-auto flex flex-col lg:flex-row items-center gap-12 flex-1"> | |
| <div className="flex-1 space-y-6 text-left"> | |
| <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs font-mono font-bold text-emerald-400 uppercase tracking-wider"> | |
| <Shield className="h-3 w-3" /> | |
| SOC2 Type II Compliant Autonomous Plane | |
| </div> | |
| <h2 className="text-4xl lg:text-6xl font-extrabold text-white leading-tight"> | |
| Self-Healing <span className="text-transparent bg-clip-text bg-gradient-to-r from-emerald-400 to-teal-300">Resiliency</span> for Microservices | |
| </h2> | |
| <p className="text-slate-400 text-base lg:text-lg leading-relaxed"> | |
| Stop cascading service failures in real time. PulseGuard X intercepts downstream bottlenecks, propagates upstream backpressure, manages token-bucket rate limits, and automatically heals degraded states. | |
| </p> | |
| <div className="flex flex-wrap gap-4 pt-2"> | |
| <button | |
| onClick={handleLogin} | |
| className="px-6 py-3 rounded-lg bg-emerald-500 text-slate-900 font-bold hover:bg-emerald-400 transition-all flex items-center gap-2 shadow-lg shadow-emerald-500/25" | |
| > | |
| Launch Live Platform | |
| <ArrowRight className="h-4 w-4" /> | |
| </button> | |
| <a | |
| href="#simulator" | |
| className="px-6 py-3 rounded-lg bg-slate-900 border border-slate-800 text-slate-200 font-bold hover:bg-slate-800 transition-all flex items-center justify-center" | |
| > | |
| Try Sandbox Demo | |
| </a> | |
| </div> | |
| </div> | |
| <div className="flex-1 w-full max-w-md lg:max-w-none"> | |
| <InteractivePlayground /> | |
| </div> | |
| </section> | |
| {/* Features Section */} | |
| <section id="features" className="py-24 bg-darkCard/20 border-t border-slate-900/60 px-8"> | |
| <div className="max-w-6xl mx-auto space-y-12"> | |
| <div className="text-center max-w-2xl mx-auto space-y-3"> | |
| <h3 className="text-xs font-mono font-bold text-emerald-400 uppercase tracking-widest">Enterprise Architecture</h3> | |
| <h2 className="text-2xl lg:text-3xl font-bold text-white">Engineered for Microservice Autonomy</h2> | |
| <p className="text-slate-500 text-sm"> | |
| Built to protect complex, distributed call chains (A → B → C) without human operator latency. | |
| </p> | |
| </div> | |
| <div className="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 hover:border-emerald-500/30 transition-all duration-300"> | |
| <div className="h-10 w-10 rounded-lg bg-emerald-500/10 flex items-center justify-center mb-6"> | |
| <Lock className="h-5 w-5 text-emerald-400" /> | |
| </div> | |
| <h4 className="text-white font-bold text-base mb-3 font-mono">Token Bucket Lua Engine</h4> | |
| <p className="text-slate-400 text-xs leading-relaxed"> | |
| Distributed, high-concurrency rate limiting executing atomic refill operations in Redis Lua. Prevents race conditions. | |
| </p> | |
| </div> | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 hover:border-emerald-500/30 transition-all duration-300"> | |
| <div className="h-10 w-10 rounded-lg bg-emerald-500/10 flex items-center justify-center mb-6"> | |
| <ShieldAlert className="h-5 w-5 text-emerald-400" /> | |
| </div> | |
| <h4 className="text-white font-bold text-base mb-3 font-mono">Cascading Backpressure</h4> | |
| <p className="text-slate-400 text-xs leading-relaxed"> | |
| Automatic upstream limit clamps and custom HTTP backpressure header propagation to prevent cascading connection queue locks. | |
| </p> | |
| </div> | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 hover:border-emerald-500/30 transition-all duration-300"> | |
| <div className="h-10 w-10 rounded-lg bg-emerald-500/10 flex items-center justify-center mb-6"> | |
| <RefreshCw className="h-5 w-5 text-emerald-400" /> | |
| </div> | |
| <h4 className="text-white font-bold text-base mb-3 font-mono">Anti-Flapping Controls</h4> | |
| <p className="text-slate-400 text-xs leading-relaxed"> | |
| Exponential Moving Average (EMA) latency monitoring and multi-tick validation prevent circuit breakers from flapping under transient spikes. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Simulator CTA */} | |
| <section id="simulator" className="py-16 px-8 max-w-4xl mx-auto text-center space-y-6"> | |
| <h2 className="text-2xl font-bold text-white">Experience Self-Healing Actions Live</h2> | |
| <p className="text-slate-400 text-sm"> | |
| Launch the live cockpit to run traffic generators, inject real chaos CPU/RAM loads, and analyze live Prometheus and Grafana dashboards in real time. | |
| </p> | |
| <div className="pt-2"> | |
| <button | |
| onClick={handleLogin} | |
| className="px-6 py-3 rounded-lg bg-emerald-500 text-slate-900 font-bold hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/20" | |
| > | |
| Enter Sandbox Cockpit | |
| </button> | |
| </div> | |
| </section> | |
| {/* Pricing Section */} | |
| <section id="pricing" className="py-24 bg-darkCard/20 border-t border-slate-900/60 px-8"> | |
| <div className="max-w-5xl mx-auto space-y-12"> | |
| <div className="text-center max-w-2xl mx-auto space-y-3"> | |
| <h3 className="text-xs font-mono font-bold text-emerald-400 uppercase tracking-widest">SaaS Licensing</h3> | |
| <h2 className="text-2xl lg:text-3xl font-bold text-white">Transparent Plans for Every Stack</h2> | |
| </div> | |
| <div className="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
| {/* Free Tier */} | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 flex flex-col justify-between"> | |
| <div> | |
| <h4 className="text-slate-400 text-xs font-mono uppercase">Developer Sandbox</h4> | |
| <p className="text-2xl font-extrabold text-white mt-2">$0</p> | |
| <p className="text-[10px] text-slate-500 font-mono">Free Forever</p> | |
| <ul className="mt-6 space-y-3 text-xs text-slate-400 font-mono"> | |
| <li className="flex items-center gap-2">✓ Service Chain: A → B → C</li> | |
| <li className="flex items-center gap-2">✓ Real Redis Token Bucket</li> | |
| <li className="flex items-center gap-2">✓ Live Chaos Injector</li> | |
| </ul> | |
| </div> | |
| <button onClick={handleLogin} className="mt-8 w-full py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs font-bold font-mono rounded"> | |
| Launch Sandbox | |
| </button> | |
| </div> | |
| {/* Pro Tier */} | |
| <div className="glass-panel p-8 rounded-xl border-2 border-emerald-500/30 flex flex-col justify-between relative shadow-lg shadow-emerald-500/5"> | |
| <div className="absolute -top-3.5 left-1/2 -translate-x-1/2 bg-emerald-500 text-slate-950 text-[10px] font-extrabold px-3 py-1 rounded-full uppercase tracking-wider"> | |
| Most Popular | |
| </div> | |
| <div> | |
| <h4 className="text-emerald-400 text-xs font-mono uppercase">Production Pro</h4> | |
| <p className="text-2xl font-extrabold text-white mt-2">$49<span className="text-xs font-mono text-slate-500">/mo</span></p> | |
| <p className="text-[10px] text-slate-500 font-mono">Per cluster node</p> | |
| <ul className="mt-6 space-y-3 text-xs text-slate-400 font-mono"> | |
| <li className="flex items-center gap-2 text-white">✓ Everything in Free</li> | |
| <li className="flex items-center gap-2">✓ Persistent Postgres Logs</li> | |
| <li className="flex items-center gap-2">✓ Dynamic SLO Overrides</li> | |
| <li className="flex items-center gap-2">✓ Slack/OpsGenie Alerts</li> | |
| </ul> | |
| </div> | |
| <button onClick={handleLogin} className="mt-8 w-full py-2 bg-emerald-500 hover:bg-emerald-400 text-slate-950 text-xs font-extrabold font-mono rounded shadow-lg shadow-emerald-500/10"> | |
| Upgrade to Pro | |
| </button> | |
| </div> | |
| {/* Enterprise Tier */} | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 flex flex-col justify-between"> | |
| <div> | |
| <h4 className="text-slate-400 text-xs font-mono uppercase">Custom Enterprise</h4> | |
| <p className="text-2xl font-extrabold text-white mt-2">Custom</p> | |
| <p className="text-[10px] text-slate-500 font-mono">Custom SLA contract</p> | |
| <ul className="mt-6 space-y-3 text-xs text-slate-400 font-mono"> | |
| <li className="flex items-center gap-2">✓ Unlimited Clusters</li> | |
| <li className="flex items-center gap-2">✓ Custom Lua Scripts</li> | |
| <li className="flex items-center gap-2">✓ 24/7 SRE Phone Support</li> | |
| </ul> | |
| </div> | |
| <button onClick={handleLogin} className="mt-8 w-full py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs font-bold font-mono rounded"> | |
| Contact Sales | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Footer */} | |
| <footer className="border-t border-slate-900 bg-slate-950/40 py-12 px-8 mt-auto"> | |
| <div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between items-center gap-6"> | |
| <div className="flex items-center gap-2"> | |
| <Activity className="h-4 w-4 text-emerald-400" /> | |
| <span className="font-bold text-xs tracking-wider text-white uppercase">PulseGuard X</span> | |
| </div> | |
| <div className="flex gap-6 text-xs text-slate-500 font-mono"> | |
| <a href="#" className="hover:text-slate-300">Terms of Use</a> | |
| <span>•</span> | |
| <a href="#" className="hover:text-slate-300">Privacy Policy</a> | |
| <span>•</span> | |
| <a href="#" className="hover:text-slate-300">SOC2 Trust Report</a> | |
| </div> | |
| <div className="text-[10px] text-slate-600 font-mono"> | |
| © {new Date().getFullYear()} PulseGuard Inc. All rights reserved. | |
| </div> | |
| </div> | |
| </footer> | |
| </div> | |
| ); | |
| } | |
| // 2. DASHBOARD APPLICATION COCKPIT (AFTER LOGIN) | |
| return ( | |
| <div className="flex h-screen bg-[#06090D] text-slate-100 overflow-hidden font-sans"> | |
| {/* Sidebar */} | |
| <aside className="w-64 bg-darkCard border-r border-slate-900/60 flex flex-col justify-between shrink-0"> | |
| <div> | |
| {/* Logo */} | |
| <div className="p-6 border-b border-slate-900/60 flex items-center gap-3"> | |
| <div className="h-9 w-9 rounded-lg bg-emerald-500 flex items-center justify-center shadow-lg shadow-emerald-500/20"> | |
| <Activity className="h-5 w-5 text-slate-900" /> | |
| </div> | |
| <div> | |
| <h1 className="font-bold text-lg tracking-wider text-white">PULSEGUARD X</h1> | |
| <p className="text-[10px] text-slate-500 font-mono tracking-widest uppercase">Self-Healing Plane</p> | |
| </div> | |
| </div> | |
| {/* Navigation Links */} | |
| <nav className="p-4 space-y-1"> | |
| <button | |
| onClick={() => setActiveTab('landing')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'landing' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Info className="h-4 w-4" /> | |
| <span>Cockpit Overview</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('dashboard')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'dashboard' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Activity className="h-4 w-4" /> | |
| <span>Reliability Dashboard</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('topology')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'topology' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Map className="h-4 w-4" /> | |
| <span>Network Topology</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('chaos')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'chaos' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Flame className="h-4 w-4" /> | |
| <span>Chaos Engineering</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('control-plane')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'control-plane' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Terminal className="h-4 w-4" /> | |
| <span>Control Decisions</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('timeline')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'timeline' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <History className="h-4 w-4" /> | |
| <span>Reliability Timeline</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('benchmarks')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'benchmarks' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <TrendingUp className="h-4 w-4" /> | |
| <span>Resilience Benchmarks</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('architecture')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'architecture' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Network className="h-4 w-4" /> | |
| <span>System Topology Map</span> | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('observability')} | |
| className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all duration-150 ${activeTab === 'observability' ? 'bg-emerald-500/10 text-emerald-400 font-medium' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'}`} | |
| > | |
| <Database className="h-4 w-4" /> | |
| <span>Observability Hub</span> | |
| </button> | |
| </nav> | |
| </div> | |
| {/* Footer info */} | |
| <div className="p-4 border-t border-slate-900/60 space-y-3 bg-slate-950/20"> | |
| <div className="flex items-center justify-between text-xs font-mono"> | |
| <span className="text-slate-500">Control Plane:</span> | |
| <span className={`flex items-center gap-1.5 font-medium ${connected ? 'text-emerald-400' : 'text-rose-400 animate-pulse'}`}> | |
| <span className={`h-1.5 w-1.5 rounded-full ${connected ? 'bg-emerald-400' : 'bg-rose-400'}`} /> | |
| {connected ? 'CONNECTED' : 'DISCONNECTED'} | |
| </span> | |
| </div> | |
| <button | |
| onClick={handleLogout} | |
| className="w-full flex items-center justify-center gap-2 py-2 border border-slate-800 hover:bg-slate-800/50 rounded-lg text-xs font-mono text-slate-400 hover:text-white transition-all" | |
| > | |
| <LogOut className="h-3.5 w-3.5" /> | |
| Sign Out | |
| </button> | |
| <div className="text-[10px] text-slate-600 font-mono text-center"> | |
| PULSEGUARD v1.0.0 | |
| </div> | |
| </div> | |
| </aside> | |
| {/* Main Content Area */} | |
| <main className="flex-1 flex flex-col min-w-0 bg-[#06090D] overflow-y-auto"> | |
| {/* Header */} | |
| <header className="h-16 border-b border-slate-900/60 flex items-center justify-between px-8 bg-darkCard/30 backdrop-blur shrink-0 z-10 sticky top-0"> | |
| <div className="flex items-center gap-4"> | |
| <h2 className="text-sm font-bold text-white uppercase tracking-wider font-mono"> | |
| {activeTab.replace('-', ' ')} | |
| </h2> | |
| </div> | |
| <div className="flex items-center gap-4"> | |
| {/* Quick System Health Metric */} | |
| <div className="flex items-center gap-6 text-xs text-slate-400 font-mono"> | |
| <div className="flex items-center gap-2"> | |
| <span>Active RPS:</span> | |
| <span className="text-white font-semibold"> | |
| {((data.services["service-a"]?.rps || 0) + (data.services["service-b"]?.rps || 0) + (data.services["service-c"]?.rps || 0)).toFixed(1)} | |
| </span> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <span>Avg Latency (P95):</span> | |
| <span className="text-white font-semibold"> | |
| {((((data.services["service-a"]?.p95 || 0) + (data.services["service-b"]?.p95 || 0) + (data.services["service-c"]?.p95 || 0)) / 3) * 1000).toFixed(0)}ms | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| {/* Tab Switchboard */} | |
| <div className="flex-1 p-8"> | |
| {/* Landing Page (Cockpit Overview) */} | |
| {activeTab === 'landing' && ( | |
| <div className="max-w-4xl mx-auto space-y-8"> | |
| <div className="bg-gradient-to-r from-emerald-500/10 via-teal-500/5 to-transparent border border-emerald-500/20 rounded-xl p-8 shadow-xl relative overflow-hidden"> | |
| <div className="absolute top-0 right-0 w-64 h-64 bg-emerald-500/5 rounded-full filter blur-3xl pointer-events-none" /> | |
| <h3 className="text-2xl font-bold text-white mb-2">PulseGuard X Reliability Control Plane</h3> | |
| <p className="text-slate-400 text-sm max-w-2xl leading-relaxed mb-6"> | |
| You are logged into the active cluster node cockpit. PulseGuard X manages distributed token-bucket rate limits, circuit breakers, and cascading backpressure propagation across this service grid. | |
| </p> | |
| <div className="flex gap-4"> | |
| <button | |
| onClick={() => setActiveTab('dashboard')} | |
| className="px-5 py-2.5 rounded-lg bg-emerald-500 text-slate-900 font-semibold text-sm hover:bg-emerald-400 transition-all flex items-center gap-2 shadow-lg shadow-emerald-500/20" | |
| > | |
| <Zap className="h-4 w-4 fill-slate-900" /> | |
| Enter Dashboard | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('chaos')} | |
| className="px-5 py-2.5 rounded-lg bg-slate-800 border border-slate-700 text-slate-200 font-semibold text-sm hover:bg-slate-700 transition-all" | |
| > | |
| Launch Chaos Testing | |
| </button> | |
| </div> | |
| </div> | |
| {/* Core Capabilities */} | |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80"> | |
| <h4 className="text-white font-bold text-sm tracking-wider uppercase mb-4 flex items-center gap-2"> | |
| <CheckCircle className="h-4 w-4 text-emerald-400" /> | |
| Core Platform Capabilities | |
| </h4> | |
| <ul className="space-y-3 text-slate-400 text-sm font-mono"> | |
| <li className="flex gap-3"><span className="text-emerald-400">01.</span> Distributed Token Bucket Lua Rate Limiter</li> | |
| <li className="flex gap-3"><span className="text-emerald-400">02.</span> Dynamic Latency & Error Rate Clamping</li> | |
| <li className="flex gap-3"><span className="text-emerald-400">03.</span> Closed/Open/Half-Open Circuit Breaker States</li> | |
| <li className="flex gap-3"><span className="text-emerald-400">04.</span> Real-time Cascading Backpressure Clamps</li> | |
| <li className="flex gap-3"><span className="text-emerald-400">05.</span> Statistical Anomaly Detection & Flapping Protections</li> | |
| </ul> | |
| </div> | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80"> | |
| <h4 className="text-white font-bold text-sm tracking-wider uppercase mb-4 flex items-center gap-2"> | |
| <Settings className="h-4 w-4 text-emerald-400" /> | |
| Production Environment Stack | |
| </h4> | |
| <div className="grid grid-cols-2 gap-4 text-xs font-mono text-slate-500"> | |
| <div> | |
| <p className="text-slate-300 font-semibold">Backend Service</p> | |
| <p>FastAPI, AsyncIO, Uvicorn</p> | |
| <p className="mt-2 text-slate-300 font-semibold">Distributed Cache</p> | |
| <p>Redis Cluster (Lua Scripts)</p> | |
| </div> | |
| <div> | |
| <p className="text-slate-300 font-semibold">Relational Database</p> | |
| <p>PostgreSQL (SQLAlchemy)</p> | |
| <p className="mt-2 text-slate-300 font-semibold">Telemetry & Scraping</p> | |
| <p>Prometheus & Grafana</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {/* SLO & Compliance */} | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80"> | |
| <h4 className="text-white font-bold text-sm tracking-wider uppercase mb-4 flex items-center gap-2"> | |
| <ShieldAlert className="h-4 w-4 text-emerald-400" /> | |
| Service Level Objectives (SLO) & Security Compliance | |
| </h4> | |
| <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-xs font-mono"> | |
| <div className="bg-slate-950/40 p-4 rounded-lg border border-slate-900/60"> | |
| <p className="text-slate-500">SYSTEM SLO TARGET</p> | |
| <p className="text-emerald-400 font-bold text-sm mt-1">99.99% Availability</p> | |
| <p className="text-[10px] text-slate-600 mt-2">Active threshold monitoring & self-healing active</p> | |
| </div> | |
| <div className="bg-slate-950/40 p-4 rounded-lg border border-slate-900/60"> | |
| <p className="text-slate-500">MUTUAL TLS (mTLS)</p> | |
| <p className="text-emerald-400 font-bold text-sm mt-1">ENFORCED (100%)</p> | |
| <p className="text-[10px] text-slate-600 mt-2">All downstream calls protected by mTLS encryption</p> | |
| </div> | |
| <div className="bg-slate-950/40 p-4 rounded-lg border border-slate-900/60"> | |
| <p className="text-slate-500">AUDIT COMPLIANCE</p> | |
| <p className="text-emerald-400 font-bold text-sm mt-1">SOC2 TYPE II COMPLIANT</p> | |
| <p className="text-[10px] text-slate-600 mt-2">Historical decision records stored in persistent SQL store</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Reliability Dashboard */} | |
| {activeTab === 'dashboard' && ( | |
| <div className="space-y-8"> | |
| {/* Active Pipeline visualization */} | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-slate-400 font-bold text-xs uppercase tracking-wider mb-6 font-mono">Service-to-Service Chain</h3> | |
| {/* SVG Live pipeline with particle animations */} | |
| <div className="relative flex justify-between items-center py-8"> | |
| <svg className="absolute inset-0 w-full h-full pointer-events-none" style={{ minHeight: '120px' }}> | |
| <defs> | |
| <linearGradient id="grad-ab" x1="0%" y1="0%" x2="100%" y2="0%"> | |
| <stop offset="0%" stopColor="#10B981" /> | |
| <stop offset="100%" stopColor={data.services["service-b"]?.status === 'CRITICAL' ? '#EF4444' : '#10B981'} /> | |
| </linearGradient> | |
| <linearGradient id="grad-bc" x1="0%" y1="0%" x2="100%" y2="0%"> | |
| <stop offset="0%" stopColor={data.services["service-b"]?.status === 'CRITICAL' ? '#EF4444' : '#10B981'} /> | |
| <stop offset="100%" stopColor={data.services["service-c"]?.status === 'CRITICAL' ? '#EF4444' : '#10B981'} /> | |
| </linearGradient> | |
| </defs> | |
| {/* Path Client -> A */} | |
| <path id="path-client-a" d="M 50 60 L 220 60" stroke="#1D2433" strokeWidth="3" fill="none" strokeDasharray="5,5" /> | |
| {/* Path A -> B */} | |
| <path id="path-a-b" d="M 320 60 L 520 60" stroke="url(#grad-ab)" strokeWidth="3" fill="none" /> | |
| {/* Path B -> C */} | |
| <path id="path-b-c" d="M 620 60 L 820 60" stroke="url(#grad-bc)" strokeWidth="3" fill="none" /> | |
| {/* Animated Particles flowing. Speed depends on RPS. */} | |
| {data.services["service-a"]?.rps > 0 && ( | |
| <circle r="4" fill="#10B981"> | |
| <animateMotion dur={`${Math.max(0.3, 4 / (data.services["service-a"].rps || 1))}s`} repeatCount="indefinite" path="M 50 60 L 220 60" /> | |
| </circle> | |
| )} | |
| {data.services["service-b"]?.rps > 0 && data.services["service-b"]?.circuit_state !== 'OPEN' && ( | |
| <circle r="4" fill={data.services["service-b"]?.status === 'CRITICAL' ? '#EF4444' : '#10B981'}> | |
| <animateMotion dur={`${Math.max(0.3, 4 / (data.services["service-b"].rps || 1))}s`} repeatCount="indefinite" path="M 320 60 L 520 60" /> | |
| </circle> | |
| )} | |
| {data.services["service-c"]?.rps > 0 && data.services["service-c"]?.circuit_state !== 'OPEN' && ( | |
| <circle r="4" fill={data.services["service-c"]?.status === 'CRITICAL' ? '#EF4444' : '#10B981'}> | |
| <animateMotion dur={`${Math.max(0.3, 4 / (data.services["service-c"].rps || 1))}s`} repeatCount="indefinite" path="M 620 60 L 820 60" /> | |
| </circle> | |
| )} | |
| </svg> | |
| {/* Node: Client */} | |
| <div className="z-10 bg-slate-900 border border-slate-800 rounded-lg p-3 text-center w-28 shadow-lg"> | |
| <p className="text-[10px] text-slate-500 font-mono uppercase font-semibold">Source</p> | |
| <p className="text-sm font-bold text-white">Client / Gen</p> | |
| <div className="mt-2 text-[10px] bg-slate-950 text-slate-400 py-1 rounded font-mono border border-slate-900"> | |
| RPS: {generatorRps} | |
| </div> | |
| </div> | |
| {/* Node: Service A */} | |
| <div className={`z-10 border rounded-lg p-4 text-center w-36 shadow-lg bg-darkCard transition-all ${getStatusBg(data.services["service-a"]?.status)}`}> | |
| <p className="text-[10px] text-slate-500 font-mono uppercase font-semibold">Microservice A</p> | |
| <p className="text-sm font-bold text-white">Ingress Proxy</p> | |
| <div className="mt-2 space-y-1 text-left text-[10px] font-mono text-slate-400"> | |
| <div className="flex justify-between"><span>RPS:</span><span className="text-white">{data.services["service-a"]?.rps.toFixed(1)}</span></div> | |
| <div className="flex justify-between"><span>Limit:</span><span className="text-emerald-400">{data.services["service-a"]?.limit_capacity} RPS</span></div> | |
| <div className="flex justify-between"><span>P95:</span><span className="text-white">{((data.services["service-a"]?.p95 || 0) * 1000).toFixed(0)}ms</span></div> | |
| </div> | |
| </div> | |
| {/* Node: Service B */} | |
| <div className={`z-10 border rounded-lg p-4 text-center w-36 shadow-lg bg-darkCard transition-all ${getStatusBg(data.services["service-b"]?.status)}`}> | |
| <p className="text-[10px] text-slate-500 font-mono uppercase font-semibold">Microservice B</p> | |
| <p className="text-sm font-bold text-white">Auth / Routing</p> | |
| <div className="mt-2 space-y-1 text-left text-[10px] font-mono text-slate-400"> | |
| <div className="flex justify-between"><span>RPS:</span><span className="text-white">{data.services["service-b"]?.rps.toFixed(1)}</span></div> | |
| <div className="flex justify-between"><span>CB state:</span><span className="text-white">{data.services["service-b"]?.circuit_state}</span></div> | |
| <div className="flex justify-between"><span>P95:</span><span className="text-white">{((data.services["service-b"]?.p95 || 0) * 1000).toFixed(0)}ms</span></div> | |
| </div> | |
| </div> | |
| {/* Node: Service C */} | |
| <div className={`z-10 border rounded-lg p-4 text-center w-36 shadow-lg bg-darkCard transition-all ${getStatusBg(data.services["service-c"]?.status)}`}> | |
| <p className="text-[10px] text-slate-500 font-mono uppercase font-semibold">Microservice C</p> | |
| <p className="text-sm font-bold text-white">Database Hop</p> | |
| <div className="mt-2 space-y-1 text-left text-[10px] font-mono text-slate-400"> | |
| <div className="flex justify-between"><span>RPS:</span><span className="text-white">{data.services["service-c"]?.rps.toFixed(1)}</span></div> | |
| <div className="flex justify-between"><span>CB state:</span><span className="text-white">{data.services["service-c"]?.circuit_state}</span></div> | |
| <div className="flex justify-between"><span>P95:</span><span className="text-white">{((data.services["service-c"]?.p95 || 0) * 1000).toFixed(0)}ms</span></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Grid of details for A, B, C */} | |
| <div className="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
| {['service-a', 'service-b', 'service-c'].map((s) => { | |
| const sData = data.services[s]; | |
| if (!sData) return null; | |
| return ( | |
| <div key={s} className="glass-panel p-6 rounded-xl border border-slate-800/80 space-y-4 shadow-md"> | |
| <div className="flex justify-between items-center pb-2 border-b border-slate-900/60"> | |
| <span className="font-bold text-white uppercase text-xs font-mono tracking-wider">{s}</span> | |
| <span className={`text-xs font-bold px-2.5 py-0.5 rounded-full ${getStatusColor(sData.status)} bg-slate-950 border border-slate-900/60`}> | |
| {sData.status} | |
| </span> | |
| </div> | |
| <div className="grid grid-cols-2 gap-4 text-xs font-mono text-slate-400"> | |
| <div> | |
| <p>Current RPS</p> | |
| <p className="text-white text-lg font-bold mt-1">{sData.rps.toFixed(1)}</p> | |
| </div> | |
| <div> | |
| <p>Token Limit</p> | |
| <p className="text-emerald-400 text-lg font-bold mt-1">{sData.limit_capacity} RPS</p> | |
| </div> | |
| <div> | |
| <p>Error Rate</p> | |
| <p className={`text-lg font-bold mt-1 ${sData.error_rate > 0 ? 'text-red-400' : 'text-slate-300'}`}> | |
| {(sData.error_rate * 100).toFixed(1)}% | |
| </p> | |
| </div> | |
| <div> | |
| <p>P95 Latency</p> | |
| <p className="text-white text-lg font-bold mt-1">{(sData.p95 * 1000).toFixed(0)}ms</p> | |
| </div> | |
| </div> | |
| {/* Circuit Breaker Status Indicator */} | |
| <div className="flex items-center justify-between bg-slate-950/40 p-3 rounded-lg border border-slate-900/60"> | |
| <span className="text-[10px] text-slate-500 font-mono uppercase font-semibold">Circuit Breaker:</span> | |
| <span className={`text-[10px] font-bold px-2 py-0.5 rounded-full ${getCircuitColor(sData.circuit_state)}`}> | |
| {sData.circuit_state} | |
| </span> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| {/* Real-time latency chart */} | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h4 className="text-white font-bold text-xs uppercase tracking-wider mb-6 font-mono">Real-Time Latency Trends (P95 ms)</h4> | |
| <div className="h-64"> | |
| {history.length === 0 ? ( | |
| <div className="h-full flex items-center justify-center text-slate-600 font-mono text-sm"> | |
| Collecting telemetry streams... | |
| </div> | |
| ) : ( | |
| <ResponsiveContainer width="100%" height="100%"> | |
| <AreaChart data={history}> | |
| <defs> | |
| <linearGradient id="colA" x1="0" y1="0" x2="0" y2="1"> | |
| <stop offset="5%" stopColor="#10B981" stopOpacity={0.2}/> | |
| <stop offset="95%" stopColor="#10B981" stopOpacity={0}/> | |
| </linearGradient> | |
| <linearGradient id="colB" x1="0" y1="0" x2="0" y2="1"> | |
| <stop offset="5%" stopColor="#3B82F6" stopOpacity={0.2}/> | |
| <stop offset="95%" stopColor="#3B82F6" stopOpacity={0}/> | |
| </linearGradient> | |
| <linearGradient id="colC" x1="0" y1="0" x2="0" y2="1"> | |
| <stop offset="5%" stopColor="#F59E0B" stopOpacity={0.2}/> | |
| <stop offset="95%" stopColor="#F59E0B" stopOpacity={0}/> | |
| </linearGradient> | |
| </defs> | |
| <CartesianGrid stroke="#1D2433" strokeDasharray="3 3" /> | |
| <XAxis dataKey="time" stroke="#21262D" tick={{ fontSize: 10, fontFamily: 'JetBrains Mono' }} /> | |
| <YAxis stroke="#21262D" tick={{ fontSize: 10, fontFamily: 'JetBrains Mono' }} unit="ms" /> | |
| <Tooltip contentStyle={{ backgroundColor: '#0E121B', borderColor: '#1D2433', color: '#FFF', fontFamily: 'JetBrains Mono' }} /> | |
| <Legend wrapperStyle={{ fontSize: 11, fontFamily: 'Inter' }} /> | |
| <Area type="monotone" dataKey="Service A Latency" stroke="#10B981" fillOpacity={1} fill="url(#colA)" /> | |
| <Area type="monotone" dataKey="Service B Latency" stroke="#3B82F6" fillOpacity={1} fill="url(#colB)" /> | |
| <Area type="monotone" dataKey="Service C Latency" stroke="#F59E0B" fillOpacity={1} fill="url(#colC)" /> | |
| </AreaChart> | |
| </ResponsiveContainer> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Network Topology Map */} | |
| {activeTab === 'topology' && ( | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-slate-400 font-bold text-xs uppercase tracking-wider mb-6 font-mono">Interactive Service Map</h3> | |
| <div className="h-[400px] bg-slate-950/40 border border-slate-900/60 rounded-lg flex items-center justify-center relative overflow-hidden"> | |
| <div className="absolute top-6 left-6 text-xs text-slate-500 font-mono space-y-1"> | |
| <p>● Green: Healthy operation</p> | |
| <p>● Yellow: Latency threshold breached / degraded limit applied</p> | |
| <p>● Red: Critical failures / circuit open</p> | |
| </div> | |
| <div className="flex gap-16 items-center"> | |
| {/* Service A */} | |
| <div className="flex flex-col items-center"> | |
| <div className={`h-24 w-24 rounded-full border-2 flex flex-col items-center justify-center transition-all bg-darkCard ${data.services["service-a"]?.status === 'HEALTHY' ? 'border-emerald-500 shadow-lg shadow-emerald-500/20' : data.services["service-a"]?.status === 'DEGRADED' ? 'border-amber-500 shadow-lg shadow-amber-500/20' : 'border-red-500 shadow-lg shadow-red-500/20'}`}> | |
| <span className="text-xs font-bold text-white font-mono">Service A</span> | |
| <span className="text-[10px] text-slate-500 mt-1 font-mono">Limits: {data.services["service-a"]?.limit_capacity} RPS</span> | |
| </div> | |
| </div> | |
| <div className="w-16 h-0.5 bg-slate-800" /> | |
| {/* Service B */} | |
| <div className="flex flex-col items-center"> | |
| <div className={`h-24 w-24 rounded-full border-2 flex flex-col items-center justify-center transition-all bg-darkCard ${data.services["service-b"]?.status === 'HEALTHY' ? 'border-emerald-500 shadow-lg shadow-emerald-500/20' : data.services["service-b"]?.status === 'DEGRADED' ? 'border-amber-500 shadow-lg shadow-amber-500/20' : 'border-red-500 shadow-lg shadow-red-500/20'}`}> | |
| <span className="text-xs font-bold text-white font-mono">Service B</span> | |
| <span className="text-[10px] text-slate-500 mt-1 font-mono">{data.services["service-b"]?.circuit_state}</span> | |
| </div> | |
| </div> | |
| <div className="w-16 h-0.5 bg-slate-800" /> | |
| {/* Service C */} | |
| <div className="flex flex-col items-center"> | |
| <div className={`h-24 w-24 rounded-full border-2 flex flex-col items-center justify-center transition-all bg-darkCard ${data.services["service-c"]?.status === 'HEALTHY' ? 'border-emerald-500 shadow-lg shadow-emerald-500/20' : data.services["service-c"]?.status === 'DEGRADED' ? 'border-amber-500 shadow-lg shadow-amber-500/20' : 'border-red-500 shadow-lg shadow-red-500/20'}`}> | |
| <span className="text-xs font-bold text-white font-mono">Service C</span> | |
| <span className="text-[10px] text-slate-500 mt-1 font-mono">{data.services["service-c"]?.circuit_state}</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Chaos Engineering */} | |
| {activeTab === 'chaos' && ( | |
| <div className="space-y-6"> | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-white font-bold text-sm tracking-wider uppercase mb-4 font-mono">Service Traffic Injection Panel</h3> | |
| <div className="flex gap-4 items-center bg-slate-950/40 p-4 rounded-lg border border-slate-900/60 mb-6"> | |
| <span className="text-xs text-slate-400 font-mono">Adjust Client Traffic Rate (RPS):</span> | |
| <div className="flex flex-wrap gap-2"> | |
| {[10, 50, 100, 200, 500, 1000].map(val => ( | |
| <button | |
| key={val} | |
| onClick={() => updateGeneratorRps(val)} | |
| className={`px-3 py-1.5 rounded text-xs font-mono font-bold transition-all ${generatorRps === val ? 'bg-emerald-500 text-slate-950 shadow-md shadow-emerald-500/10' : 'bg-slate-800 text-slate-400 hover:text-white'}`} | |
| > | |
| {val} RPS | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| {['service-b', 'service-c'].map(service => { | |
| const status = chaosState[service] || {}; | |
| return ( | |
| <div key={service} className="bg-slate-900/40 border border-slate-800/60 rounded-xl p-6 space-y-4"> | |
| <div className="flex justify-between items-center pb-2 border-b border-slate-800/60"> | |
| <span className="text-white font-bold text-xs uppercase font-mono tracking-wider">{service} Injection</span> | |
| <button | |
| onClick={() => clearChaos(service)} | |
| className="text-[10px] font-bold text-slate-900 bg-rose-400 hover:bg-rose-300 px-3 py-1 rounded uppercase tracking-wider font-mono" | |
| > | |
| Reset Service | |
| </button> | |
| </div> | |
| <div className="flex flex-wrap gap-2 py-1 text-[10px] font-mono"> | |
| {status.crash && <span className="bg-red-500/10 text-red-400 border border-red-500/20 px-2 py-0.5 rounded">CRASHED</span>} | |
| {status.delay > 0 && <span className="bg-amber-500/10 text-amber-400 border border-amber-500/20 px-2 py-0.5 rounded">DELAY: {status.delay}s</span>} | |
| {status.error_rate > 0 && <span className="bg-orange-500/10 text-orange-400 border border-orange-500/20 px-2 py-0.5 rounded">ERRORS: {status.error_rate * 100}%</span>} | |
| {status.cpu_load > 0 && <span className="bg-blue-500/10 text-blue-400 border border-blue-500/20 px-2 py-0.5 rounded">CPU: {status.cpu_load * 100}%</span>} | |
| </div> | |
| <div className="space-y-4 pt-2"> | |
| <div className="flex justify-between items-center"> | |
| <span className="text-xs text-slate-400 font-mono">Crash Service:</span> | |
| <button | |
| onClick={() => triggerChaos(service, 'crash', !status.crash)} | |
| className={`px-4 py-1.5 rounded text-xs font-mono font-bold transition-all ${status.crash ? 'bg-red-500 text-white' : 'bg-slate-800 text-slate-400 hover:text-white'}`} | |
| > | |
| {status.crash ? "Crashed (Recover)" : "Inject Crash"} | |
| </button> | |
| </div> | |
| <div className="space-y-1"> | |
| <div className="flex justify-between text-xs font-mono text-slate-400"> | |
| <span>Inject Delay (Latency):</span> | |
| <span className="text-white">{status.delay || 0}s</span> | |
| </div> | |
| <input | |
| type="range" min="0" max="3" step="0.1" | |
| value={status.delay || 0} | |
| onChange={(e) => triggerChaos(service, 'delay', parseFloat(e.target.value))} | |
| className="w-full h-1 bg-slate-800 rounded-lg appearance-none cursor-pointer accent-emerald-500" | |
| /> | |
| </div> | |
| <div className="space-y-1"> | |
| <div className="flex justify-between text-xs font-mono text-slate-400"> | |
| <span>Inject Errors (HTTP 500 rate):</span> | |
| <span className="text-white">{((status.error_rate || 0) * 100).toFixed(0)}%</span> | |
| </div> | |
| <input | |
| type="range" min="0" max="1" step="0.1" | |
| value={status.error_rate || 0} | |
| onChange={(e) => triggerChaos(service, 'error_rate', parseFloat(e.target.value))} | |
| className="w-full h-1 bg-slate-800 rounded-lg appearance-none cursor-pointer accent-emerald-500" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Control Decisions */} | |
| {activeTab === 'control-plane' && ( | |
| <div className="space-y-6 max-w-4xl mx-auto"> | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-white font-bold text-sm tracking-wider uppercase mb-4 font-mono">Controller Decision Engine (Audit Logs)</h3> | |
| <div className="overflow-x-auto"> | |
| <table className="w-full text-left border-collapse text-xs font-mono"> | |
| <thead> | |
| <tr className="border-b border-slate-800/80 text-slate-500 uppercase tracking-wider"> | |
| <th className="pb-3 pl-2">Timestamp</th> | |
| <th className="pb-3">Service</th> | |
| <th className="pb-3">Action</th> | |
| <th className="pb-3">Transition</th> | |
| <th className="pb-3">Reason</th> | |
| </tr> | |
| </thead> | |
| <tbody className="divide-y divide-slate-800/60 text-slate-300"> | |
| {data.audits.length === 0 ? ( | |
| <tr> | |
| <td colSpan="5" className="py-6 text-center text-slate-600">No decisions logs in database yet. Run traffic to trigger limits.</td> | |
| </tr> | |
| ) : ( | |
| data.audits.map(a => ( | |
| <tr key={a.id} className="hover:bg-slate-800/20"> | |
| <td className="py-3 pl-2 text-slate-500">{new Date(a.timestamp).toLocaleTimeString()}</td> | |
| <td className="py-3 font-semibold text-white">{a.service}</td> | |
| <td className="py-3"> | |
| <span className="bg-slate-950/40 text-slate-300 border border-slate-800/80 px-2 py-0.5 rounded"> | |
| {a.action} | |
| </span> | |
| </td> | |
| <td className="py-3 text-emerald-400"> | |
| {a.old_value} → {a.new_value} | |
| </td> | |
| <td className="py-3 text-slate-400 truncate max-w-xs">{a.reason}</td> | |
| </tr> | |
| )) | |
| )} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Reliability Timeline */} | |
| {activeTab === 'timeline' && ( | |
| <div className="max-w-3xl mx-auto space-y-6"> | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-white font-bold text-sm tracking-wider uppercase mb-6 font-mono">Real-Time Event Log</h3> | |
| <div className="relative border-l border-slate-800 ml-3 space-y-6"> | |
| {data.events.length === 0 ? ( | |
| <p className="text-sm font-mono text-slate-600 pl-6">No events captured yet.</p> | |
| ) : ( | |
| data.events.map(e => ( | |
| <div key={e.id} className="relative pl-6"> | |
| <div className={`absolute -left-1.5 top-1.5 h-3 w-3 rounded-full border-2 bg-darkBg ${e.severity === 'CRITICAL' ? 'border-red-500' : e.severity === 'WARNING' ? 'border-amber-500' : 'border-emerald-400'}`} /> | |
| <div className="space-y-1"> | |
| <div className="flex items-center gap-3"> | |
| <span className="text-[10px] font-mono text-slate-500">{new Date(e.timestamp).toLocaleTimeString()}</span> | |
| <span className={`text-[10px] font-mono font-bold uppercase ${e.severity === 'CRITICAL' ? 'text-red-400' : e.severity === 'WARNING' ? 'text-amber-400' : 'text-emerald-400'}`}> | |
| {e.event_type} | |
| </span> | |
| <span className="bg-slate-900 border border-slate-800 text-slate-400 text-[10px] font-mono px-1.5 py-0.5 rounded"> | |
| {e.service} | |
| </span> | |
| </div> | |
| <p className="text-xs text-slate-300 font-mono">{e.message}</p> | |
| </div> | |
| </div> | |
| )) | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* System Architecture Map */} | |
| {activeTab === 'architecture' && ( | |
| <div className="max-w-4xl mx-auto space-y-6"> | |
| <div className="glass-panel p-8 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-white font-bold text-sm tracking-wider uppercase mb-6 font-mono">System Components Interconnect</h3> | |
| <div className="grid grid-cols-3 gap-6 text-center text-xs font-mono"> | |
| {/* Left Column: Client */} | |
| <div className="border border-slate-800/80 rounded-xl p-4 bg-slate-950/20 space-y-4"> | |
| <p className="text-slate-400 font-bold uppercase border-b border-slate-800 pb-2">Client Ingress</p> | |
| <div className="bg-darkCard border border-darkBorder rounded-lg p-3"> | |
| <p className="text-white font-bold">Load Generator</p> | |
| <p className="text-[10px] text-slate-500 mt-1">Generates simulated customer traffic</p> | |
| </div> | |
| </div> | |
| {/* Mid Column: Backend Stack */} | |
| <div className="border border-slate-800/80 rounded-xl p-4 bg-slate-950/20 space-y-4"> | |
| <p className="text-slate-400 font-bold uppercase border-b border-slate-800 pb-2">Service Grid</p> | |
| <div className="bg-darkCard border border-darkBorder rounded-lg p-3"> | |
| <p className="text-white font-bold">FastAPI Container Chain</p> | |
| <p className="text-[10px] text-slate-500 mt-1">Service A → B → C (Runs telemetry & rate check)</p> | |
| </div> | |
| <div className="bg-darkCard border border-darkBorder rounded-lg p-3"> | |
| <p className="text-white font-bold">Redis Cluster</p> | |
| <p className="text-[10px] text-slate-500 mt-1">Executes token bucket Lua & handles buffers</p> | |
| </div> | |
| </div> | |
| {/* Right Column: Reliability Controller */} | |
| <div className="border border-slate-800/80 rounded-xl p-4 bg-slate-950/20 space-y-4"> | |
| <p className="text-slate-400 font-bold uppercase border-b border-slate-800 pb-2">Control Plane</p> | |
| <div className="bg-darkCard border border-darkBorder rounded-lg p-3"> | |
| <p className="text-white font-bold">Reliability Controller</p> | |
| <p className="text-[10px] text-slate-500 mt-1">Loops every 2s, executes self-healing overrides</p> | |
| </div> | |
| <div className="bg-darkCard border border-darkBorder rounded-lg p-3"> | |
| <p className="text-white font-bold">PostgreSQL DB</p> | |
| <p className="text-[10px] text-slate-500 mt-1">Maintains event audit trails & benchmarks</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Resilience Benchmarks */} | |
| {activeTab === 'benchmarks' && ( | |
| <div className="space-y-6 max-w-4xl mx-auto"> | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <h3 className="text-white font-bold text-sm tracking-wider uppercase mb-4 font-mono">Platform Resilience Benchmarks</h3> | |
| <p className="text-slate-400 text-xs mb-6 max-w-2xl leading-relaxed"> | |
| Trigger automated runs simulating failure injection on Service C under heavy traffic. | |
| Compare statistics between unprotected setups (flapping, cascading timeouts) and protected configurations (automated limits, fail-fast, backpressure). | |
| </p> | |
| <div className="flex gap-4 mb-8"> | |
| <button | |
| disabled={benchmarkLoading} | |
| onClick={() => runResilienceBenchmark(true)} | |
| className="px-5 py-2.5 rounded-lg bg-emerald-500 text-slate-900 font-bold text-xs hover:bg-emerald-400 transition-all flex items-center gap-2" | |
| > | |
| <Zap className="h-4 w-4 fill-slate-900" /> | |
| {benchmarkLoading ? "Running..." : "Run Test (WITH PROTECTION)"} | |
| </button> | |
| <button | |
| disabled={benchmarkLoading} | |
| onClick={() => runResilienceBenchmark(false)} | |
| className="px-5 py-2.5 rounded-lg bg-rose-500 text-white font-bold text-xs hover:bg-rose-400 transition-all flex items-center gap-2" | |
| > | |
| <Flame className="h-4 w-4" /> | |
| {benchmarkLoading ? "Running..." : "Run Test (NO PROTECTION)"} | |
| </button> | |
| </div> | |
| {/* Benchmark results database table */} | |
| <div className="space-y-6"> | |
| <h4 className="text-white font-bold text-xs uppercase tracking-wider font-mono">Historical Runs</h4> | |
| {benchmarks.length === 0 ? ( | |
| <div className="text-slate-600 font-mono text-xs py-4 text-center border border-slate-800/60 rounded-lg"> | |
| No benchmark data. Trigger a run to generate reports. | |
| </div> | |
| ) : ( | |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div className="bg-slate-950/40 p-4 border border-slate-800/60 rounded-lg h-64"> | |
| <p className="text-slate-400 font-bold text-[10px] uppercase font-mono mb-4">Availability / Success Rate (%)</p> | |
| <ResponsiveContainer width="100%" height="90%"> | |
| <BarChart data={benchmarks}> | |
| <CartesianGrid stroke="#1D2433" strokeDasharray="3 3" /> | |
| <XAxis dataKey="test_name" stroke="#21262D" tick={{ fontSize: 9, fontFamily: 'JetBrains Mono' }} /> | |
| <YAxis stroke="#21262D" tick={{ fontSize: 10, fontFamily: 'JetBrains Mono' }} /> | |
| <Tooltip contentStyle={{ backgroundColor: '#0E121B', borderColor: '#1D2433', color: '#FFF' }} /> | |
| <Bar dataKey="success_rate" fill="#10B981" /> | |
| </BarChart> | |
| </ResponsiveContainer> | |
| </div> | |
| <div className="space-y-3 overflow-y-auto max-h-64 pr-2"> | |
| {benchmarks.map(b => ( | |
| <div key={b.id} className="bg-slate-900/60 border border-slate-800/60 rounded-lg p-4 font-mono text-[10px] space-y-1"> | |
| <div className="flex justify-between font-bold text-white"> | |
| <span>{b.test_name}</span> | |
| <span className={b.has_protection ? "text-emerald-400" : "text-rose-400"}> | |
| {b.has_protection ? "PROTECTED" : "UNPROTECTED"} | |
| </span> | |
| </div> | |
| <p className="text-slate-500">{new Date(b.timestamp).toLocaleString()}</p> | |
| <div className="grid grid-cols-3 gap-2 pt-2 text-slate-400"> | |
| <div>Success: <span className="text-white font-bold">{(b.success_rate * 100).toFixed(1)}%</span></div> | |
| <div>P95 Latency: <span className="text-white font-bold">{(b.p95_latency * 1000).toFixed(0)}ms</span></div> | |
| <div>Requests: <span className="text-white font-bold">{b.total_requests}</span></div> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {/* Observability Hub */} | |
| {activeTab === 'observability' && ( | |
| <div className="max-w-6xl mx-auto space-y-8"> | |
| {/* Prometheus embedded Frame */} | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <div className="flex justify-between items-center mb-4"> | |
| <h3 className="text-white font-bold text-xs uppercase tracking-wider font-mono">Prometheus Query Panel</h3> | |
| <a | |
| href="/prometheus/" target="_blank" rel="noreferrer" | |
| className="text-[10px] bg-slate-800 border border-slate-700 text-slate-300 px-3 py-1.5 rounded hover:text-white font-mono" | |
| > | |
| Open Fullscreen | |
| </a> | |
| </div> | |
| <iframe | |
| src="/prometheus/" | |
| title="Prometheus Console" | |
| className="w-full h-[350px] border border-slate-800/80 rounded-lg bg-slate-950" | |
| /> | |
| </div> | |
| {/* Grafana embedded Frame */} | |
| <div className="glass-panel p-6 rounded-xl border border-slate-800/80 shadow-md"> | |
| <div className="flex justify-between items-center mb-4"> | |
| <h3 className="text-white font-bold text-xs uppercase tracking-wider font-mono">Grafana Cockpit Dashboard</h3> | |
| <a | |
| href="/grafana/" target="_blank" rel="noreferrer" | |
| className="text-[10px] bg-slate-800 border border-slate-700 text-slate-300 px-3 py-1.5 rounded hover:text-white font-mono" | |
| > | |
| Open Fullscreen (Credentials: admin/admin) | |
| </a> | |
| </div> | |
| <iframe | |
| src="/grafana/" | |
| title="Grafana Dashboard" | |
| className="w-full h-[550px] border border-slate-800/80 rounded-lg bg-slate-950" | |
| /> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </main> | |
| </div> | |
| ); | |
| } | |