Problema
Section titled “Problema”El AI-LAB tiene dos sitios web:
- Publico (
ai-lab.labrazahome.com) — Cloudflare Pages (estatico) - Privado (
blog-ai-lab.labrazahome.com) — Cloudflare Tunnel + Traefik + Astro preview
El sitio privado esta protegido por Cloudflare Access (Zero Trust), lo que impedía que el sitio publico hiciera fetch de datos de la API desde el dominio privado.
Solucion: Hostname Detection
Section titled “Solucion: Hostname Detection”Se implemento deteccion de hostname en el JavaScript para usar diferentes fuentes de datos segun el dominio:
const isPublic = window.location.hostname === "ai-lab.labrazahome.com" || window.location.hostname.includes("pages.dev");const apiUrl = isPublic ? "/api/analytics.json" : "https://blog-ai-lab.labrazahome.com/api/analytics";const res = await fetch(apiUrl, { cache: "no-store",});Sitio Privado: Service Token + Cloudflare Access
Section titled “Sitio Privado: Service Token + Cloudflare Access”- Las peticiones se hacen al mismo origen del blog privado:
/api/analytics - El browser no envía tokens de acceso manuales
- Cloudflare Access protege el sitio, no el JS del cliente
- Traefik enruta
/api/*alocalhost:8084(Live API) - Datos en tiempo real
Sitio Publico: JSON Estatico
Section titled “Sitio Publico: JSON Estatico”- Se sirven ficheros JSON estaticos desde
public/api/analytics.jsonypublic/api/status.json - Mismo dominio → sin CORS, sin Access, sin preflight
- Los datos son ficticios pero realistas (requests, health score, GPUs, etc.)
- Se actualizan manualmente en cada build de Cloudflare Pages
Paginas Afectadas
Section titled “Paginas Afectadas”| Pagina | Privado | Publico |
|---|---|---|
/ops/ | API real + Service Token | analytics.json estatico |
/status/history/ | API real + Service Token | analytics.json estatico |
/status/gpus/ | API real via Traefik | status.json estatico |
Separación de documentación Astro (Julio 2026)
Section titled “Separación de documentación Astro (Julio 2026)”AI-LAB Docs también implementa separación público/privado para su documentación técnica en Astro/Starlight.
Arquitectura
Section titled “Arquitectura”Contenido público (ai-lab.labrazahome.com) y privado (blog-ai-lab.labrazahome.com) comparten el mismo codebase en apps/ialab-docs/src/content/docs/. La separación se logra mediante un build filter que elimina paths PRIVATE_ONLY antes del build público.
Mecanismo
Section titled “Mecanismo”- Clasificación: Cada página se etiqueta como
PUBLIC_SAFEoPRIVATE_ONLYsegún su sensibilidad (IPs internas, puertos, runbooks, secretos). - Build filter:
scripts/private-content-filter.jsondefine 33+ paths PRIVATE_ONLY que se eliminan temporalmente antes del build público víascripts/build-public-wrapper.mjs. - Restauración: Tras el build público, los archivos se restauran automáticamente con
git checkout. - Sidebar condicional: La variable
AILAB_PUBLIC_BUILDoculta secciones privadas (Runbooks, Incidents, Historical) en el sidebar de Starlight. - Redirects edge:
public/_redirectsbloquea rutas privadas en Cloudflare Pages.
Cobertura
Section titled “Cobertura”| Métrica | Público | Privado |
|---|---|---|
| Páginas | 171 (filtradas) | 277 (completas) |
| IPs internas | 0 (validado con grep) | Presentes donde aplica |
| Sidebar | Sin Runbooks/Incidents/Historical | Completo |
Scripts
Section titled “Scripts”scripts/build-public-wrapper.mjs— wrapper que filtra y restaura automáticamentescripts/private-content-filter.json— catálogo de 33+ paths PRIVATE_ONLYscripts/build-public-filter.mjs— filter standalone (deprecated)package.json:build:publicybuild:private
Pipeline CI/CD
Section titled “Pipeline CI/CD”scripts/phase-closure/publish-astro-public.ps1— build público + deploy Cloudflarescripts/phase-closure/publish-astro-private.ps1— build privado + deploy local
Archivos Clave
Section titled “Archivos Clave”runtime/analytics/health_score.py— usadiscovered_nodesen vez denodesruntime/analytics/runtime_analytics.py— usadiscovered_nodesen vez denodesruntime/state/live_api.py— handlerdo_OPTIONSpara CORS preflightapps/ialab-docs/src/pages/ops/index.astro— hostname detectionapps/ialab-docs/src/pages/status/history/index.astro— hostname detection + fix variable bugapps/ialab-docs/src/pages/status/gpus/index.astro— hostname detectionapps/ialab-docs/public/api/analytics.json— datos dummy publicosapps/ialab-docs/public/api/status.json— datos dummy publicosapps/ialab-docs/scripts/build-public-wrapper.mjs— build filter wrapperapps/ialab-docs/scripts/private-content-filter.json— 33+ entries PRIVATE_ONLYapps/ialab-docs/astro.config.mjs— sidebar condicional via AILAB_PUBLIC_BUILDapps/ialab-docs/public/_redirects— bloqueo de rutas privadas en edge
Bugs Corregidos
Section titled “Bugs Corregidos”- health_score.py: leia
nodes[]en vez dediscovered_nodes[] - runtime_analytics.py: mismo error, nodos siempre 0
- live_api.py: faltaba handler
do_OPTIONSpara CORS - history page: variable
rundefined (debia serres) - gpus page: fetch a
/api/analyticsen vez de/api/status.json - Backups: ficheros
.bakcon contaminacion de ANSI escape sequences