Crea tu propia status page con IA con un prompt
Una página de estado es un semáforo con historial. Verde si todo va bien, rojo si algo se ha caído, y una lista de incidentes debajo.
Un fin de semana, como mucho. ¿Qué puede tener de complicado?
Pues tiene un comprobador que no puede confundir su propia caída con la del servicio, un porcentaje de disponibilidad que casi nadie calcula bien, una máquina de estados con historia que no se reescribe, un envío de avisos que no puede duplicar correos ni ahogar a nadie, y una página que tiene que seguir en pie justo cuando todo lo demás está en el suelo.
Esa última frase es el proyecto entero. Todo lo demás son detalles.
Por eso una status page propia es un ejercicio buenísimo: parece una tabla con un <span> de color y termina siendo una lección de sistemas distribuidos en miniatura.
Este post no repite el método. La receta general —cómo eliges qué reconstruir, el prompt cero, los criterios de aceptación, los prompts de rescate— la tienes en cómo crear tu propio X con IA. Y si vienes de los hermanos mayores de este proyecto, crear tu propio Calendly con IA o crear tu propio YNAB con IA, reconocerás la estructura. Aquí vamos a lo concreto de una página de estado:
- Un prompt único para arrancar ahora mismo, si no quieres leer más
- Qué entra y qué no entra en una status page que se termina
- Las seis piezas donde se juega el partido, con el prompt de cada una
- El agujero de correctitud que tu agente no va a detectar solo
- Los mantenimientos programados, el trozo que todo el mundo olvida
- Dónde mirar cuando te atasques, con OpenStatus como referencia viva
- Cómo generar el checklist que te dice si esto está de verdad terminado
Vamos al lío.
El prompt único, si quieres empezar ahora mismo ¶
Hay gente que ha llegado hasta aquí con el portátil abierto y el agente esperando. Para ti va esto.
Copia el prompt, pégalo y dale al enter.
Vas a construir "Semáforo", una página de estado pequeña a propósito,
al estilo de Instatus: comprueba unos cuantos servicios, muestra su
estado en público y deja publicar incidentes. Quiero una aplicación
que funcione de verdad, no una maqueta.
Usa el stack que veas en el repositorio; si está vacío, propón uno
habitual y pregúntame antes de instalar nada exótico.
ANTES DE ESCRIBIR CÓDIGO
Devuélveme un plan corto con rutas, endpoints, tablas y decisiones.
Espera a que yo lo apruebe.
MODELO DE DATOS
Component (nombre, grupo, orden), Check (componente, timestamp, si
respondió, latencia, código de estado), StatusEvent (componente,
estado, desde, hasta), Incident (título, impacto, estado, inicio, fin)
e IncidentUpdate (incidente, mensaje, estado, timestamp). Nada más.
LAS TRES COSAS QUE NO PUEDES HACER MAL
1. El estado de un componente NO es un booleano. Es un enum:
operativo, degradado, caída parcial, caída total, en mantenimiento.
El estado global de la página se deriva del peor componente, con el
mantenimiento tratado aparte: una ventana de mantenimiento nunca
pinta la página en rojo.
2. Un solo check fallido NO declara una caída. Hacen falta dos fallos
consecutivos para bajar y dos éxitos para subir. Guarda todos los
checks en crudo y deriva el estado a partir de ellos, nunca al revés.
3. La disponibilidad se calcula ponderando por TIEMPO, no contando
checks. Un 99,9% mensual son 43 minutos de caída, y ese número tiene
que salir de los intervalos de estado, no de una división entre
checks buenos y checks totales.
PANTALLAS
Página pública (estado global arriba, componentes agrupados con su
estado, barras de disponibilidad de los últimos 90 días e historial de
incidentes), panel de administración para cambiar estados y publicar
actualizaciones de incidente, y una vista de los checks de un
componente. Cada pantalla declara su acción principal, su estado de
carga, su estado vacío y su error recuperable.
FUERA DE ALCANCE
Páginas privadas con login, SSO, SMS, escalados y guardias, checks
desde varias regiones, métricas de rendimiento históricas y varios
equipos. Si crees que hace falta algo de esto, pregúntame.
TESTS
Unitarios del cálculo de estado y disponibilidad con estos casos: dos
fallos seguidos que declaran caída, un fallo aislado que no la declara,
disponibilidad de un mes con una caída de 45 minutos, una ventana de
mantenimiento que no descuenta disponibilidad, y la derivación del
estado global cuando un componente está degradado y otro caído.
ENTREGA
Migraciones, datos de ejemplo, .env.example comentado y un README que
me permita levantar esto desde cero dentro de seis meses.
Cuando termines, dime qué has dejado a medias y qué decisiones tomaste
sin preguntarme.
Con eso tienes una primera versión que se abre en el navegador y pinta semáforos de verdad.
Ahora la parte honesta: eso es una primera versión, no un producto.
No avisa a nadie, no distingue un mantenimiento de una caída, no aguanta si se cae tu base de datos y trata los huecos de datos como si fueran disponibilidad perfecta. El prompt cubre tres de las seis piezas difíciles. Las otras tres son las que más tiempo te van a comer.
Así que vuelve por aquí cuando lo tengas en marcha. El resto del post es justo eso.
El nivel de vibe coding al que apunta este post ¶
Conviene situarlo antes de empezar, porque hay tres formas de construir esto y solo una encaja aquí.
La primera es el vibe coding básico: pides “hazme una status page”, aceptas lo que salga y lo despliegas. Vale para una demo. No vale para colgarla en status.tudominio.com y que la mire un cliente. Si estás en ese punto, empieza por cómo programar con IA tu primer proyecto.
La tercera es la metodología completa: especificación, artefactos versionados, criterios de aceptación formales. Es lo que conviene en un proyecto que va a durar, y lo tienes en la guía de Spec Driven Development. Para un fin de semana es matar moscas a cañonazos.
Este post vive en la segunda: vibe coding con criterio. Sigues conversando con el agente, sigues sin escribir specs formales, pero sabes de antemano dónde se va a equivocar el modelo y llegas a ese punto con el prompt preparado. Si quieres el marco de cuánta garantía pedir según lo que te juegas, lo desarrollo en cómo hacer bien vibe coding.
🔑 Una status page es el único producto que se juzga por cómo se comporta el peor día del año. Todo lo que construyas aquí se mide contra ese día, no contra los otros trescientos sesenta y cuatro.
Sobre la herramienta da bastante igual: cualquier agente de terminal con acceso a ficheros te sirve. Si todavía no has elegido, tienes la comparativa de agentes de IA en terminal. Los prompts que vienen funcionan igual en todos.
El tercer nivel, cuando la página deja de ser un experimento
El ciclo completo de Spec Driven Development con OpenSpec en modo asistido sobre un proyecto pequeño: proposal, spec, diseño, tareas y archivar. Lo ves entero antes de coger tú el volante.
Abrir el curso gratis →Qué entra y qué no entra en tu status page ¶
El alcance es la decisión más importante del proyecto y se toma antes del primer prompt.
Una status page propia que se termina cubre esto:
- Componentes agrupados, cada uno con su estado y su historial.
- Un comprobador que hace peticiones periódicas y guarda el resultado.
- Disponibilidad por ventanas de tiempo, con barras diarias de los últimos noventa días.
- Incidentes con actualizaciones encadenadas y componentes afectados.
- Suscriptores por correo, con avisos cuando cambia algo relevante.
- Mantenimientos programados, que se avisan antes y no descuentan disponibilidad.
Y deja fuera esto, a propósito:
- Checks desde varias regiones del mundo
- Páginas privadas con autenticación y SSO
- Avisos por SMS, llamada o guardias con escalado
- Métricas de rendimiento históricas al estilo de un panel de observabilidad
- Varios equipos y varias páginas sobre la misma instalación
Esa lista de exclusiones no es pereza: es la parte que convierte un fin de semana en un trimestre. Escríbela en tu fichero de contexto y el agente dejará de proponerte cosas que no vas a construir.
Las seis piezas donde se juega el partido ¶
Aquí está el mapa. Cada pieza tiene su trampa concreta, y ninguna se resuelve sola por muy bien que escribas el prompt inicial.
| Pieza | Por qué es difícil | Cómo sabes que está bien |
|---|---|---|
| El estado de un componente | No es un booleano, y el global se deriva de los demás | Un mantenimiento no pinta la página de rojo |
| El comprobador | Tu fallo de red parece una caída del servicio | Un fallo aislado no dispara un incidente |
| La disponibilidad | Contar checks no es medir tiempo | 99,9% mensual da 43 minutos, no otra cosa |
| Los incidentes | Son historia, y la historia no se reescribe | Una actualización publicada no se edita, se añade |
| Los avisos | Duplicar correos o ahogar al suscriptor | Reintentar el envío no manda dos veces lo mismo |
| La página en sí | Comparte infraestructura con lo que vigila | Tiras la base de datos y la página sigue viva |
Las tres primeras son de lógica pura. Las tres siguientes son de sistemas, y son las que de verdad separan un juguete de una herramienta.
Saber de antemano dónde está la trampa de cada pieza se aprende viendo proyectos ajenos. Cada domingo seleccionamos 12 recursos sobre programar con IA y los +6.700 que la leemos aportamos lo que vamos rompiendo por el camino.
Quiero esa dinamita 🧨Pieza 1: el estado no es un booleano ¶
Antes de entrar en materia, mira cómo se ve una página de estado real. Esta es la página pública de Uptime Kuma, uno de los proyectos de código abierto más usados del ramo:

