Skip to main content

Documentation Index

Fetch the complete documentation index at: https://wiki.vivla.com/llms.txt

Use this file to discover all available pages before exploring further.

Windmill

Windmill es la plataforma central de automatizaciones de Vivla. Desplegada en Railway como instancia self-hosted, gestiona syncs programados, webhooks y notificaciones desde un único workspace.

Arquitectura

┌──────────────┐     ┌──────────────────┐     ┌──────────────┐
│  Windmill    │────▶│  Vivla Tools API │────▶│  Supabase    │
│  (Railway)   │     │  (NestJS)        │     │  (PostgreSQL)│
└──────────────┘     └──────────────────┘     └──────────────┘
       │                     │
       │              ┌──────────────┐
       │              │  Firebase    │
       │              │  (Firestore) │
       │              └──────────────┘


┌──────────────┐
│  Slack       │
│  (alertas)   │
└──────────────┘

Workspace

Un único workspace vivla organizado por proyecto:
CarpetaProyectoContenido
f/vivla_tools/sync/Vivla ToolsSync jobs (users, properties, deals, bookings, firebase-legacy-responses)
f/vivla_tools/notifications/Vivla ToolsReemplazo de Firebase Cloud Functions
f/vivla_tools/webhooks/Vivla ToolsHandlers de eventos externos
f/vivla_backend/vivla-backendAutomaciones de eventos y migraciones
f/shared/CompartidoUtilidades cross-project (HTTP clients)

Variables de entorno

Los scripts reciben un parámetro env ('dev' o 'prod') y resuelven variables con el sufijo correspondiente:
const suffix = env === 'prod' ? '_prod' : '_dev'
const apiUrl = await wmill.getVariable(`f/vivla_tools/api_url${suffix}`)
const apiKey = await wmill.getVariable(`f/vivla_tools/api_key${suffix}`)
Variable devVariable prodSecret
f/vivla_tools/api_url_devf/vivla_tools/api_url_prodNo
f/vivla_tools/api_key_devf/vivla_tools/api_key_prodSi

Autenticación

Los scripts se autentican contra la API con x-api-key header. El backend valida el key via Auth0OrApiKeyGuard — el mismo guard que acepta tokens Auth0 para usuarios humanos. No requiere Auth0 M2M, no expira, no necesita refresh.

Sync Jobs

Endpoints

EndpointMétodoDescripción
/chat/sync/usersPOSTSync usuarios desde Firebase. Body: { chainDealsSync?: boolean }
/chat/sync/propertiesPOSTSync propiedades
/chat/sync/dealsPOSTSync deals
/chat/sync/bookingsPOSTSync bookings
/chat/sync/firebase-legacy-responsesPOSTSync respuestas NPS legacy (3 colecciones Firebase → survey_legacy_responses)
/chat/sync/jobs/:idGETEstado del job (incluye errorMessage y steps en caso de fallo)
/chat/sync/jobs/:id/logsGETLogs detallados del job
/chat/sync/jobsGETListar jobs recientes

Flujo de ejecución

  1. Windmill llama POST /chat/sync/{entity} con x-api-key
  2. Backend crea un sync job en chat_sync_jobs y ejecuta el sync
  3. Windmill poll GET /chat/sync/jobs/:id cada 5 segundos hasta completion
  4. En caso de fallo, el error se guarda en error_message + chat_sync_logs

Flows programados

Daily Full Sync

Sync completo diario de todas las entidades:
  • Path: f/vivla_tools/sync/sync_full
  • Schedule: 0 4 * * * (4:00 AM UTC)
  • Retry: 2 reintentos, 5 minutos de backoff
StepScriptInput
1sync_usersenv = flow_input.env, chainDealsSync = true
2sync_propertiesenv = flow_input.env
3sync_bookingsenv = flow_input.env
4sync_firebase_legacy_responsesenv = flow_input.env
5slack_notifyResultado de steps anteriores
Cada step debe tener env conectado a flow_input.env. Si no se conecta, el step usa el default 'dev' aunque el schedule pase 'prod'. Esta es la misconfiguration más común — si el sync prod parece no funcionar, verificar primero este wiring.

NPS Legacy Responses (Hourly)

Sync independiente de respuestas NPS legacy:
  • Path: f/vivla_tools/sync/sync_firebase_legacy_responses
  • Schedule: 0 * * * * (cada hora)
  • Colecciones: nps-home-responses, nps-booking, nps-home-excellence-values
El sync es idempotente (upsert en source_collection + source_doc_id).

Slack Notifications

El último step del flow envía un resumen a Slack usando Block Kit:
  • Canal: #vivla-tools-sync
  • Resource: slack_auth (tipo RT.Slack configurado en Windmill)

Scripts de referencia

Todos los scripts están en el repo como referencia:
docs/internal/tools/chat/implementation/epics/3.2-sync-module-improvements/scripts/
  sync_users.ts
  sync_properties.ts
  sync_deals.ts
  sync_bookings.ts
  sync_firebase_legacy_responses.ts
  sync_full.ts
  slack_notify.ts

Debugging

Ver error de un sync job fallido

-- En Supabase SQL Editor
SELECT id, status, error_message, steps, result
FROM chat_sync_jobs
WHERE id = '<job-id>';

-- Logs detallados
SELECT level, message, context, created_at
FROM chat_sync_logs
WHERE job_id = '<job-id>'
ORDER BY created_at DESC;

Errores comunes

ErrorCausaSolución
MODULE_NOT_FOUND en CLIEl backend en prod ejecuta JS compilado pero el spawn apunta a .tsVerificar que sync.service.ts detecta dist/ y usa node + .js
variable not foundVariable de Windmill no existe o tiene path incorrectoVerificar sufijo _dev/_prod y el path exacto con f/ prefix
401 UnauthorizedAPI key no coincide con la del backendComparar variable de Windmill con API_KEY en Railway
Job failed sin detalleScript Windmill no lee errorMessage del jobActualizar script para incluir errorMessage y steps en el throw
Prod sync hitting devenv no conectado a flow_input.envAbrir flow editor, conectar cada step a flow_input.env

Documentación técnica detallada

Para guías paso a paso de configuración del workspace:
  • docs/internal/tools/chat/implementation/epics/3.2-sync-module-improvements/02-windmill-setup-guide.md
  • docs/internal/tools/chat/implementation/epics/3.2-sync-module-improvements/03-windmill-configuration-walkthrough.md