Documento de comprensión · pre-implementación

El journey no es una pantalla. Es un sistema que conversa con el cliente en cada hito.

Alberto diseñó en un Excel con macros el "cerebro" de Goopcar: máquinas de estado que acompañan al cliente por WhatsApp, automáticamente, desde que compra su auto hasta que lo renueva. Este documento traduce ese diseño a un modelo claro, lo muestra funcionando, y lo conecta con el motor que ya existe en el código — para que pase a producción de forma eficiente, sostenible y escalable.

Journey = máquina de estados + reglas + mensajes Canal único: WhatsApp config-as-data · 0 código por journey Modelo de negocio: 5 productos · 37 módulos · 90 journeys
1 La idea en 30 segundos

La tesis de Alberto, en una frase

Un journey es el ciclo de vida del cliente-vehículo en postventa, sostenido por un canal de comunicación siempre activo que toca cada hito accionable. Cada estado del cliente se empareja con un mensaje automático; cada respuesta del cliente mueve el estado. El sistema toma el control — no el asesor.

"Muchos de esos estados que estamos hablando después los podríamos poner asociados a mensajes automáticos. Esa es la idea." — Alberto Jara (recogido en las notas de Óscar)
🔁

Estado ↔ mensaje

Enviar un mensaje es una señal de estado. "Tu auto ya está en el taller" confirma el ingreso. La comunicación es la fuente de verdad del avance.

🤖

El sistema toma el control

El asesor ve uno o dos días; el journey dura años. Por eso la automatización orquesta — pero todo queda visible y auditable en el ledger.

💰

Hacia hitos monetizables

"El journey se tiene que traducir en hitos monetizables." Cada bitácora distingue hitos que generan ingreso de hitos de apoyo.

⚠️
Cómo leer este documento. Alberto no siempre formaliza lo que quiere; parte del trabajo fue interpretarlo. Donde el modelo es una lectura nuestra (no su palabra literal) lo señalamos. Y donde falta que él decida, lo dejamos explícito en la sección 9 — son 6 preguntas que hoy bloquean la implementación.
2 Dos horizontes

El micro-journey y el macro-journey

Todo cliente vive dos escalas anidadas. El micro-journey es una visita al taller (días). El macro-journey es la tenencia del auto (años), que enlaza un micro-journey con el siguiente por desgaste o kilometraje.

Micro-journey · la visita

La cita o mantención: T-2 → T+1. Es el journey operativo que el asesor gestiona a diario. Ocho hitos funcionales, algunos monetizables.

Monetizable — genera ingreso Apoyo — sostiene la relación
M0
Solicitud / Origen
Opcional si viene del DMS
Apoyo
M1
Agendamiento / Confirmación
T-2/T-1 · reduce inasistencia + oferta de adicionales
Monetiza
M2
Check-in físico
T0 · bienvenida y apertura de OT
Apoyo
M3
Diagnóstico y presupuesto
Aprobación de adicionales — el upselling
Monetiza
M4
Estatus de avance
"Terminamos frenos, empezamos lavado"
Apoyo
M5
Cierre y cobranza
Link de pago adelantado desde WhatsApp
Monetiza
M6
Check-out / retiro
Entrega formalizada
Apoyo
M7
Encuesta CX / NPS
T+1 · si nota < 7, alerta inmediata
Apoyo
Macro-journey · la tenencia

Los años que el cliente es dueño del vehículo. El sistema lo acompaña entre visitas y detecta el próximo momento de valor.

Dos señales que Alberto separa

  • Próxima acción del journey — la mantención que "toca" por kilometraje (ej: los 20.000 km).
  • Próxima oportunidad — una venta cruzada distinta: revisión técnica, seguro obligatorio, garantía extendida.
"¿Cuál es la próxima acción del journey? La de 20.000… Pero ¿cuál es la próxima oportunidad? Una revisión técnica. O la venta de seguro obligatorio." — Alberto Jara

El macro-journey cierra con la renovación / retoma (venta de unidad nueva) — y detecta la fuga hacia (o desde) otro concesionario con scoring. Cerca del 50% de los clientes no llega a su primera mantención: ese churn es el dolor que el sistema ataca.

