Estado del entorno
Una página exclusiva para super_admin (/system/environment) que reporta cuáles de las integraciones de la plataforma están realmente configuradas — a través del backend y ambos frontends de Next.js — sin exponer jamás un valor secreto. Esto no estaba documentado hasta ahora; la funcionalidad se construyó en una sesión posterior al resto de este conjunto de documentación de administración.
Deliberadamente más estricto que la protección estilo VIEW_ANALYTICS usada por los resolvers del dashboard: esta superficie enumera todo el inventario de integraciones de la plataforma (qué proveedores están conectados, qué credenciales faltan, qué regiones/IDs de cuenta están en juego), lo cual es un mapa de reconocimiento aunque nunca se devuelva un valor secreto — así que toda query y mutation aquí requiere super_admin, no solo un permiso puntual.
Checklist de implementación
- Reportar la configuración propia del backend (
adminGetEnvironmentStatus) — leeconstants/env-catalog.js(18 grupos, 109 variables) contraprocess.envy devuelve, por variable: si está configurada, su longitud, su nivel de requerimiento resuelto (required/recommended/optional, donde algunas variables solo son requeridas cuando otra variable es igual a un valor dado — p. ej. las variables de BigQuery cuandoANALYTICS_DB_TYPEesbigquery), y — para las variables que el catálogo marca explícitamente comosecret: false(nombres de región, IDs públicos, feature flags, URLs públicas) — el valor real. Todo lo demás reporta presencia y longitud únicamente, nunca el valor. - Reportar la configuración propia de un frontend desplegado (
adminGetFrontendEnvironmentStatus(app: WEB | ADMIN)) — proxeado servidor-a-servidor: el backend consulta/api/env-statusen la URL desplegada de la app objetivo (FRONTEND_URLparaWEB,ADMIN_FRONTEND_URLparaADMIN) ya que no puede inspeccionar de otra forma el entorno de un proceso Next.js separado. Cada frontend cataloga sus propias variablesNEXT_PUBLIC_*(frontend-nextjs: 19;frontend-admin: 2) en unsrc/lib/env-catalog.tslocal y las sirve, sin autenticación, desdesrc/app/api/env-status/route.ts— seguro porque cualquier cosaNEXT_PUBLIC_*ya es legible desde el bundle de JS desplegado con ver-código-fuente, así que no hay nada que proteger. Si la consulta falla (app inalcanzable, tiempo agotado, o su variable*_URLno está configurada en el backend), el grupo vuelve con un arrayvariablesvacío y un mensajefetchErroren lugar de arrojar un error. - Ejecutar una prueba de conectividad en vivo por grupo (
adminTestEnvironmentGroup(groupId)) — una mutation (no una query) ya que contacta a terceros y nunca debe agruparse en lote, cachearse o precargarse. 9 de los 18 grupos del backend declaran untest(database,redis,storage,email,analytics,push,payments,ads,livekit); el resto no tiene prueba de conectividad y la mutation lo reporta en lugar de fallar.adsagregado en esta sesión: cuandoGAM_NETWORK_CODE/GAM_SERVICE_ACCOUNT_KEYestán configurados, ahora prueba la conectividad con GAM mediantegam-report.service.js#testConnection— se autentica y resuelve la clave de segmentación personalizadacreatorsin llegar a ejecutar un reporte real. Cada prueba compite contra un límite de 8s. Las ejecuciones exitosas/fallidas se registran con el id del administrador que las llamó, con fines de auditoría, ya que ejercitan credenciales de producción contra proveedores reales. - Interfaz de frontend (
/system/environment) — tres pestañas (Backend / Admin / Web), cada grupo renderizado como un acordeón cerrado por defecto, con una marca verde de "todo bien" cuando toda variable requerida de ese grupo está configurada (un grupo puede mostrarse en verde aunque tenga variables opcionales sin configurar — el criterio es "no falta nada requerido", no "100% configurado"). Cada fila de variable muestra un ícono de tres estados (configurada / falta-y-es-requerida / falta-y-es-opcional — una variable opcional faltante deliberadamente no se muestra como un problema) y, al expandirse, su nivel de requerimiento, un enlace a documentación cuando el catálogo tiene uno, y (para variablessecret: false) el valor real. Estado de carga con forma tipo skeleton, no un spinner, igual que el resto del panel de administración.
Una decisión estructural que vale la pena señalar
El catálogo del backend (constants/env-catalog.js) solo contiene estructura — key, secret, requirement, requiredIf, docsUrl — sin ninguna etiqueta, descripción o texto de "cómo obtener esto". Todo ese texto vive en apps/frontend-admin/src/messages/{en,es}.json bajo system.environment.groups.<id> y system.environment.variables.<KEY>, buscado por el id/key que define el catálogo y renderizado mediante next-intl. Esto evita que la página quede alguna vez en solo inglés en un idioma (ver la regla de i18n del CLAUDE.md del repositorio) y está reforzado por una prueba del backend (tests/unit-test/env-catalog.unit.test.js) que hace fallar el build si una entrada del catálogo no tiene sus mensajes correspondientes en ambos idiomas.
Referencia técnica
query AdminGetEnvironmentStatus {
adminGetEnvironmentStatus {
nodeEnv
checkedAt
totalMissingRequired
groups {
id
testable
missingRequired
configured
total
fetchError
variables {
key
isSecret
isSet
value
valueLength
requirement
isMissing
docsUrl
}
}
}
}
query AdminGetFrontendEnvironmentStatus($app: AdminFrontendApp!) {
adminGetFrontendEnvironmentStatus(app: $app) {
id testable missingRequired configured total fetchError
variables { key isSecret isSet value valueLength requirement isMissing docsUrl }
}
}
mutation AdminTestEnvironmentGroup($groupId: String!) {
adminTestEnvironmentGroup(groupId: $groupId) { groupId ok message durationMs testedAt }
}
Backend: graphql/types/admin/env-status.type.js, graphql/resolvers/admin/env-status.resolver.js, managers/admin-managers/env-status.manager.js, constants/env-catalog.js. Frontend: apps/frontend-admin/src/app/system/environment/page.tsx, el src/lib/env-catalog.ts propio de cada app + src/app/api/env-status/route.ts.
La página /system (métricas de salud del sistema + exportación de analítica) es una funcionalidad distinta — ver Dashboard de analítica para adminGetSystemHealth y adminExportAnalytics.