> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bbrands.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Runbook de operaciones

> Tareas de monitoreo del día 2 con los comandos exactos: sincronizar variables de entorno, agregar o cambiar un monitor, rotar el health token, regenerar los recursos de la página de estado, y resolver drift.

<Info>
  Este runbook cubre las tareas operativas recurrentes de la plataforma de
  monitoreo. Cada tarea empareja el **disparador funcional** ("cuándo necesito esto")
  con los **comandos exactos** a ejecutar. Ninguna tarea aquí imprime ni almacena valores
  de secretos.
</Info>

## Sincronizar variables de entorno

Las variables de entorno viven en **1Password Environments** (una por
entorno) y fluyen a dos destinos: archivos locales `.env.<env>` para el
desarrollo, y Vercel para las apps desplegadas.

<CardGroup cols={2}>
  <Card title="1Password → archivos locales" icon="laptop-code">
    Ejecuta `pnpm env:sync` para reflejar cada 1Password Environment en el archivo
    `.env.<environment>` de cada app. Sin argumentos sincroniza **todas** las apps y **todos**
    los entornos; los entornos a los que tu token no puede acceder se omiten con una
    advertencia en lugar de fallar.
  </Card>

  <Card title="1Password → Vercel" icon="cloud-arrow-up">
    Ejecuta el workflow **Sync Env** (`workflow_dispatch`) para enviar un 1Password
    Environment a Vercel, luego **vuelve a desplegar** `horizon-api` para que los nuevos valores
    surtan efecto.
  </Card>
</CardGroup>

```bash theme={null}
# Everything (all apps, all accessible environments)
pnpm env:sync

# Only the API app
pnpm env:sync api

# A single environment
pnpm env:sync --env certification
```

<Warning>
  Editar una variable en 1Password no es suficiente para los entornos desplegados: después de
  que el workflow Sync Env actualice Vercel, debes **volver a desplegar** `horizon-api` para
  que el runtime lea los nuevos valores.
</Warning>

## Agregar o cambiar un monitor

El monitoreo es código — nunca click-ops en la UI de Better Stack.

<Steps>
  <Step title="Edita la definición">
    Cambia el módulo bajo `infra/betterstack/modules/` o el manifiesto de estado deseado
    `adopted/<env>.json` del entorno.
  </Step>

  <Step title="Abre un PR">
    El carril de **validación** se ejecuta automáticamente (`fmt`, `validate`, verificaciones JSON).
    Consulta [CI/CD para el monitoreo](/es/monitoring/github-actions).
  </Step>

  <Step title="Plan">
    Lanza el workflow con `action = plan` para el entorno objetivo y
    lee el diff. Localmente: `pnpm tf:betterstack:plan`.
  </Step>

  <Step title="Apply">
    Lanza con `action = apply` y escribe `APPLY`, o ejecuta
    `./scripts/status-monitoring/terraform-apply.sh apply <env>` localmente. Confirma
    que un `plan` de seguimiento no muestra cambios.
  </Step>
</Steps>

## Rotar `HEALTH_MONITOR_TOKEN`

El health token autentica a los monitores de Better Stack contra los endpoints de
componentes. Rótalo si pudiera haberse filtrado, o de forma programada. El orden
importa para evitar un hueco de monitoreo.

<Steps>
  <Step title="Genera un nuevo token">
    `openssl rand -hex 32`.
  </Step>

  <Step title="Guárdalo en el vault">
    Actualiza `HEALTH_MONITOR_TOKEN` en el 1Password Environment del entorno.
  </Step>

  <Step title="Propaga al runtime">
    Ejecuta el workflow **Sync Env**, luego vuelve a desplegar `horizon-api` para que los endpoints
    acepten el nuevo token. Los endpoints fallan cerrados, así que el antiguo y el nuevo no deben
    estar vivos a la vez por mucho tiempo.
  </Step>

  <Step title="Actualiza los monitores">
    Ejecuta `terraform apply <env>` para que Better Stack envíe el nuevo `x-health-token`
    en cada monitor (el token alimenta `TF_VAR_health_monitor_token`).
  </Step>

  <Step title="Verifica">
    Haz un smoke-test de los endpoints (abajo); todos deberían devolver `200`.
  </Step>
</Steps>

## Regenerar los recursos de la página de estado tras un apply