Fuentes: Docs/Contexto/31_journeys.md, notas de Óscar sobre las reuniones, SSoT-Vision-Alberto-Jara.md.

3 Las piezas

Anatomía de un journey

El Journey Designer de Alberto define diez piezas. Lo notable: casi todas ya tienen su tabla en el esquema del proyecto. Haz clic en cada pieza para ver qué es y cómo se aterriza en código.

🗺️
Journey
Config_Journey · la unidad diseñable

Un flujo conversacional con un objetivo de negocio. Es una máquina de estados completa y autocontenida: se crea, cambia o agrega sin tocar el motor ni otros journeys (Journey-as-Module).

ExcelConfig_JourneyPrismaJourneyDefinition
codeversionnameproductCodemoduleCodeinitialStateCodetriggerEventactive

Identidad (code, version). Sin tenantId: es catálogo de producto, no dato de un cliente.

Estado
Config_Estados · nodo de la FSM

Dónde está el cliente en el journey (Pendiente, Confirmado, EnServicio…). Un journey tiene un estado inicial; los estados finales lo cierran; un estado puede encadenar a otro journey.

ExcelConfig_EstadosPrismaJourneyState
codeisFinalblockschainsToJourneyCode
Trigger
Trigger_Journey · cuándo se dispara

La condición que enciende el journey. Dos clases: por evento (una variable/estado cambia) o por tiempo (una ventana temporal). Formato: SI [condición] Y [ventana] → ENTONCES [journey].

ExcelTrigger_Journey (TRI)PrismaJourneyDefinition.triggerEvent
Tipo_TriggerVariable_TriggerOperadorValor_TriggerTiming (15_seg…365_dias)Temporalidad (Antes/Exacto/Despues)Prioritario
🛡️
Orquestación (guarda)
Config_Orquestacion · ¿puede correr?

Se evalúa después del trigger y antes de instanciar: una condición que permite o bloquea. Es el "validador de redundancia" de Alberto: no mandar recordatorio si el cliente ya confirmó.

ExcelConfig_Orquestacion (ORQ)PrismaOrchestrationRule + JourneyTransition.guard
variableoperatorvalueconnector (Y/O)permits

⚠️ Gap: la tabla existe pero el motor aún no la consulta. Ver sección 8.

➡️
Transición
la arista de la máquina de estados

Conecta un estado con el siguiente. Se dispara por uno de tres elementos: el Mensaje Inicial, un Botón que el cliente presiona, o un Timeout. Al aplicarse, actualiza variables y puede encadenar otro journey.

ExcelConfig_Estados (Elemento)PrismaJourneyTransition
fromStateCodehitoTypehitoQualifiertoStateCodevariableUpdatesguard
💬
Mensaje / Plantilla
Config_Mensajes · el contenido

El texto que se envía, emitido por bot, asesor o IA. Usa variables {{Nombre_Cliente}} y botones de respuesta rápida. Son plantillas WhatsApp pre-aprobadas (HSM). Solo admin las crea — gobernanza.

ExcelConfig_MensajesPrismaJourneyMessageCommunicationTemplate
codeactor (bot/advisor/ia)templateCodeemitOnStateCode
🔤
Variable
DN_Variables · la memoria del journey

Datos que el journey lee (en triggers y guardas) y escribe (como efecto de una transición). Ej: Vehiculo_Nuevo, Bienvenida_Enviada, Cliente_Activado. También son los merge-tags de los mensajes.

ExcelDN_Variables + Actualizar_VariablesPrismaJourneyVariable + OperationalCase.variablesJson
namedefaultValuedescription
⏱️
Timeout
Config_Timeout · si no responde

Qué pasa si el cliente no responde en un plazo. Define la espera y cuántas veces reintentar antes de forzar la transición. Es el "trigger temporal" que exime al asesor de acordarse.

ExcelConfig_TimeoutPrismaJourneyTimeout
stateCodewaitDurationrepeatresultEvent

⚠️ Gap: falta el worker que dispare timeouts del motor genérico en producción.

🔗
Encadenamiento (JOU_OUT)
un journey lanza al siguiente

El estado final de un journey puede convertirse en el disparador del siguiente. Así se compone el macro-journey a partir de micro-journeys: activación → mantención → renovación.

