Arquitectura del Sistema
Diagrama completo de servicios
Infraestructura de producción
| Componente | Red | Acceso externo |
|---|---|---|
| node-api | Docker bridge crimoo_net | Solo via gtm-proxy (puerto 3000 expuesto en host) |
| PostgreSQL | Docker bridge crimoo_net | Solo dentro del bridge |
| ClickHouse | Docker bridge crimoo_net | Solo dentro del bridge |
| gtm-fabric | Host network | Via Tailscale (100.97.60.119:8000) |
| gtm-proxy | Host network | Público (:80/:443) + Tailscale |
Control Plane vs Data Plane
| Control Plane | Data Plane | |
|---|---|---|
| Servicio | node-api | gtm-fabric + gtm-proxy |
| Rol | Gestión, configuración, billing | Procesamiento de eventos en tiempo real |
| Escala | Única instancia (o pocas) | Una VM por cliente/zona |
| BD | PostgreSQL + ClickHouse | Sin BD propia — todo via node-api |
| Estado | Stateful | Stateless |
gtm-fabric es stateless
gtm-fabric no tiene base de datos propia. Para cualquier dato de configuración consulta a node-api:
- Al arrancar →
GET /internal/fabric/gtms?vmId=X(carga GTMs en cache local) - Durante procesamiento → consulta node-api si necesita datos que no tiene en cache
- Al capturar contactos → flush batch a
POST /internal/fabric/contacts/batch - Al reportar uso → flush batch a
POST /internal/fabric/usage
El único storage que usa directamente es ClickHouse para escribir eventos de tagging y logs de containers.
Comunicación node-api → gtm-fabric
node-api se comunica con gtm-fabric por HTTP directo (no Pub/Sub):
| Acción | node-api llama a gtm-fabric |
|---|---|
| Crear GTM | POST /api/v1/gtm |
| Eliminar GTM | DELETE /api/v1/gtm/:id |
| Actualizar dominio primario | POST /api/v1/gtm/:id/domains/update |
| Añadir dominio custom | POST /api/v1/gtm/:id/domains/add |
| Remover dominio | DELETE /api/v1/gtm/:id/domains/remove |
| Habilitar custom loader | PUT /api/v1/gtm/:id/custom-loader |
| Deshabilitar custom loader | DELETE /api/v1/gtm/:id/custom-loader |
| Activar preview header | POST /api/v1/gtm/:id/preview-header |
| Remover preview header | DELETE /api/v1/gtm/:id/preview-header |
Pub/Sub — proyecto, topics y subscriptions
Proyecto GCP: graceful-splice-493501-q7 (único). Cualquier referencia a mystical-accord-480500-p7 es legacy y debe migrarse.
| Topic | Publisher | Consumer (subscription) | Mensaje |
|---|---|---|---|
gtm-tagging-topic | gtm-proxy | tagging-events-vm-{vmId}-sub (gtm-fabric) | TaggingEvent (eventos HTTP del browser) |
gtm-operations-topic | node-api | gtm-operations-vm-{vmId}-sub (gtm-fabric) | Comandos de gestión GTM por VM |
Patrón de subscriptions dinámicas: una subscription por VM, con nombre derivado del vmId. Las subscriptions se crean externamente (Terraform / scripts de despliegue) — PubSubSubscriptionManager solo las identifica al arrancar y falla con IllegalStateException si la subscription no existe.
Service Account única: crimoo-pubsub-sa@graceful-splice-493501-q7.iam.gserviceaccount.com
- Roles:
pubsub.publisher,pubsub.subscriber,pubsub.viewer,secretmanager.secretAccessor,monitoring.metricWriter,logging.logWriter - Key montada en
/opt/crimoo/gcp-credentials.jsonen el VPS, compartida por gtm-proxy y gtm-fabric (volume mount idéntico en ambosdocker-compose.yml).
Fail-fast al startup: PubSubEventPublisher (gtm-proxy) verifica con TopicAdminClient.getTopic() que el topic existe antes de inicializar el publisher. Si no existe → el bean falla y el proxy no levanta.