Files
nova/docs/index.html

327 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stellar Air — NOVA Platform Architecture</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #0a0e17;
color: #e8eaf0;
font-family: 'Inter', sans-serif;
line-height: 1.6;
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
}
header {
padding: 16px 24px;
border-bottom: 1px solid #1e2a4a;
display: flex;
align-items: baseline;
gap: 16px;
flex-shrink: 0;
}
header h1 {
font-family: 'JetBrains Mono', monospace;
font-size: 22px;
font-weight: 600;
letter-spacing: 3px;
color: #0066ff;
}
header .subtitle {
font-size: 13px;
color: #4a5568;
letter-spacing: 1px;
text-transform: uppercase;
}
.layout {
display: flex;
flex: 1;
min-height: 0;
}
nav {
display: flex;
flex-direction: column;
gap: 0;
width: 200px;
flex-shrink: 0;
background: #121829;
border-right: 1px solid #1e2a4a;
padding: 8px 0;
overflow-y: auto;
}
nav a {
padding: 10px 20px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: #8892a8;
text-decoration: none;
border-left: 2px solid transparent;
transition: all 0.15s;
cursor: pointer;
}
nav a:hover { color: #e8eaf0; background: #1a2340; }
nav a.active { color: #0066ff; border-left-color: #0066ff; background: #0d1a33; }
main {
flex: 1;
overflow: auto;
padding: 32px 48px;
}
.graph-section {
display: none;
animation: fadeIn 0.2s ease;
}
.graph-section.active { display: block; }
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.graph-section h2 {
font-family: 'JetBrains Mono', monospace;
font-size: 15px;
font-weight: 500;
color: #8892a8;
margin-bottom: 8px;
letter-spacing: 1px;
}
.graph-section p {
font-size: 13px;
color: #4a5568;
margin-bottom: 24px;
max-width: 800px;
}
.graph-container {
background: #0a0e17;
border: 1px solid #1e2a4a;
padding: 24px;
overflow: auto;
}
.graph-container img {
max-width: 100%;
height: auto;
}
.legend {
display: flex;
gap: 24px;
margin-top: 16px;
font-size: 11px;
font-family: 'JetBrains Mono', monospace;
color: #4a5568;
}
.legend span::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
margin-right: 6px;
border-radius: 50%;
}
.legend .live::before { background: #00c853; }
.legend .mock::before { background: #ffc107; }
.legend .mcp::before { background: #0066ff; }
.legend .ops::before { background: #ff3d00; }
.graph-container a { display: block; }
.graph-container img { max-width: 100%; height: auto; }
/* Repo tree */
.tree-container {
background: #0a0e17;
border: 1px solid #1e2a4a;
padding: 24px;
overflow: auto;
}
.repo-tree {
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1.7;
color: #8892a8;
}
.t-root { color: #0066ff; font-weight: 600; font-size: 15px; }
.t-dir { color: #e8eaf0; font-weight: 500; }
.t-mcp { color: #0066ff; font-weight: 500; }
.t-ops { color: #ff3d00; font-weight: 500; }
.t-pax { color: #00c853; font-weight: 500; }
.t-live { color: #00c853; }
.t-comment { color: #4a5568; }
</style>
</head>
<body>
<header>
<h1>STELLAR AIR</h1>
<span class="subtitle">NOVA Operations Platform — Architecture</span>
</header>
<div class="layout">
<nav>
<a class="active" onclick="show('system')">System</a>
<a onclick="show('mcp')">MCP Servers</a>
<a onclick="show('efhas')">FCE Agent</a>
<a onclick="show('handover')">Handover Agent</a>
<a onclick="show('data')">Data Flow</a>
<a onclick="show('deploy')">Deployment</a>
<a onclick="show('repo')">Repository</a>
</nav>
<main>
<section id="system" class="graph-section active">
<h2>SYSTEM ARCHITECTURE</h2>
<p>End-to-end view: Vue UI → Kong gateway (optional) → FastAPI → MCP servers → live and scenario data sources. Langfuse (separate shared cluster) traces every agent run and tool call.</p>
<div class="graph-container">
<a href="viewer.html?src=graphs/system_architecture.svg"><img src="graphs/system_architecture.svg" alt="System Architecture"></a>
</div>
<div class="legend">
<span class="live">Live API</span>
<span class="mock">Scenario data</span>
<span class="mcp">MCP protocol</span>
</div>
</section>
<section id="mcp" class="graph-section">
<h2>MCP SERVER TOPOLOGY</h2>
<p>Three servers scoped by access domain. Each exposes tools, resources, and prompts. FCE connects to shared + passenger. Handover connects to shared + ops.</p>
<div class="graph-container">
<a href="viewer.html?src=graphs/mcp_servers.svg"><img src="graphs/mcp_servers.svg" alt="MCP Servers"></a>
</div>
<div class="legend">
<span class="mcp">Shared server</span>
<span class="ops">Ops server</span>
<span class="live">Passenger server</span>
</div>
<div class="legend" style="margin-top: 8px;">
<span style="color:#8892a8">── solid = tool calls</span>
<span style="color:#8892a8">╌╌ dashed = resource reads</span>
<span style="color:#8892a8">··· dotted = prompt gets</span>
</div>
</section>
<section id="efhas" class="graph-section">
<h2>FCE AGENT — BEHIND EVERY DEPARTURE</h2>
<p>Passenger notification agent. Triages flight status, gathers context from 5 parallel tool calls (including live weather and FAA data), synthesizes an empathetic notification.</p>
<div class="graph-container">
<a href="viewer.html?src=graphs/efhas_agent.svg"><img src="graphs/efhas_agent.svg" alt="FCE Agent"></a>
</div>
</section>
<section id="handover" class="graph-section">
<h2>SHIFT HANDOVER AGENT</h2>
<p>Ops briefing agent. Scans all hubs in parallel, scores issues by severity × time sensitivity, categorizes into IMMEDIATE / MONITOR / FYI, generates a structured brief.</p>
<div class="graph-container">
<a href="viewer.html?src=graphs/handover_agent.svg"><img src="graphs/handover_agent.svg" alt="Handover Agent"></a>
</div>
</section>
<section id="data" class="graph-section">
<h2>DATA FLOW — REAL vs MOCK</h2>
<p>Weather and FAA airport status are live (no API key). Flight, crew, passenger, and maintenance data are scenario-based fixtures switchable from the UI.</p>
<div class="graph-container">
<a href="viewer.html?src=graphs/data_flow.svg"><img src="graphs/data_flow.svg" alt="Data Flow"></a>
</div>
<div class="legend">
<span class="live">Live data (no API key)</span>
<span class="mock">Scenario data (switchable)</span>
</div>
</section>
<section id="deploy" class="graph-section">
<h2>DEPLOYMENT</h2>
<p>Kind cluster for dev (Tilt), docker-compose for EC2 production (nova-api + nova-ui on shared gateway network). Woodpecker CI builds images on push to main. EC2 nginx proxies stellarair.mcrn.ar → container; Kong Konnect available as optional governance layer.</p>
<div class="graph-container">
<a href="viewer.html?src=graphs/deployment.svg"><img src="graphs/deployment.svg" alt="Deployment"></a>
</div>
</section>
<section id="repo" class="graph-section">
<h2>REPOSITORY STRUCTURE</h2>
<p>Monorepo: MCP servers, agents, IRROP engine, API, Vue UI (with shared component framework), and deployment configs.</p>
<div class="tree-container">
<pre class="repo-tree"><span class="t-root">stellar-ops/</span>
├── <span class="t-dir">mcp_servers/</span>
│ ├── <span class="t-mcp">shared/</span> <span class="t-comment">server.py · tools.py · resources.py · prompts.py</span>
│ │ └── tools: <span class="t-live">get_route_weather</span> · <span class="t-live">get_hub_forecasts</span> · <span class="t-live">get_airport_status</span>
│ │ get_flight_status · get_flight_details · get_irregular_ops
│ │ get_airport_congestion · get_maintenance_flags
│ ├── <span class="t-ops">ops/</span> <span class="t-comment">server.py · tools.py · resources.py · prompts.py</span>
│ │ └── tools: get_crew_notes · get_crew_duty_status · get_pending_rebookings
│ │ generate_narrative
│ ├── <span class="t-pax">passenger/</span> <span class="t-comment">server.py · tools.py · resources.py · prompts.py</span>
│ │ └── tools: generate_notification
│ ├── shared_llm.py <span class="t-comment">multi-provider: Groq · Anthropic · Bedrock · OpenAI</span>
│ └── <span class="t-dir">data/</span>
│ ├── models.py <span class="t-comment">FlightData · CrewMember · Passenger · MELItem · HubInfo</span>
│ ├── real/ <span class="t-live">openmeteo.py · faa.py</span>
│ └── scenarios/ <span class="t-comment">normal_ops · weather_disruption_ord</span>
<span class="t-comment">maintenance_delay_sfo · crew_swap_ewr</span>
├── <span class="t-dir">agents/</span>
│ ├── fce.py <span class="t-comment">FCE — "Behind Every Departure" (passenger notifications)</span>
│ ├── handover.py <span class="t-comment">Shift Handover (ops brief: IMMEDIATE / MONITOR / FYI)</span>
│ └── shared/
│ ├── mcp_client.py <span class="t-comment">MCPMultiClient + connect_servers context manager</span>
│ ├── parser.py <span class="t-comment">parse_tool_result · parse_resource_result · parse_prompt_result</span>
│ └── tool_runner.py <span class="t-comment">build_tool_caller — timeout · Langfuse span · error collection</span>
├── <span class="t-dir">api/</span>
│ ├── main.py <span class="t-comment">FastAPI: agents, scenarios, WebSocket, /health, Langfuse traces</span>
│ └── config.py <span class="t-comment">Pydantic Settings — centralized env var reads</span>
├── <span class="t-dir">ui/</span>
│ ├── framework/ <span class="t-comment">soleprint-ui (shared component library)</span>
│ └── app/ <span class="t-comment">Vue 3 SPA — Operations · Internals · Data · Settings</span>
│ └── src/config.ts <span class="t-comment">Kong proxy URL + API/WS base</span>
├── <span class="t-dir">ctrl/</span>
│ ├── Dockerfile.api/ui <span class="t-comment">Container builds</span>
│ ├── nginx.conf <span class="t-comment">UI nginx (proxies /agents /scenarios /config /health /ws)</span>
│ ├── k8s/ <span class="t-comment">base/ + overlays/dev/ (Kustomize)</span>
│ ├── Tiltfile <span class="t-comment">Dev environment (Kind cluster: unt)</span>
│ ├── edge/ <span class="t-comment">Production docker-compose (nova-api + nova-ui on gateway net)</span>
│ └── deploy.sh <span class="t-comment">rsync (bypass CI) · edge (pull registry images)</span>
├── <span class="t-dir">tests/</span> <span class="t-comment">69 tests: models · clients · MCP · scenarios · agents</span>
│ └── base.py <span class="t-comment">dual-mode: inprocess (default) · live (CONTRACT_TEST_MODE=live)</span>
├── <span class="t-dir">.woodpecker/</span> <span class="t-comment">CI pipeline — build API + UI, push to registry.mcrn.ar</span>
├── <span class="t-dir">docs/</span> <span class="t-comment">Architecture graphs (this page)</span>
└── .mcp.json <span class="t-comment">Claude Code integration — 3 servers</span></pre>
</div>
</section>
</main>
</div>
<script>
function show(id) {
document.querySelectorAll('.graph-section').forEach(s => s.classList.remove('active'));
document.querySelectorAll('nav a').forEach(a => a.classList.remove('active'));
document.getElementById(id).classList.add('active');
event.currentTarget.classList.add('active');
}
</script>
</body>
</html>