ExcelConfig_Estados.JOU_OUTPrismaJourneyState.chainsToJourneyCode

⚠️ Gap: el modelo lo registra en el ledger (journey.chained) pero aún no crea la instancia encadenada.

4 Cómo cobra vida

El motor: un solo handleHito() para todos los journeys

El motor no sabe de "el journey del taller" ni de "el de activación". Solo sabe procesar hitos. Un hito llega, el motor busca qué transición calza, la aplica, y avanza. Esto es config-as-data: los journeys son datos, el motor es genérico. Agregar el journey número 91 es registrar datos, no escribir código.

Los cuatro hitos que el mundo le manda al motor

📤message_sent

Se envió un mensaje. Suele ser el hito que abre el journey (y confirma un estado).

👆customer_reply

El cliente respondió: por botón, texto o lista. Es lo que ramifica el flujo.

⏱️timeout_elapsed

Venció el plazo de espera. El cliente no respondió: se fuerza la transición de timeout.

🏭dms_event

El sistema del taller (DMS) reportó algo: apertura de OT, pago, cierre. Único origen válido para el ingreso físico.

El ciclo de OrchestrationEngine.handleHito(hito)

Idempotencia
¿Ya procesé este eventId? Marcador durable en el ledger — un webhook repetido no avanza dos veces.
Resolver instancia
Ubico el caso del cliente. Aislamiento multi-tenant: un hito solo mueve casos de su propio tenant.
Resolver adopción
TenantJourney me dice qué versión del journey usa este tenant y con qué overrides (sus plantillas WABA, sus textos).
Match de transición
Busco la arista que calza: fromStateCode + hitoType + hitoQualifier + guard sobre las variables.
Aplicar
Cambio de estado · actualizo variables · escribo en el ledger · emito mensajes (con overrides) · encadeno el siguiente journey · armo el timeout.
🛡️
Barandas de doctrina embebidas. El motor rechaza con DOCTRINE_NO_DOUBLE_INPUT toda transición al estado físico "ingresado" que no venga de un dms_event. La doctrina de Goopcar vive dentro del motor.

Fuente: Docs/adr/0003-config-as-data-journey-engine.md, apps/api/src/modules/journey-engine/orchestration/.

5 Ver para creer

Journeys reales, funcionando

Estos no son ejemplos inventados: son los journeys que ya viven como datos en el repositorio. Explora la máquina de estados, y en el primero, juega la conversación por WhatsApp como si fueras el cliente.

code JOU_001 v1 producto ENGAGE_PLUS trigger Vehiculo_Nuevo = 1 inicial Pendiente timeout 30 min

Cuando alguien compra un auto 0 km, el sistema abre su canal de postventa por WhatsApp y le ofrece activarlo. Según responda, ramifica — y si activa, encadena al siguiente journey (JOU_010).

Haz clic en un estado del diagrama para ver su mensaje, sus transiciones y su timeout.

Juégalo: la conversación real por WhatsApp

Simulación fiel al descriptor jou001.package.ts. Cada clic emite un hito real del motor.

code TALLER v1 módulo MOD_TALLER trigger Agendamiento inicial NuevoIngreso estados 18

El journey operativo de la visita al taller — el que más le importa a Alberto. 18 estados, un camino feliz y sus rutas de excepción (no-show, reagendamiento, recuperación). Hoy avanza por dms_event. Haz clic en un estado para ver el mensaje automático que debería emitir en ese hito.

Haz clic en un estado para ver su rol y el mensaje del hito.
💡
La brecha entre el código y la visión. Hoy taller.package.ts tiene messages: [] — solo modela las transiciones. Los textos que ves al hacer clic son la propuesta derivada de las plantillas canónicas de Alberto. Poblar esos mensajes es exactamente "asociar cada estado a un mensaje automático" — su tesis central.

Fuentes: jou001.package.ts, taller.package.ts, Docs/Contexto/33_templates_mensajes.md, .claude/rules/backend.md §6.

6 La ambición completa

El universo: 5 productos, 37 módulos, 90 journeys

Los dos journeys que exploraste son la punta del iceberg. El modelo de negocio canónico de Alberto (Excel 2606 Detalle Goopcar Tech) define 90 journeys en 5 productos y 37 módulos, que cubren toda la vida del cliente-vehículo — de la compra a la renovación. Hoy solo 5 están diseñados como máquina de estados; los otros 85 son intención declarada, listos para poblarse como datos sobre el mismo motor.

