Ir al contenido

Integración de tenant

Espejo es multi-tenant por diseño (ver Conceptos centrales): un tenant por cuenta de cliente, un proyecto por cosa que graban, una clave pública por proyecto embebida en las páginas de ese producto. Integrar un nuevo tenant tiene la misma forma sin importar quién sea — esta página lo recorre usando Angirú, la plataforma de gestión agropecuaria, que es el tenant #1.

El propio README de Espejo lo dice sin rodeos: el proyecto empezó como el grabador interno de Angirú — una extensión de Chrome que funcionaba pero requería instalación, no tenía concepto de tenant, y solo veía el tráfico de red la mitad del tiempo (chrome.webRequest no puede leer cuerpos sin el protocolo DevTools, que muestra el banner intrusivo de “siendo depurado”). Espejo generalizó eso en un grabador basado en <script>, multi-tenant; la extensión en sí sobrevive solo para lo que un script de página estructuralmente no puede hacer — seguir varias pestañas y capturar cosas fuera del navegador.

Esa historia también explica por qué el adaptador de almacenamiento tiene el cliente S3 con la forma específica para R2 (region: 'auto', forcePathStyle: true) — es la misma forma ya probada contra R2 por el grabador original de Angirú.

  1. Por ahora, antes de que exista la consola, eso es BootstrapService (apps/api/src/bootstrap.service.ts): en cada arranque garantiza de forma idempotente un tenant/proyecto/clave a partir de variables de entorno. El de Angirú está configurado exactamente así en .env.example:

    Ventana de terminal
    BOOTSTRAP_TENANT=Angiru
    BOOTSTRAP_PROJECT_SLUG=angiru
    BOOTSTRAP_PROJECT_NAME=Angiru
    BOOTSTRAP_INGEST_KEY=pk_live_cambiame

    Una vez que la consola esté disponible, esto pasa a ser POST /v1/projects desde una sesión de usuario real (ver API de consola) — las variables de bootstrap son un puente, no el camino permanente, y el plan es eliminar BootstrapService una vez que esa pantalla exista.

  2. El frontend de Angirú incluye el script tag con la clave pública de su proyecto, igual que cualquier integrador:

    <script src="https://dbuger.dnh.ar/sdk/espejo.js" data-key="pk_live_..."></script>

    y conecta su propia UI de “Reportar un problema” para llamar a espejo.report(description) (ver Quickstart), que sube lo que haya en el ring buffer en ese momento y devuelve la URL de la grabación.

  3. Lo que pasa después de report() es responsabilidad de Angirú, no de Espejo

    Sección titulada «Lo que pasa después de report() es responsabilidad de Angirú, no de Espejo»

    El trabajo de Espejo termina al devolver una URL de sesión. Lo que un tenant específico hace con esa URL — adjuntarla a un ticket de soporte, abrir un issue en GitHub, alertar a alguien — es lógica de producto que vive en el código del propio tenant, nunca en Espejo. Angirú, por ejemplo, convierte un reporte en un issue de GitHub de su lado; ese flujo (y su documentación) vive en el repositorio de Angirú, no acá — este repo solo produce la grabación y el enlace a ella.

Nada de incorporar un segundo tenant está tratado como caso especial para Angirú. Las garantías que mantienen a los tenants separados son estructurales, descritas en detalle en Conceptos centrales y Servidor MCP:

  • Toda consulta que toca una sesión filtra a través de la relación project.tenant_id — nunca una lista resuelta de ids que podría quedar desactualizada.
  • Una sesión o un scope que no se encuentra devuelve el mismo 404 que uno que no existe, tanto en la API de consola como en las herramientas MCP — nunca un 403 que confirme que el id es real.
  • La clave de administrador (x-espejo-admin-key) ve todos los tenants, que es exactamente por qué se rechaza donde el acceso se otorga en nombre de una persona: crear un proyecto, o cualquier cosa bajo /v1/mcp/*.
  • El scope de proyecto de una conexión MCP se fija una sola vez, al momento del consentimiento, desde user.tenant.id — nunca desde un parámetro de la request.