`BETTERSTACK_STATUS_PAGE_RESOURCES` mapea cada scope de componente a su id de recurso
de la página de estado, que la sincronización de degradado usa para abrir/cerrar Status Reports. Después de un
`apply` que crea o cambia recursos, regenéralo:

```bash theme={null}
node scripts/status-monitoring/fetch-status-page-resources.mjs <env>
```

Copia el JSON resultante en la variable `BETTERSTACK_STATUS_PAGE_RESOURCES` del entorno
en 1Password, luego ejecuta **Sync Env** y vuelve a desplegar. Terraform también expone
esto como el output `status_page_resources_json`.

## Detectar y resolver drift

El drift es cualquier diferencia entre la config commiteada y el estado en vivo de Better
Stack (usualmente por un cambio manual en la UI).

<Steps>
  <Step title="Detecta">
    Ejecuta un `plan`. Un resultado `0 to add, 0 to change, 0 to destroy` significa que no hay drift.
    Cualquier línea `~`/`+`/`-` es drift.
  </Step>

  <Step title="Decide la dirección">
    **El código gana** (la norma): `apply` para empujar la config commiteada sobre el
    cambio manual. **Adopta el cambio**: actualiza el `.tf`/manifiesto para que coincida con
    la realidad, luego confirma que el `plan` está limpio.
  </Step>

  <Step title="Audita los manifiestos (opcional)">
    Regenera y revisa el diff antes de hacer commit:

    ```bash theme={null}
    node scripts/status-monitoring/export-betterstack-inventory.mjs <env>
    node scripts/status-monitoring/generate-adoption-manifest.mjs --all
    git diff infra/betterstack/adopted/
    ```
  </Step>
</Steps>

## Simular degradado en development

Para ejercitar la ruta amarilla sin un incidente real:

```bash theme={null}
node scripts/status-monitoring/simulate-degraded-development.mjs
```

Luego confirma que el componente se pone amarillo vía un Status Report (no rojo) en la
página de estado de development.

## Smoke-test de los endpoints

```bash theme={null}
./scripts/status-monitoring/smoke-component-endpoints.sh
```

Carga `HEALTH_MONITOR_TOKEN` desde `backend/horizon-api/.env.development` y
verifica todos los endpoints de pull por componente. Sobrescribe el host o el token en línea:

```bash theme={null}
HOST=https://certification.api.bbrands.io \
HEALTH_MONITOR_TOKEN=<token> \
  ./scripts/status-monitoring/smoke-component-endpoints.sh
```

## Referencia de variables de entorno

Solo nombres — nunca commitees ni pegues valores.

| Variable                                         | Propósito                                              |
| ------------------------------------------------ | ------------------------------------------------------ |
| `HEALTH_MONITOR_TOKEN`                           | Secreto compartido `x-health-token` para los endpoints |
| `BETTERSTACK_UPTIME_API_TOKEN`                   | Provider de Uptime / gestión de la página de estado    |
| `BETTERSTACK_STATUS_PAGE_ID`                     | Id numérico de la página de estado por entorno         |
| `BETTERSTACK_STATUS_PAGE_RESOURCES`              | Mapa scope de componente → id de recurso (JSON)        |
| `BETTERSTACK_HEARTBEAT_CRON_HEALTH_API`          | Heartbeat para el cron health/api                      |
| `BETTERSTACK_HEARTBEAT_CRON_HEALTH_INTEGRATIONS` | Heartbeat para el cron health/integrations             |
| `BETTERSTACK_HEARTBEAT_CRON_METRICS_PUSH`        | Heartbeat para el cron metrics-push                    |
| `BETTERSTACK_METRICS_URL`                        | URL de ingesta de métricas de Telemetry (opcional)     |
| `BETTERSTACK_METRICS_TOKEN`                      | Token de métricas de Telemetry (opcional)              |
| `LOGTAIL_API_TOKEN`                              | Habilita los módulos Terraform de log-alerts           |
| `TF_BACKEND_OVERRIDE`                            | Bloque `backend "s3"` de estado remoto (secret de CI)  |
| `TF_STATE_ACCESS_KEY` / `TF_STATE_SECRET_KEY`    | Credenciales de estado remoto (secrets de CI)          |

## Código relacionado

* Runbook operativo: `docs/initiatives/betterstack/02-betterstack-runbook.md`
* Operaciones de la página de estado: `docs/operations/status-page.md`
* Script de sincronización de env: `scripts/env/sync-local.mjs`