Engage+
Canal de comunicación digital (infraestructura del WhatsApp gobernado).
10 módulos0 journeys
Service
El journey de postventa: la visita al taller de punta a punta.
9 módulos30 journeys
Mobility
Movilidad y traslados asociados al servicio (señal, no gestión logística).
5 módulos15 journeys
Loyalty
Retención, campañas, reactivación, no-show y fidelización.
7 módulos20 journeys
Ownership+
Venta de productos, cumplimiento, protección, retoma y renovación.
6 módulos25 journeys

Los cinco productos son las fases del ciclo de vida: Engage+ (el canal) sostiene a los otros cuatro, que van de la postventa inmediata (Service) a la renovación del auto (Ownership+), pasando por movilidad y fidelización.

El "spine" real: lo único diseñado hoy

Un solo camino está modelado como FSM ejecutable: el onboarding post-compra. Nace de la compra de un 0 km y encadena cinco journeys diseñados. Los destinos en gris son journeys ya referenciados pero aún sin diseñar — el trabajo pendiente es poblarlos.

🚗 Compra de vehículo 0 km
Estado raíz: Vehiculo_Nuevo → dispara JOU_001 (+24 hrs, prioritario)
JOU_001Activación Canal Postventadiseñado v56
trigger: Vehiculo_Nuevo · +24_hrs · Exacto · prioritario
Botón 1 → Cliente_Activado JOU_002 · Seguimiento de cortesía
Botón 2 → Cliente_No_Activado JOU_004 · sin diseñar
Timeout → Cliente_No_Responde
JOU_002Seguimiento de cortesía del clientediseñado v35
trigger: Cliente_Activado · +30_dias · Exacto
Mensaje / Botones → Cliente_Contactado JOU_003 · 1ra mantención
JOU_003Indicación de primera mantencióndiseñado v5
trigger: Cliente_Contactado · +90_dias · Exacto
Mensaje / Botón 1 → Cliente_Contactado JOU_005 · Invitación a agendar
JOU_005Invitación a Agendar primera mantencióndiseñado v1
trigger: Cliente_Contactado · +30_dias · Exacto
Botón 1 → Cliente_Requiere_Agendar JOU_006 · Reserva de Hora
Botón 2 → Solicita_Recordar JOU_007 · sin diseñar
Timeout → Cliente_No_Responde
JOU_006Reserva de Horadiseñado v7
trigger: Cliente_Requiere_Agendar · +15_seg · Exacto
Flow → Cita_Agendada JOU_010 · Confirmación (sin diseñar)
Timeout → Cliente_No_Responde
⚠️
Discrepancia a reconciliar antes de implementar. El JOU_001 canónico (Excel 2606, v56) tiene 2 botones, encadena a JOU_002 / JOU_004 y su timeout es de 24 hrs. El JOU_001 del código (greenfield, jou001.package.ts) tiene 3 botones, encadena a JOU_010 y su timeout es de 30 min. El greenfield fue un vehículo para validar el motor, no el journey definitivo. Al implementar en serio, JOU_001 debe alinearse con el modelo canónico (o versionarse de forma explícita).
📎
Fuentes navegables (en el repo). El catálogo completo de los 90 journeys y el diagrama de alto nivel viven junto a este documento: Árbol de caminos del journey global (jerarquía navegable + máquina de estados del spine) y Diagrama del journey global (vista fase → etapa). Fuente original: 2606 Detalle Goopcar Tech.xlsm.
7 Cómo escala a 90 journeys y a muchos tenants

Los tres planos: definición, adopción, instancia

Aquí está la clave de "sostenible y escalable". Un journey se diseña una vez (genérico), cada concesionario lo adopta con sus textos, y cada cliente tiene su instancia viva. Tres planos separados = un solo diseño sirve a todos los tenants sin duplicar código.

Plano 1

Definición

catálogo genérico · sin tenantId · sin RLS

La FSM como datos. Identidad (code, version). Es activo de producto: se versiona y se comparte entre todos los concesionarios.