Fíjate en tres cosas: los componentes agrupados, la fila de barras diarias debajo de cada uno y el bloque de estado global arriba del todo. Esos tres elementos son las piezas 1, 3 y 1 otra vez. Todo lo demás de la pantalla es decoración.
Y aquí empieza casi todo el desorden posterior. Preguntas “¿está el servicio arriba?” y suena a true o false, así que el modelo te devuelve un boolean y sigue adelante.
El problema es que un servicio que responde en nueve segundos está arriba, y también está roto.
Un estado útil tiene al menos cinco valores: operativo, degradado, caída parcial, caída total y en mantenimiento. Y el estado global de la página no es un campo que alguien actualiza a mano: se deriva del peor de sus componentes, con una excepción importante.
// Orden de gravedad: el estado global es el peor de los componentes
const SEVERITY = [
"operational",
"degraded",
"partial_outage",
"major_outage",
] as const;
type ComponentStatus = (typeof SEVERITY)[number] | "maintenance";
function pageStatus(components: ComponentStatus[]): ComponentStatus {
// El mantenimiento se comunica aparte: no ensucia la gravedad global
const relevant = components.filter((s) => s !== "maintenance");
if (relevant.length === 0) return "maintenance";
return relevant.reduce((worst, current) =>
SEVERITY.indexOf(current) > SEVERITY.indexOf(worst) ? current : worst
);
}
Esa excepción del mantenimiento es la que se salta todo el mundo. Si tratas la ventana de mantenimiento como una gravedad más, tu página aparece en rojo un martes a las tres de la mañana porque estabas migrando la base de datos, y el correo de aviso sale con el mismo tono de alarma que una caída real.
Los usuarios aprenden rápido a ignorar una página que grita sin motivo.
Refactoriza el estado de los componentes:
- Sustituye cualquier booleano de "arriba/abajo" por un enum con cinco
valores: operativo, degradado, caída parcial, caída total,
mantenimiento.
- El estado global de la página se calcula, nunca se guarda. Es el peor
de los componentes, con el mantenimiento excluido del cálculo de
gravedad y comunicado en un aviso aparte.
- Los grupos de componentes muestran el peor estado de sus hijos, con
la misma regla.
Está terminado cuando un componente en mantenimiento y el resto en
operativo dan una página que no está en rojo, y hay un test que lo
comprueba.
Pieza 2: el comprobador miente más de lo que crees ¶
Tu comprobador hace una petición cada minuto y guarda si respondió. Fácil.
Hasta el día que tu servidor pierde la conexión durante cuatro minutos y tu página anuncia al mundo que el servicio estaba caído. No lo estaba. El que estaba caído eras tú.
Este es el problema clásico del observador: cuando el sensor falla, el sistema no distingue “no hay señal” de “señal negativa”. Y en una status page esa confusión te cuesta credibilidad, que es lo único que vende el producto.
Hay tres reglas que el agente no aplicará si no se las das:
- Histéresis: hacen falta dos o tres fallos consecutivos para declarar una caída, y el mismo número de éxitos para volver. Esto elimina el parpadeo, el flapping que llena de ruido el historial.
- Separar el error de red del error del servicio: un timeout, un DNS que no resuelve y un 503 son tres cosas distintas y conviene guardarlas distinguidas.
- Guardar el check en crudo y derivar el estado: nunca sobrescribas el estado con el último resultado. El estado es una conclusión que se saca de una serie de observaciones.
interface Check {
ok: boolean;
latencyMs: number;
at: Date;
}
// Dos fallos seguidos bajan el estado; dos éxitos seguidos lo suben.
// Con uno solo no se toca nada: así se evita el parpadeo.
function nextStatus(
current: ComponentStatus,
recent: Check[], // los más recientes primero
threshold = 2
): ComponentStatus {
const window = recent.slice(0, threshold);
if (window.length < threshold) return current;
if (window.every((c) => !c.ok)) return "major_outage";
if (window.every((c) => c.ok)) return "operational";
return current;
}
⚠️ Guarda cada comprobación como un hecho crudo e inmutable, y calcula el estado a partir de la serie. En cuanto guardes el estado como campo mutable pierdes la capacidad de recalcular el pasado, y en la pieza del agujero vas a necesitarla.
Sobre la latencia: si quieres el estado “degradado” —y merece la pena— defínelo contra un umbral explícito, no contra una media móvil que el agente se invente. Algo como “por encima de dos segundos en tres checks seguidos” es defendible y comprobable. Una media deslizante con parámetros mágicos no lo es.
Pieza 3: la disponibilidad no se cuenta, se mide ¶
Aquí está el error de cálculo más extendido de todo el proyecto, y también el más silencioso.
Preguntas por la disponibilidad de un componente y el código te divide los checks buenos entre los checks totales. Parece razonable. Está mal.
Si compruebas cada treinta segundos por el día y cada cinco minutos por la noche, cada check nocturno pesa diez veces más que uno diurno. Si el comprobador se atasca y deja de hacer peticiones durante la caída, resulta que tienes menos checks fallidos y la disponibilidad sube justo cuando el servicio está peor.
La disponibilidad se pondera por tiempo. Construyes intervalos de estado a partir de la serie de checks y sumas la duración de los intervalos caídos sobre el total de la ventana.
interface StatusInterval {
status: ComponentStatus;
from: Date;
to: Date;
}
// Disponibilidad ponderada por tiempo, no por número de checks.
// El mantenimiento se excluye del denominador: no cuenta como caída
// ni como tiempo en pie.
function uptimeRatio(intervals: StatusInterval[]): number {
let counted = 0;
let down = 0;
for (const i of intervals) {
if (i.status === "maintenance") continue;
const ms = i.to.getTime() - i.from.getTime();
counted += ms;
if (i.status === "major_outage" || i.status === "partial_outage") {
down += ms;
}
}
return counted === 0 ? 1 : (counted - down) / counted;
}
Conviene tener los números en la cabeza, porque son los que le vas a enseñar a alguien que paga. Sobre un mes de treinta días, un 99,9% permite unos 43 minutos de caída. Un 99,95% baja a unos 21 minutos. Un 99,99%, a poco más de cuatro. La diferencia entre esos tres números es la diferencia entre tres arquitecturas distintas, y toda ella cabe en dos decimales.
Queda un detalle de presentación con más miga de la que parece: las barras diarias. Esa fila de noventa rectángulos que todo el mundo copia necesita cubos por día, y un día empieza y acaba según una zona horaria. Si la eliges por defecto en el servidor, tus barras se moverán el día que cambies de proveedor. Elige una zona horaria de la página, guárdala, y calcula los cubos contra ella siempre.
Revisa el cálculo de disponibilidad:
- Debe ponderarse por tiempo a partir de intervalos de estado, no
contando checks buenos entre checks totales.
- Las ventanas disponibles son 24 horas, 7 días, 30 días y 90 días.
- Los intervalos de mantenimiento se excluyen del numerador y del
denominador.
- Las barras diarias agrupan por día en la zona horaria configurada de
la página, guardada en base de datos, no en la del servidor.
Escribe tests con estos casos: un mes con una caída de 45 minutos, un
mes con dos caídas cortas, un mes con una ventana de mantenimiento de
dos horas, y un componente creado a mitad de la ventana.
Ese último caso —un componente que no existía al principio de la ventana— es el que suele devolver un 0% precioso en la barra de noventa días. No tenías datos, no tenías caída.
Pieza 4: un incidente es historia, y la historia no se reescribe ¶
Un incidente parece un registro con un campo estado que vas cambiando. Investigando, identificado, en seguimiento, resuelto.
Lo es, pero con una condición que cambia el diseño entero: cada cambio de estado va acompañado de un mensaje público, y ese mensaje ya no se toca.
La razón es la única que importa aquí. Alguien leyó tu actualización de las 10:42 y tomó una decisión con ella. Si a las 12:00 la editas para que quede mejor, ese alguien ya no puede reconstruir lo que sabía. Una status page cuya historia se puede maquillar no sirve para lo que sirve una status page.
Así que el incidente tiene una cabecera mutable —título, componentes afectados, estado actual— y una lista de actualizaciones que solo crece.
- El estado actual del incidente es el de su última actualización, no un campo aparte que puede desincronizarse.
- Cada actualización lleva su marca de tiempo real de publicación.
- El incidente tiene un
inicioque puedes fechar hacia atrás: te enteras a las 11:00 de algo que empezó a las 10:15, y la disponibilidad tiene que reflejar las 10:15. - Resolver un incidente cierra la ventana, pero no impide añadir después un análisis retrospectivo.
Implementa los incidentes como cabecera mutable más historial
inmutable:
- Estados: investigando, identificado, en seguimiento, resuelto.
- Cada cambio de estado exige un mensaje público y crea una
IncidentUpdate. Las actualizaciones publicadas no se editan ni se
borran desde la interfaz.
- El estado actual del incidente se deriva de su última actualización.
- El incidente guarda inicio y fin propios, que puedo fechar hacia
atrás y que son los que usa el cálculo de disponibilidad.
- Un incidente afecta a uno o varios componentes, cada uno con su
propio impacto.
Propóneme antes cómo vas a evitar que la cabecera y el historial se
desincronicen, con sus contras.
Ese “propóneme antes” es un patrón que uso mucho: pedir alternativas antes que soluciones. La elección de diseño es tu trabajo, no el suyo.
Antes de escribir la primera línea
Cómo se estresa un plan antes de que el agente lo implemente
Te llevas los patrones para que el agente devuelva planes que sí puedes ejecutar: subagentes antagónicos que atacan tu diseño, el plan-reviewer y el cierre con checklist y prueba de concepto.
Destripar el método →Audio premium · Web Reactiva Premium
Pieza 5: avisar sin duplicar y sin ahogar ¶
Los suscriptores parecen el trozo aburrido y son el que se rompe en producción.
Cuando publicas una actualización, sale un envío en abanico a toda la lista. Si el proveedor de correo devuelve un error a mitad y reintentas el lote entero, la mitad de tus suscriptores recibe el mismo correo dos veces. Si un componente parpadea seis veces en diez minutos, reciben seis correos.
Las dos cosas destruyen la confianza en la misma dirección: la gente se da de baja.
La solución tiene tres patas y ninguna es complicada, pero hay que pedirlas:
- Idempotencia en el envío. Una marca por combinación de actualización, suscriptor y canal. Antes de mandar, se comprueba; después de mandar, se escribe. Reintentar no duplica.
- Confirmación antes de avisar. El aviso de cambio de estado no sale del check, sale del estado ya confirmado por la histéresis de la pieza 2. Así el parpadeo no llega al buzón de nadie.
- Suscripción por componente. Quien solo usa tu API no quiere saber que se ha caído el panel de facturación.
Y una cuarta que no es técnica: doble confirmación al suscribirse y un enlace de baja firmado en cada correo. Sin eso tienes un sistema para enviar correo no solicitado a cualquier dirección que alguien teclee en tu formulario.
💡 “Reintentar el envío tres veces deja los mismos correos enviados que hacerlo una vez.” Esa frase es la definición práctica de idempotencia y vale para cualquier trabajo en segundo plano que escribas en tu vida: importaciones, recordatorios, webhooks. Guárdatela.
Implementa las notificaciones a suscriptores con estas garantías:
- Alta con doble confirmación por correo y baja con enlace firmado en
cada envío.
- Suscripción global o por componentes concretos.
- Los avisos se disparan desde un cambio de estado ya confirmado y
desde la publicación de una actualización de incidente, nunca desde
un check individual.
- Envío idempotente: una marca única por actualización, suscriptor y
canal, comprobada antes de enviar. Reintentar el trabajo no manda
nada dos veces.
- Los envíos van en una cola con reintentos y respaldo exponencial, no
en el ciclo de la petición web.
Está terminado cuando ejecutar el trabajo de envío tres veces seguidas
deja el mismo número de correos que ejecutarlo una vez.
Pieza 6: la página tiene que sobrevivir a lo que vigila ¶
Y llegamos al clímax, que es donde se cae la mayoría de las réplicas caseras.
Has construido una aplicación bonita. Panel de administración, base de datos, API. La página pública consulta esa base de datos para pintar los componentes. Todo desplegado en el mismo sitio que tu producto, porque para qué complicarse.
Entonces se cae la base de datos.
Y tu status page, que existe precisamente para contarle al mundo que se ha caído la base de datos, devuelve un error 500.
Una status page que comparte destino con lo que vigila no es una status page. Es un adorno que funciona los días que no hace falta.
Las cuatro separaciones que necesitas son estas:
- Alojamiento distinto del producto que vigilas. Otro proveedor, idealmente.
- DNS y dominio distintos, o al menos otra zona. Si tu DNS cae,
status.tudominio.comcae con él. - Lectura sin base de datos. La página pública sirve un JSON precalculado desde un almacenamiento estático o una caché, actualizado cada pocos segundos. Si la escritura muere, la lectura sigue.
- Salida de correo independiente. El aviso de la caída no puede salir por la infraestructura caída.
// La página pública lee un snapshot precalculado, nunca la base de datos.
// Si el generador muere, se sirve el último snapshot con su marca de tiempo.
interface StatusSnapshot {
generatedAt: string; // ISO 8601, se muestra siempre al visitante
pageStatus: ComponentStatus;
components: { id: string; name: string; status: ComponentStatus }[];
activeIncidents: { id: string; title: string; status: string }[];
}
Fíjate en el campo generatedAt. Enséñalo siempre en la página, con un texto tipo “actualizado hace 40 segundos”. Si el generador se atasca, el visitante ve que el dato está viejo en lugar de creerse un verde de hace tres horas.
Ese es el detalle que convierte una degradación silenciosa en una degradación honesta, y es la diferencia entre las dos cosas que puede hacer tu página el peor día del año.
Separa la página pública del resto del sistema:
- Un proceso genera cada 30 segundos un snapshot JSON con el estado
global, los componentes y los incidentes activos.
- La página pública se sirve desde ese snapshot en almacenamiento
estático o caché, y no abre ninguna conexión a la base de datos
durante la petición.
- Si el snapshot no se ha regenerado, se sirve el último disponible con
su marca de tiempo visible.
- El envío de correo usa credenciales y proveedor propios,
independientes del producto vigilado.
- Documenta en el README qué se cae y qué sobrevive en tres escenarios:
base de datos caída, API caída, proveedor de correo caído.
No implementes despliegue todavía. Primero quiero el diseño y esa
tabla de escenarios.
Separar lo que sobrevive de lo que se cae con todo lo demás es una decisión de arquitectura que se aprende de los sustos de otros. En la newsletter de los domingos compartimos esos sustos y lo que sacamos de ellos. Gratis, desde 2018.
Quiero esa dinamita 🧨El agujero que no verás hasta dentro de tres meses ¶
Aquí va la parte que no aparece en ningún tutorial de este tipo y que a mí me parece la más interesante de toda la aplicación.
Tu sistema tiene tres estados posibles, no dos. Arriba, abajo y sin datos.
El día que tu comprobador se detenga seis horas —porque lo desplegaste mal, porque se quedó sin memoria, porque el cron se paró— vas a tener un hueco en la serie. Y ese hueco se puede interpretar de dos maneras, las dos falsas:
- Si rellenas el hueco como tiempo en pie, publicas un 100% de disponibilidad de un periodo del que no sabes nada. Estás mintiendo hacia arriba.
- Si lo rellenas como caída, castigas al servicio por un fallo tuyo. Estás mintiendo hacia abajo.
La respuesta correcta es la incómoda: guardar el hueco como hueco. Un tercer estado, excluido del cálculo como el mantenimiento, y visible en las barras diarias con su propio color y su propia leyenda.
Cuesta más de programar y es menos bonito de mirar. También es la única versión honesta.
Hay un segundo filo en el mismo agujero. La disponibilidad de tu página no es un dato guardado, es un dato derivado, y lo derivado se puede volver mentira cuando cambias el pasado. Fechas un incidente hacia atrás. Añades una ventana de mantenimiento que no habías declarado. Reclasificas una caída total como parcial. Cada una de esas ediciones cambia números que ya publicaste.
Revisa cómo se comporta el sistema con huecos y con ediciones del
pasado:
1. Si el comprobador deja de funcionar seis horas, ¿qué hay en la
serie? ¿Se distingue "sin datos" de "en pie" y de "caído"?
2. ¿El cálculo de disponibilidad excluye los huecos del numerador y del
denominador, como hace con el mantenimiento?
3. Si fecho un incidente hacia atrás o añado una ventana de
mantenimiento retroactiva, ¿se recalculan la disponibilidad y las
barras diarias afectadas?
4. ¿Hay algún porcentaje guardado en base de datos que pueda quedar
desincronizado con los eventos reales?
Propón cómo garantizar que cualquier número mostrado es coherente con
la serie completa de eventos. No implementes nada todavía, solo el
diagnóstico.
Y ese prompt merece una sesión nueva, con el contexto limpio. Un agente que acaba de escribir el cálculo de disponibilidad lleva encima todas las razones por las que le pareció buena idea guardar ese porcentaje. No es un revisor: es el autor defendiendo su obra.
El trozo que todo el mundo olvida: los mantenimientos programados ¶
Tienes la página en marcha. Lleva dos semanas vigilando tus servicios. Y un sábado por la mañana actualizas la base de datos, la página se pone roja durante veinte minutos y tus suscriptores reciben un aviso de caída total.
Los mantenimientos programados son la parte menos vistosa del producto y una de las que más valor aportan en el día a día. Además son la primera vez en el proyecto que necesitas trabajo en segundo plano de verdad, así que conviene tratarlos con cariño.
Añade mantenimientos programados.
Requisitos:
- Una ventana define componentes afectados, inicio, fin y un mensaje
público.
- Un trabajo periódico pone los componentes en mantenimiento al llegar
el inicio y los devuelve a su estado real al llegar el fin.
- Los suscriptores reciben un aviso al programarla, otro al empezar y
otro al terminar, con tono informativo y no de alarma.
- Los intervalos de mantenimiento quedan excluidos del cálculo de
disponibilidad.
- Marca de aplicación por ventana y transición, para que ejecutar el
trabajo dos veces no cambie dos veces el estado ni mande dos avisos.
Está terminado cuando ejecutar el trabajo tres veces seguidas deja el
mismo estado y los mismos avisos que ejecutarlo una vez.
Cuando esto funcione, el paso natural son los canales extra: un webhook firmado, un feed RSS del historial de incidentes y una insignia embebible con el estado actual. Son tres piezas pequeñas que multiplican el uso de la página, porque dejan de obligar a nadie a visitarla.
Dónde mirar cuando te atasques: OpenStatus como referencia viva ¶
Cuando quieras ver cómo resuelve todo esto gente que lleva años haciéndolo, tienes una referencia excelente y con las puertas abiertas: OpenStatus, la plataforma de código abierto que combina página de estado y monitorización en una sola herramienta.

