Astro es la capa documental y visual de AI-LAB, separada del runtime crítico. Sirve documentación técnica, blog, paneles de estado público, portal privado de operaciones y visualización de telemetría agregada. No ejecuta lógica de inferencia ni modifica el runtime.

  • App: /opt/ai-lab/apps/ialab-docs
  • Framework: Astro 6.3.1 con Starlight, React 19, Tailwind CSS 4
  • Build: npm run builddist/
  • Serving: astro preview mediante systemd (ailab-docs.service) en puerto 4322
  • URL pública: https://ai-lab.labrazahome.com
  • URL privada: https://blog-ai-lab.labrazahome.com (protegida con Cloudflare Access)
  • Documentación técnica del laboratorio (content collections)
  • Blog privado/público (15 entradas)
  • Paneles de estado ligeros (status hub, health score)
  • Portal privado de operaciones
  • Visualización de telemetría agregada
  • Runbooks e incidentes documentados
  • Mapa de nodos, GPUs, modelos y servicios
src/pages/ → Rutas del sitio (cada .astro es una ruta)
src/components/ → Componentes reutilizables (.astro y .tsx/.jsx)
src/layouts/ → Layout principal
src/content/ → Content collections (blog, docs, runbooks, incidents)
blog/ → 15 entradas de blog en markdown
docs/ → Documentación técnica (arquitectura, runtime, ADRs, fases)
runbooks/ → Runbooks operacionales
incidents/ → Incidentes documentados
src/styles/ → CSS global
public/ → Archivos estáticos (imágenes, _redirects, JSON de estado)
dist/ → Build de salida
RutaTipoDescripción
/páginaHome / landing
/architecture/páginaArquitectura operacional (datos de API)
/architecture/security/páginaSeguridad
/ai-infrastructure/páginaInfraestructura AI (10 capas)
/research/páginaResearch index
/hardware-lab/páginaHardware lab
/observability/páginaObservabilidad
/experiments/páginaExperiments
/projects/páginaProyectos técnicos
/skills/páginaSkills
/blog/página + slugBlog técnico (collection)
/docs/página + slugDocumentación técnica (collection con Starlight sidebar)
/runbooks/página + slugRunbooks (collection)
/status/páginaStatus hub con KPIs y health score
/status/live/páginaEstado vivo (redirect a métricas)
/status/history/páginaHistórico de telemetría (KPIs + health score + Recharts)
/status/topology/páginaTopología del cluster (ASCII + TopologyGraph)
/status/gpus/páginaEstado GPUs
/status/models/páginaModelos
/infra/páginaInfrastructure inventory (datos de API)
/portal/páginaPortal privado de operaciones
/ops/páginaOperations Center (redirect a metricas.labrazahome.com/ops)
/ops/commands/páginaComandos operacionales
/ops/learning/páginaLearning
/ops/memory/páginaMemory
/services/páginaServicios
/knowledge/páginaKnowledge hub
/incidents/páginaIncidentes
/models/páginaModel registry
/api/*.jsonAPI RouteEndpoints JSON internos de Astro

Definidas en src/content.config.ts:

  • blog: src/content/blog/*.md — title, date, summary, tags
  • docs: src/content/docs/**/*.md — title, summary, order
  • runbooks: src/content/runbooks/*.md — title, summary, severity

La seguridad no depende de Astro, sino de Cloudflare Access / routing / proxy delante de la app.

  • / — landing
  • /status/, /status/history/, /status/topology/, /status/gpus/, /status/models/ — estado público con métricas agregadas (sin datos sensibles)
  • /blog/ y entradas (según configuración de Cloudflare)
  • /docs/ (según configuración)
  • /architecture/, /ai-infrastructure/, /research/, /hardware-lab/, /observability/, /experiments/, /projects/, /skills/
  • /api/*.json — datos agregados no sensibles
  • /portal/* — portal de operaciones
  • /ops/* — operations center, commands, learning, memory
  • /services/ — servicios internos
  • /knowledge/ — knowledge hub
  • /incidents/ — incidentes
  • /models/ — model registry
  • /runbooks/ — runbooks
Cloudflare Pages (ai-lab.labrazahome.com) → público
Cloudflare Access + Tunnel (blog-ai-lab.labrazahome.com) → privado
→ Traefik reverse proxy
→ Astro dev/preview en :4322

Astro consume datos del runtime a través de API routes internas que redirigen al Live API backend:

Astro frontend (navegador)
→ /api/status.json (proxy Astro → Cloudflare/Tunnel → Traefik)
→ AI-LAB Live API (:8084)
→ runtime/state/cluster_state.json
→ Prometheus / Gateway metrics
Endpoint AstroBackendComponentes que lo usan
/api/status.jsonLive API :8084HomeLiveStats, LiveStatus, Status Hub, History
/api/eventsLive API :8084EventStream (planificado)
/api/topologyLive API :8084TopologyGraph
/api/history.jsonLive API :8084HistoryCharts.jsx
/api/analytics.jsonLive API :8084Status Hub + History
/api/infra.jsonLive API :8084Infra inventario
/api/architecture.jsonLive API :8084Architecture page
/api/models.jsonLive API :8084Models page
/api/services.jsonLive API :8084Services page
/api/knowledge.jsonLive API :8084Knowledge hub
/api/incidents.jsonLive API :8084Incidents page
Navegador → fetch(/api/status.json)
→ Astro static build (no SSR) → archivo estático en dist/ o redirect
→ Cloudflare Pages _redirects
→ Cloudflare Tunnel
→ Traefik
→ Live API :8084
→ runtime/state/cluster_state.json

Nota: En modo astro preview local (systemd), las rutas /api/* se sirven desde public/api/ si existen archivos JSON estáticos, o mediante la app separada de métricas (Next.js SSR en metricas.labrazahome.com).

ComponenteArchivoDescripciónEstado
SidebarLinksrc/components/SidebarLink.astroEnlace de navegación con icono y detección de ruta activaActivo
HomeLiveStatssrc/components/HomeLiveStats.astroKPIs de home (GPUs, LLM nodes, Docker, VRAM) con refresh cada 5sActivo
LiveStatussrc/components/LiveStatus.astroBarra de estado live con GPUs, LLM, containersActivo
LiveStatusCardsrc/components/LiveStatusCard.astroCard individual de estadoActivo
StatusCardsrc/components/StatusCard.astroCard para status hubActivo
TopologyGraphsrc/components/TopologyGraph.astroTopología ASCII del cluster con refresh cada 5sActivo (ASCII, pendiente Cytoscape)
GpuBarsrc/components/GpuBar.astroBarra de GPUActivo
OpsServiceCardsrc/components/OpsServiceCard.astroCard de servicio para opsActivo
TerminalWidgetsrc/components/TerminalWidget.astroWidget terminalActivo
ClusterHealthsrc/components/ClusterHealth.astroSalud del clusterActivo
EventStreamsrc/components/EventStream.astroStream de eventos SSE (planificado)Pendiente
ComponenteArchivoDescripciónEstado
HistoryChartssrc/components/HistoryCharts.jsxGráficas históricas con Recharts (usage, VRAM)Activo
LibreríaPropósitoEstado
RechartsGráficas de histórico (HistoryCharts.jsx)Instalado y activo
Cytoscape.jsReemplazo planificado para topología gráfica interactivaInstalado en package.json pero no implementado
MermaidDiagramas en documentaciónInstalado y activo (astro-mermaid)
LucideIconos en sidebar y componentesInstalado y activo
uPlotGráficos ligeros para GPU liveNo instalado (pendiente de fase anterior)
Terminal window
cd /opt/ai-lab/apps/ialab-docs
npm run build
# → genera dist/ con 254 páginas estáticas
# → incluye sitemap, search index (Pagefind via Starlight)
# → _redirects copiado a dist/
  • Producción: astro preview en puerto :4322 mediante systemd (ailab-docs.service)
  • Desarrollo: astro dev con hot reload
  • Cloudflare Pages: build automático en push a GitHub, despliegue en ai-lab.labrazahome.com
  • Separación público/privado: Cloudflare Access + Tunnel para tráfico privado

El archivo public/_redirects controla el enrutamiento en Cloudflare Pages. Actualmente sin reglas definidas (vacío). Las redirecciones se gestionan desde Cloudflare Dashboard.

Servir dist/ con nginx para eliminar Node.js del serving path y maximizar rendimiento.

  • No se exponen datos sensibles en rutas públicas
  • /ops/* y /portal/* protegidos con Cloudflare Access
  • /status/* público solo con métricas agregadas (sin IPs internas, sin tokens)
  • Las API routes internas solo sirven datos agregados no sensibles
  • La autenticación no depende de Astro sino de Cloudflare Access (Zero Trust)
ÁreaEstadoComentario
Astro appActivo/opt/ai-lab/apps/ialab-docs, Astro 6.3.1
BuildOK254 páginas, ~12s
Status pageActivoKPIs, health score, refresh 15s
TopologyActivo (ASCII)Pendiente migración a Cytoscape
History pageActivoRecharts + KPIs + health gauge
Ops dashboardRedirigidoops/ redirige a metricas.labrazahome.com/ops
PortalActivoHub de enlaces a herramientas
Cloudflare redirectsVacíopublic/_redirects sin reglas
RechartsActivoHistoryCharts.jsx funcional
CytoscapeInstaladoEn package.json, no implementado
uPlotNo instaladoPendiente de fase anterior
MermaidActivoDiagramas en content collections
Starlight searchActivoPagefind index integrado
Navegación (sidebar)Activo15 enlaces + logo + runtime footer
  1. Astro static (SSG) en vez de SSR: No necesita servidor Node para servir contenido. La build genera HTML estático. El contenido dinámico (KPIs, health) se carga via fetch client-side desde /api/*.
  2. Cloudflare Access para seguridad: La autenticación no se implementa en Astro sino en el edge (Cloudflare Access + Tunnel). Astro no maneja sesiones ni tokens.
  3. Live API separada: Los datos operativos no se sirven desde Astro SSR. Se sirven desde una app separada (Next.js en metricas.labrazahome.com) o desde la Live API (:8084).
  4. Starlight para documentación: La sidebar de docs y el search vienen de Starlight, no implementados manualmente.
  5. React islands: Solo donde se necesita interactividad (HistoryCharts con Recharts). El resto es Astro puro.
  6. Archivos JSON estáticos en public/: Algunos endpoints /api/*.json se servían desde archivos estáticos. Ahora se sirven dinámicamente desde la app de métricas.
  • Consolidar /dashboard unificado con estado vivo y health en una sola vista
  • Migrar TopologyGraph de ASCII a Cytoscape.js (librería ya instalada)
  • Implementar GpuLiveChart con uPlot para gráficos GPU en tiempo real
  • Definir reglas en public/_redirects para enrutamiento Cloudflare Pages explícito
  • Mejorar search/RAG interno sobre content collections
  • Separar claramente blog público y portal privado en la navegación
  • Servir dist/ con nginx como futuro hardening (eliminar Node.js del serving)
flowchart TD
  User["Usuario / Operador"] --> CF["Cloudflare Pages / Access"]
  CF --> Astro["Astro Docs / Portal :4322"]
  Astro --> API["/api/* redirects"]
  API --> Tunnel["Cloudflare Tunnel / Traefik"]
  Tunnel --> LiveAPI["AI-LAB Live API :8084"]
  LiveAPI --> State["runtime/state/*.json"]
  LiveAPI --> Prom["Prometheus / Gateway Metrics"]
  Astro --> PublicStatus["/status público"]
  Astro --> PrivateOps["/ops redirige a metricas.labrazahome.com"]
  Astro --> Blog["/blog técnico"]
  Astro --> Docs["/docs documentación"]