JourneyDefinitionJourneyStateJourneyTransitionJourneyMessageJourneyVariableOrchestrationRuleJourneyTimeout
Plano 2

Adopción

per-tenant · con RLS

Qué journey usa cada concesionario, en qué versión, y con qué overrides: sus plantillas WABA propias, sus textos, su marca.

TenantJourneytenantIdjourneyCodeadoptedVersionoverridesJson
Plano 3

Instancia

per-tenant · con RLS

El journey vivo de un cliente concreto: en qué estado está y el valor de sus variables. El historial es append-only en el ledger.

OperationalCase.currentStateCodevariablesJsonLedgerEntry

Invariante del ADR-0003: definición genérica + adopción per-tenant. La definición nunca lleva tenantId; el aislamiento vive en adopción e instancia.

8 El puente

Del Excel de Alberto al código actual

La conclusión que hace esto viable de programar hoy: el motor config-as-data ya existe y su esquema calza casi 1:1 con el Journey Designer. No hay que reinventar — hay que poblar datos y cerrar unos pocos gaps.

Pieza del Journey Designer (Excel/VBA)Equivalente en el código (Prisma)Estado
Journey Config_JourneyJourneyDefinition (code, version)Existe
Estado Config_EstadosJourneyStateExiste
Mensaje InicialJourneyMessage (emitOnStateCode)Existe
Botón (respuesta) CFG_BotonesJourneyTransition (hitoType=customer_reply, qualifier=BTN_xxx)Existe
Timeout Config_TimeoutJourneyTimeout + transición timeout_elapsedParcial — falta worker
Mensaje / Template Config_MensajesJourneyMessageCommunicationTemplateExiste (WhatsApp)
Resultado / Acción Config_Resultado_AcciontoStateCode + variableUpdatesExiste
Variable DN_VariablesJourneyVariable + variablesJsonExiste
Orquestación Config_OrquestacionOrchestrationRulePersiste, motor no la consulta
Encadenamiento JOU_OUTJourneyState.chainsToJourneyCodeRegistra, no instancia
ProductoJourneyDefinition.productCode (string)Falta catálogo
MóduloJourneyDefinition.moduleCode (string)Falta catálogo
Recurso (adjunto) Config_RecursosCommunicationTemplate.metadataSin entidad propia
9 Deuda técnica priorizada

Lo que falta cerrar para producción

Siete tareas concretas separan el motor "validado en tests" del motor "corriendo journeys en vivo". Ordenadas por impacto.

1
Worker genérico de timeouts src/worker/tick.ts
El scheduler actual solo sirve al journey hardcodeado del taller. El motor data-driven no tiene barrido que dispare timeout_elapsed en producción. Bloqueante para tener JOU_001 vivo.
2
Cablear el flag JOURNEY_ENGINE_TALLER dispatcher.ts
El flag existe y la paridad está verificada por tests, pero el enrutado runtime (A2 ↔ motor genérico) no está conectado. Es el paso de contract.
3
Consultar OrchestrationRule en el motor orchestration/engine.ts
Las guardas se persisten pero el motor no las evalúa. Hoy hay dos mecanismos de condición en paralelo (guard en transición vs. OrchestrationRule) sin semántica diferenciada. Riesgo de bug latente.
4
Executor de encadenamiento (JOU_OUT) orchestration/engine.ts
chainsToJourneyCode existe y se loguea journey.chained, pero no se crea la instancia del journey siguiente. Sin esto, el macro-journey no se compone.
5
Poblar los mensajes del journey de taller taller.package.ts
messages: [] hoy. Asociar cada estado a su plantilla (confirmación, check-in, no-show, diagnóstico, listo, NPS) materializa la tesis "estado ↔ mensaje automático".
6
Tablas ProductCatalog y ModuleCatalog schema.prisma
Hoy producto/módulo son strings opacos. Necesarios para navegar la jerarquía de 5 productos / 37 módulos / 93 journeys del modelo de negocio.
7
Guardas sobre datos externos + repeat de timeout
Las guardas hoy solo leen variablesJson interno; disparar por datos de cliente/vehículo/OT requiere un resolutor de variables. Y el campo repeat > 0 aún no se ejecuta.
10 Antes de codear

Seis decisiones que Alberto debe cerrar