Los datos, consultados en su repositorio en agosto de 2026: licencia AGPL-3.0, unas 8.800 estrellas y 682 forks, con el código repartido en un 81% de TypeScript y un 2,8% de Go. Su servicio gestionado comprueba desde 28 regiones en paralelo y sus localizaciones privadas caben en una imagen Docker de 8,5 MB.
Lo que a ti te importa es su arquitectura, porque es la lección de la pieza 6 hecha código. Según su propio README, el proyecto separa el panel en Next.js, el servidor de API en Hono, el comprobador en Go y el renderizador de la página de estado como servicio desplegable aparte. Ese corte no es estético: es lo que permite que la página pública siga en pie cuando el resto tiembla.
🛡️ Mirar el código de un proyecto maduro cuando te atascas no es hacer trampa. Es lo contrario de copiar el prompt gigante: tú ya has intentado resolver la pieza, tienes el problema en la cabeza y por eso entiendes por qué ellos lo resolvieron así.
Un aviso sobre la licencia, porque cambia según lo que quieras hacer. AGPL-3.0 es copyleft de red: si modificas OpenStatus y ofreces el resultado como servicio a terceros, tienes que publicar tus cambios. Para uso interno o para leer y aprender no hay problema. Para montar encima un producto propio, léela antes con calma.
Si la AGPL te frena, la otra referencia obligada es Uptime Kuma, el proyecto cuya página pública has visto más arriba. Licencia MIT, unas 86.700 estrellas y 7.800 forks según su repositorio en agosto de 2026, escrito en Vue 3 y Node, con varias páginas de estado y comprobaciones cada veinte segundos. Es menos ambicioso en arquitectura que OpenStatus —todo vive en un proceso con SQLite— y por eso mismo se lee en una tarde. Tienen además una demo temporal en demo.kuma.pet que se borra a los diez minutos: perfecta para trastear sin instalar nada.
Y si lo que quieres es la comparación con el SaaS que estás replicando: los precios publicados de Instatus en 2026 arrancan en un plan gratuito con una página pública y 200 suscriptores, siguen en 20 dólares al mes en el plan Pro y saltan a 300 en el plan Business, que es donde aparecen las páginas privadas y el SSO. La misma comparativa de Instatus sitúa el plan Business de Statuspage, de Atlassian, en 399 dólares al mes para 5.000 suscriptores. Ese salto de precio es, casi siempre, la razón por la que alguien acaba leyendo un post como este.
Cómo se genera el checklist de “esto está terminado” ¶
Has llegado hasta aquí siguiendo el post. Tienes seis piezas construidas y, repartidos entre ellas, seis criterios de “está terminado cuando…”. El problema es que están sueltos, en seis conversaciones que ya has cerrado.
Toca juntarlos en un solo sitio. Hay una forma buena de hacerlo y una mala.
La mala es pedirle al agente “dime si el proyecto está terminado”. Te va a decir que sí. Siempre dice que sí.
Los tres tipos de comprobación ¶
Cualquier checklist útil de este proyecto tiene tres cajones, y confundirlos es lo que hace que la gente acabe con listas de treinta puntos que nadie repasa.
Lo que se comprueba solo. Los tests: la histéresis del comprobador, la derivación del estado global, la disponibilidad de un mes con una caída conocida, la exclusión del mantenimiento, la idempotencia del envío. Se ejecutan con un comando y devuelven verde o rojo.
Lo que se comprueba a mano en diez minutos. Apagar el servicio vigilado y ver cuánto tarda la página en reaccionar. Tirar la base de datos y comprobar que la página pública sigue respondiendo con su marca de tiempo. Programar un mantenimiento de cinco minutos y ver los tres avisos.
Lo que solo se contesta con criterio. ¿Cuántos fallos seguidos declaran una caída? ¿Qué umbral define “degradado”? ¿Los huecos de datos se pintan aparte? Aquí el agente no puede ayudarte: son decisiones de producto y las tomaste tú.
El prompt que lo genera ¶
Con ese reparto claro, el prompt tiene sentido. Fíjate en que no le pido una lista: le pido un fichero verificable.
Recorre el repositorio y genera un fichero VERIFY.md con el checklist
de verificación de este proyecto antes de darlo por terminado.
Reglas para construirlo:
- Cada punto describe CÓMO se comprueba, no solo qué se comprueba.
"La disponibilidad funciona" no vale. "Ejecutar el test X y ver que
pasa" sí vale.
- Agrupa los puntos en tres secciones: automático (un comando), manual
(menos de diez minutos) y decisión de producto (una pregunta que solo
puedo responder yo).
- Los puntos automáticos citan el fichero y el nombre del test que ya
existe. Si un criterio no tiene test que lo respalde, NO te lo
inventes: márcalo como hueco y ponlo en una lista aparte al final.
- Los puntos manuales incluyen el dato de prueba concreto: qué servicio
apagar, cuánto esperar, qué esperar ver en pantalla.
- Las decisiones de producto van formuladas como pregunta cerrada, con
el valor implementado ahora mismo entre paréntesis.
Al final, una sección de huecos: criterios que aparecen en el código o
en los comentarios pero que nadie está comprobando.
No arregles nada. Solo el fichero.
Las dos líneas que hacen todo el trabajo son la del “cómo se comprueba” y la de “si no hay test, márcalo como hueco”. Sin la primera te devuelve una lista de deseos. Sin la segunda se inventa tests que no existen y los da por pasados.
La regla que impide que el checklist mienta ¶
Un checklist se corrompe siempre por el mismo sitio: alguien marca una casilla sin comprobarla.
Con un agente de por medio pasa a los dos minutos. Le pides que repase el fichero y te devuelve todo marcado, porque marcar es lo más parecido a completar la tarea que le has pedido.
La regla es sencilla: cada punto se cierra con una evidencia pegada al lado. La salida del comando, la captura del estado, la fecha en que lo probaste. Sin evidencia, la casilla sigue vacía aunque el agente jure que funciona.
Repasa VERIFY.md y ejecuta solo los puntos de la sección automática.
Para cada uno, pega debajo la salida real del comando: la de verdad, no
un resumen tuyo.
Los puntos manuales y las decisiones de producto los dejas sin tocar:
esos los cierro yo.
Si un punto falla, no lo arregles. Anótalo y sigue con el siguiente.
Ese “no lo arregles, anótalo y sigue” evita el problema clásico: el agente se atasca con el primer fallo, se le va el contexto y nunca llegas a saber si los otros diez puntos pasaban.
Las tres señales de que puedes cerrar el portátil ¶
Con el fichero cerrado, quedan tres preguntas que ningún checklist responde.
La primera: la usas de verdad. Tu página vigila algo tuyo que está en producción y la miras cuando algo va raro, antes que los logs.
La segunda: has ensayado el peor día. Has tirado a propósito lo que vigilas, has visto la página reaccionar, has recibido el correo y has publicado un incidente de prueba de principio a fin.
La tercera, y es la que más cuesta: la siguiente funcionalidad que se te ocurre está en la lista de exclusiones. Cuando te sorprendas pensando “sería fácil añadir checks desde tres regiones”, ese es el momento de cerrar el portátil.
Guarda el VERIFY.md en el repositorio y repásalo antes de cada despliegue. Es lo único de todo el proyecto que te va a seguir sirviendo dentro de seis meses, cuando vuelvas a tocarlo y no recuerdes por dónde empezaba.
Y si un día tu página aguanta el peor momento del año y le cuenta la verdad a alguien mientras todo lo demás arde, habrás construido algo bastante mejor que un semáforo.
Preguntas frecuentes ¶
¿Qué es una status page y para qué sirve?
Es una página pública que muestra el estado actual de los servicios de un producto, su historial de incidentes y su disponibilidad. Sirve para que los usuarios sepan qué está pasando sin abrir un ticket, y para dejar constancia comprobable de cómo se comunicó cada caída.
¿Cuánto se tarda en montar una status page propia con IA?
Una versión mínima con componentes, comprobador, incidentes y página pública cabe en unas seis horas de trabajo real. Añadir suscriptores con envío idempotente, mantenimientos programados y la separación de infraestructura se va a un par de días.
¿Cuál es la parte más difícil de construir una status page?
Que la página siga en pie cuando se cae lo que vigila. Si comparte base de datos, alojamiento o DNS con el producto monitorizado, devuelve un error justo el día que hace falta. La solución es servir un snapshot precalculado desde infraestructura separada.
¿Cómo se calcula bien el porcentaje de disponibilidad?
Ponderando por tiempo, no contando checks. Se construyen intervalos de estado a partir de la serie de comprobaciones y se suma la duración de los intervalos caídos sobre el total de la ventana, excluyendo mantenimientos y huecos de datos.
¿Cuántos minutos de caída permite un 99,9% de disponibilidad?
Sobre un mes de treinta días, unos 43 minutos. Un 99,95% baja a unos 21 minutos y un 99,99% a poco más de cuatro. Esa diferencia de dos decimales suele implicar arquitecturas por completo distintas.
¿Cómo se evita que la página parpadee con fallos aislados?
Con histéresis: se exigen dos o tres comprobaciones fallidas seguidas para declarar una caída y el mismo número de éxitos para volver a operativo. Además, los avisos a suscriptores se disparan desde el estado ya confirmado, nunca desde un check individual.
¿Qué estados debe tener un componente?
Al menos cinco: operativo, degradado, caída parcial, caída total y en mantenimiento. Un booleano de arriba o abajo no distingue un servicio lento de uno inaccesible, y esa distinción es justo la que aporta valor durante un incidente.
¿Cómo se gestionan los mantenimientos programados?
Con ventanas que definen componentes, inicio, fin y mensaje público, aplicadas por un trabajo periódico idempotente. Esos intervalos se excluyen del cálculo de disponibilidad y sus avisos usan un tono informativo, no de alarma.
¿Se pueden editar las actualizaciones de un incidente ya publicadas?
No conviene. La cabecera del incidente puede cambiar, pero las actualizaciones publicadas son historia: alguien tomó una decisión leyéndolas. Si hace falta corregir algo, se publica una actualización nueva que lo aclare.
¿Merece la pena si ya existe OpenStatus?
Depende del objetivo. Si necesitas una herramienta para producción, instala OpenStatus o paga un SaaS. Si lo que quieres es aprender, reconstruir un producto cuyo comportamiento ya conoces te convierte en el mejor tester posible de tu propio código.
Fuentes ¶
- OpenStatus, repositorio oficial en GitHub. Licencia AGPL-3.0, stack, arquitectura de servicios, estrellas y forks.
- OpenStatus, sitio y documentación. Regiones de comprobación, monitorización como código y opciones de autoalojamiento.
- Uptime Kuma, repositorio oficial en GitHub. Licencia MIT, stack, funciones, capturas y demo pública.
- Instatus, página de precios. Planes, límites de suscriptores y funciones por nivel.
- Instatus, “8 Best Statuspage Alternatives”. Comparativa de precios con Statuspage de Atlassian.
🧨 Última oprtunidad para recibir la dinamita que mereces sobre programación con IA el próximo domingo: Suscríbete gratis a Web Reactiva en https://webreactiva.com/newsletter
12 recursos para developers cada domingo en tu bandeja de entrada
Además de una skill práctica bien explicada, trucos para mejorar tu futuro profesional y una pizquita de humor útil para el resto de la semana. Gratis.