Estas ambigüedades salieron de las notas de Óscar sobre lo conversado con Alberto — él las marca como "clave" pero no las resuelve. Cada una tiene una recomendación nuestra; necesitamos su confirmación antes de escribir el código que depende de ellas.

1
¿Cuál es la unidad mínima / ID del journey?
"Es clave que definamos la unidad mínima… un ID a lo largo de todo el journey. Si lo definimos mal, nos puede dar muchos dolores de cabeza." — ¿Por cliente, por vehículo, o por caso operativo?
Caso por par Vehículo+Cita, dentro del macro-journey del vehículo
El micro-journey se ancla al par Vehículo+Fecha (ya en doctrina); el macro-journey vive en el vehículo. Concilia ambas escalas.
Un único ID por cliente
Simple, pero rompe cuando un cliente tiene varios autos o cambia de dueño.
2
Transiciones de estado: ¿automáticas o con override manual?
En reunión Alberto duda ("lo cambia el asesor… o se cambia solo"); en sus comentarios escritos es tajante ("no lo debería gestionar el asesor"). La doctrina prohíbe la transición manual al ingreso físico.
Automático por defecto, con override auditado
El motor avanza; el asesor puede corregir salvo el ingreso físico (solo por DMS). Todo override queda en el ledger.
Automático puro
Más limpio, pero sin válvula de escape para casos de borde reales del taller.
3
Los umbrales temporales concretos
Alberto dice "a las XX hrs de la cita" (no-show) y "si pasan X días" (riesgo de fuga), pero nunca pone el número. El motor los necesita como datos.
Defaults configurables por tenant
No-show T+4h, confirmación T-48h/T-24h, NPS T+24h, riesgo 15 días. Editables por concesionario vía overrides.
Fijos globales
Más simple de arrancar, pero cada taller opera distinto.
4
¿De quién es el journey y las oportunidades?
"No me gusta ese concepto de que el asesor es dueño del cliente… el asesor ve uno o dos días máximo." Pero el schema tiene assignedAdvisorId.
El sistema/tenant es dueño; el asesor es la lente
El journey y las oportunidades pertenecen al tenant; el asesor solo los ve dentro de su ventana temporal. Alinea con "Asesor-First".
El asesor es dueño de su cartera
Contradice a Alberto explícitamente; rompe la continuidad del journey largo.
5
¿Qué ve el asesor vs. el gerente?
Alberto oscila: "no sé si esto está a nivel de asesor o gerente… probablemente no [asesor]". Durante la reunión se sacaron plantillas, automatizaciones y oportunidades de la vista del asesor.
Asesor = cola de trabajo accionable; gerente = diseño y reportes
El asesor ejecuta hitos; el diseño de journeys, plantillas y KPIs viven en roles superiores. "No-Dashboard-en-Inicio".
Todo visible para todos
Sobrecarga al asesor con analítica que Alberto rechazó como puerta de entrada.
6
Modelo dueño / usuario del vehículo y destinatario de los mensajes
"Nos da harto dolor de cabeza porque no tenemos esa separación." El titular puede no ser quien conduce ni quien recibe los WhatsApp. Hoy el schema solo tiene customerId.
Separar titular / conductor / destinatario
Campos ownerCustomerId, primaryDriverCustomerId, messageRecipientCustomerId. Los mensajes van a quien tenga el "check" de gestionado.
Un solo customerId (hoy)
Riesgo real: mandar mensajes al dueño legal en vez del usuario que agenda y conduce.

Próximo paso sugerido

Validar este modelo con Alberto (usar la sección 10 como agenda de decisiones). Cerradas esas seis, el camino de implementación es corto porque el motor ya existe: poblar el journey del taller como datos, cerrar los gaps 1–4, y activar el flag con paridad verificada.

1 · Confirmar las 6 decisiones 2 · Poblar mensajes del taller 3 · Worker de timeouts + chaining 4 · Flip del flag con paridad 5 · Studio de autoría (fase 2)
Desarrollado por Cognitiva SpA
www.cognitivaspa.cl
Ingeniería inversa del archivo 2606 Journey Designer - Goopcar Tech.xlsm · modelo de negocio canónico 2606 Detalle Goopcar Tech.xlsm.