🔄 MVP — Dinamización de Conversaciones Abandonadas¶
Fecha: 1 de abril de 2026 Propósito: Estudio de viabilidad técnica del nuevo MVP Backlog solicitado por el cliente Estado: Análisis completo — Pendiente de decisión
1. Resumen del Requisito¶
"Incorporar un sistema de notificaciones para dinamización de conversaciones abandonadas, adaptando el cierre automático para procesos de continuidad (prevención, coach) e introduciendo notificaciones proactivas que animen al cliente a retomar la interacción."
Los 4 Pilares del MVP¶
| # | Pilar | Descripción |
|---|---|---|
| 1 | Identificar | Detectar conversaciones abandonadas en servicios de continuidad |
| 2 | Prorrogar | Incrementar tiempo de cierre automático para estos servicios |
| 3 | Notificar | Enviar push proactivos durante la prórroga |
| 4 | Resolver | Si retoma → continúa. Si no → cierra tras prórroga |
2. 🔑 Hallazgo Crítico: La Infraestructura YA Existe (60%)¶
Del análisis del código de QueueDetailsNotifications.jsx y Queue/index.jsx, la entidad Cola ya tiene los campos necesarios:
graph TB
subgraph "Campos que YA EXISTEN en la Cola"
A["max_inactive_patient_warning_time<br/>⏰ Aviso de inactividad del paciente<br/>(en minutos)"]
B["max_inactive_patient_time<br/>⏰ Tiempo Máximo de Inactividad del Paciente<br/>(en minutos)"]
C["close_inactive_encounters<br/>☑️ Cerrar casos inactivos automáticamente"]
D["max_inactive_time<br/>⏰ Tiempo Máximo de Inactividad general<br/>(en minutos)"]
E["revoke_inactive<br/>☑️ Revocar + re-evaluar políticas"]
end
subgraph "Lo que NECESITA el MVP"
F["Prórroga de cierre para servicios de continuidad"]
G["Notificación push al paciente durante prórroga"]
H["Configuración diferenciada por servicio/cola/motivo"]
I["Deep link para retomar conversación"]
end
A -.->|"Parcialmente equivalente a"| F
B -.->|"Es exactamente"| F
C -.->|"Controla"| F
style A fill:#059669,color:#fff
style B fill:#059669,color:#fff
style C fill:#059669,color:#fff
style D fill:#059669,color:#fff
style E fill:#059669,color:#fff
style F fill:#D97706,color:#fff
style G fill:#ef4444,color:#fff
style H fill:#D97706,color:#fff
style I fill:#ef4444,color:#fff
Mapeo Campo por Campo¶
| Campo existente | Tipo | Valor actual | ¿Sirve para MVP? |
|---|---|---|---|
max_inactive_patient_warning_time |
int (min) | configurable | ❌ PARCIAL / INVÍABLE: Netcomp dispara un push genérico estandarizado hardcodeado en Erlang (encounter_inactive) y solo se ejecuta una vez. Si queremos notificaciones multi-stage o custom, no podemos usarlo sin tocar Erlang. |
max_inactive_patient_time |
int (min) | configurable | ❌ INVÍABLE: Netcomp ejecuta un script de cierre incondicional (dkv_telemed_util:close_encounter). No permite prórrogas dinámicas desde Pet Flows. |
close_inactive_encounters |
bool | true/false | 🟡 Controla si actúa el script de Erlang. Para Pet Flows, deberá ser FALSE en colas dinamizadas. |
max_inactive_time |
int (min) | 15 | 🟡 Parcial — Es para el doctor, no para el paciente |
revoke_inactive |
bool | true/false | 🟡 Parcial — Reasignación, no notificación |
[!WARNING] Resultado del Spike técnico (Erlang/netcomp): Si reutilizamos
max_inactive_patient_warning_time, el sistema emite automáticamente un push nativo al paciente (ej: "Tu consulta sigue abierta") hardcodeado en el código fuente. Esto imposibilita una orquestación multi-stage de Push Notifications personalizada sin requerir despliegues de netcomp. La infraestructura existe, pero su rigidez contradice el requisito del cliente (mensajes configurables y multi-stage prórroga).
3. Análisis de Gap — Lo que Existe vs Lo que Falta¶
| Requisito MVP | ¿Existe? | Dónde | Gap |
|---|---|---|---|
| Detectar conversación abandonada | ✅ Existe | PET: lógica de inactividad en cola | Ninguno |
| Diferenciar por tipo de servicio | 🟡 Parcial | Cola tiene component_type, product_ids |
Necesita: filtro por "servicio de continuidad" |
| Diferenciar por cola | ✅ Existe | Cada cola tiene su propia config de tiempos | Ninguno |
| Diferenciar por motivo de apertura | 🔴 No existe | El encounter tiene closing_reason, pero no opening_reason en cola config | Gap: necesita nuevo campo o lógica |
| Incrementar tiempo de cierre | ✅ Existe | max_inactive_patient_time ya es configurable por cola |
Solo ajustar el valor |
| Enviar push al paciente | 🔴 No existe | El sistema actual envía emails a operadores, no push a pacientes | Gap principal |
| Deep link para retomar | 🔴 No existe | Gorush soporta deep links, pero no hay lógica de "retomar encounter" | Gap: necesita endpoint + deep link |
| Cierre tras prórroga | ✅ Existe | close_inactive_encounters + max_inactive_patient_time |
Solo configurar |
| Configurar mensajes por servicio/cola | 🔴 No existe | Las notificaciones existentes no tienen templates personalizables | Gap: templates de push |
Los 4 Gaps Principales¶
┌─────────────────────────────────────────────────────────────────────┐
│ GAP 1: Enviar push al PACIENTE (no al operador) │
│ → Hoy: email a destinatarios humanos (operadores/jefes de cola) │
│ → MVP: push notification al paciente via Gorush con deep link │
│ │
│ GAP 2: Lógica de "cuándo notificar" durante la prórroga │
│ → Hoy: hay un warning_time pero no se sabe qué acción dispara │
│ → MVP: a los X minutos de inactividad → push #1 │
│ a los Y minutos → push #2 (recordatorio) │
│ a los Z minutos → cierre definitivo │
│ │
│ GAP 3: Templates de notificación configurables │
│ → Hoy: no hay templates de push por cola/servicio │
│ → MVP: "Hola {{nombre}}, tu conversación con {{doctor}} │
│ sigue abierta. ¿Necesitas continuar?" │
│ │
│ GAP 4: Deep link de retoma │
│ → Hoy: no existe deep link a encounter activo │
│ → MVP: qcplus://encounter/{{encounter_id}}/resume │
└─────────────────────────────────────────────────────────────────────┘
4. Dos Opciones de Implementación¶
Opción A — Solo config PET (sin Pet Flows)¶
graph LR
PET["🐾 PET Cloud<br/>Detecta inactividad"]
-->|"Nuevo código Java"| LOGIC["⚙️ Lógica nueva<br/>Evalúa servicio<br/>Decide push"]
--> NTF["📲 dkv-notifications<br/>Envía push"]
--> APP["📱 QC+ App<br/>Deep link retoma"]
style PET fill:#009BE0,color:#fff
style LOGIC fill:#D97706,color:#fff
style NTF fill:#059669,color:#fff
Qué implica: - Añadir en PET (Java/Spring Boot) lógica que, al detectar inactividad del paciente, envíe push via dkv-notifications - Configurar templates de push en la cola (nuevos campos) - Implementar deep link de retoma en la app QC+
| Pro | Contra |
|---|---|
| Sin dependencia de Pet Flows | Código hardcodeado en PET |
| Rápido para 1 uso específico | No reutilizable para otros flujos |
| Equipo Java existente puede hacerlo | Sin editor visual, sin dashboard |
| Cada cambio = deploy de PET | |
| No soporta múltiples notificaciones en secuencia fácilmente |
Estimación: 15-20 SP, 2-3 semanas
Opción B — PET + Pet Flows (Recomendada)¶
graph LR
PET["🐾 PET Cloud<br/>Detecta inactividad"]
-->|"Webhook"| FLOWS["📊 Pet Flows<br/>Flujo visual"]
--> WAIT["⏱️ Wait<br/>Prórroga"]
--> PUSH["📲 Push<br/>via dkv-notifications"]
--> CHECK["🔍 ¿Retomó?<br/>Query a PET"]
CHECK -->|"Sí"| END1["✅ Fin<br/>Conversación activa"]
CHECK -->|"No"| PUSH2["📲 Recordatorio #2"]
PUSH2 --> CLOSE["🔒 Cierre<br/>POST a PET"]
style PET fill:#009BE0,color:#fff
style FLOWS fill:#7C3AED,color:#fff
style WAIT fill:#6366f1,color:#fff
style PUSH fill:#059669,color:#fff
style CHECK fill:#D97706,color:#fff
Qué implica:
- PET emite webhook cuando detecta inactividad del paciente (campo max_inactive_patient_warning_time)
- Pet Flows ejecuta un flujo visual que:
1. Espera N minutos
2. Envía push #1
3. Espera M minutos
4. Consulta PET: ¿el paciente retomó?
5. Si no → push #2
6. Espera P minutos
7. Si no retomó → cierra via API
| Pro | Contra |
|---|---|
| Configurable visualmente — marketing puede ajustar tiempos y mensajes | Necesita Pet Flows operativo (MVP Backlog primero o en paralelo) |
| Reutilizable — mismo motor para MVP Backlog (encuesta) y MVP | Más componentes en producción |
| Dashboard — se ve qué conversaciones están en prórroga | Mayor complejidad inicial |
| Escalable — mañana añades email, SMS, IA | |
| No toca código Java para cambios de flujo |
Estimación: 25-30 SP, pero reutiliza 80% del trabajo del MVP Backlog
5. Diseño del Flujo MVP (Opción B Refinada — Dapr Timers)¶
Dado que no podemos modificar el core de Erlang para detener el push automático y único, Pet Flows se convierte en el Orquestador Cronometrado.
graph TD
T["⚡ TRIGGER<br/>Nuevo Mensaje en Chat<br/>App: DKV PET<br/>(vía webhook)"]
--> F["🔍 DAPR ACTOR<br/>Actualiza 'LastMessageTime'<br/>(Resetea Timer)"]
F --> W1["⏱️ DAPR TIMER<br/>T=24h Inactividad<br/>(configurable)"]
W1 --> P1["📲 PUSH #1<br/>'Hola {{nombre}}, tu consulta...'"]
P1 --> W2["⏱️ DAPR TIMER<br/>T=48h Inactividad<br/>(configurable)"]
W2 --> P2["📲 PUSH #2<br/>'{{nombre}}, tu conversación se cerrará...'"]
P2 --> W3["⏱️ DAPR TIMER<br/>T=72h Inactividad<br/>(configurable)"]
W3 --> CLOSE["🔒 CERRAR<br/>POST /encounters/{{id}}/close<br/>reason: inactivity_timeout"]
style T fill:#7C3AED,color:#fff
style F fill:#D97706,color:#fff
style W1 fill:#6366f1,color:#fff
style P1 fill:#059669,color:#fff
style W2 fill:#6366f1,color:#fff
style P2 fill:#059669,color:#fff
style W3 fill:#6366f1,color:#fff
style CLOSE fill:#ef4444,color:#fff
La regla de Oro "Zero-Erlang-Touch"¶
Para las colas que queramos dinamizar mediante Pet Flows (ej. Coach, Prevención):
1. Configurar en el admin legacy (PET): max_inactive_patient_warning_time = 0 y close_inactive_encounters = false. (Se desactiva la inactividad nativa).
2. Delegar en Pet Flows: Al recibir cualquier mensaje de paciente vía webhook_new_message_recipients, Dapr registra el tiempo y planifica cronómetros independientes. Si entra un nuevo mensaje, el cronómetro nativo de Dapr se borra/sobrescribe.
Esto nos confiere el 100% del control del flujo (Push #1, Push #2, SMS, etc.) sin inyectar ninguna lógica adicional en netcomp.
Nodos Utilizados (del catálogo)¶
| Nodo | App | Módulo | ¿Existe en MVP Backlog? |
|---|---|---|---|
| Trigger: Inactividad paciente | 🐾 DKV PET | pet-patient-inactive |
❌ Nuevo trigger |
| Filtro por servicio | (edge filter) | Condición en edge | ✅ Ya existe |
| Wait (30/60/120 min) | 🔧 Flow Control | fc-sleep |
✅ Sí |
| Push notification | 📲 Notificaciones | notify-push-rich |
✅ Sí |
| Consultar PET | 🗄️ Datos | data-http |
✅ Sí |
| Cerrar encounter | 🐾 DKV PET | pet-close-encounter |
❌ Nueva acción |
| Log/Analytics | 🗄️ Datos | data-variable |
✅ Sí |
Solo necesitamos 2 módulos nuevos: pet-patient-inactive (trigger) y pet-close-encounter (acción).
6. Configuración de Mensajes por Servicio/Cola/Motivo¶
El requisito dice: "La herramienta permite configurar diferentes mensajes de notificación en función de: Servicio, Cola, Motivo de apertura."
Resolución con Pet Flows¶
En vez de crear un sistema de templates rígido en PET, cada combinación servicio+cola+motivo se resuelve con un flujo distinto o con bifurcaciones dentro del mismo flujo:
Flujo: Dinamización Prevención Flujo: Dinamización Coach
├── Cola: Prevención General ├── Cola: Coach Nutrición
├── Mensaje: "Tu plan de ├── Mensaje: "Tu coach
│ prevención sigue activo..." │ te espera..."
├── Prórroga: 4 horas ├── Prórroga: 24 horas
└── Recordatorios: 2 └── Recordatorios: 3
O (alternativa)
Flujo Único: Dinamización General
├── Trigger: Inactividad paciente
├── Router: ¿Qué tipo de servicio?
│ ├── Rama Prevención → mensajes de prevención
│ ├── Rama Coach → mensajes de coach
│ └── Rama Default → mensajes genéricos
└── Configuración visual, sin código
[!TIP] Ventaja del editor visual: Marketing puede crear/modificar flujos por cola sin pedir deploy a desarrollo. Esto es exactamente lo que el requisito describe como "quick win".
7. Cambios Necesarios en PET Cloud (¡NINGUNO CORE!)¶
Gracias a reorientar la solución a Timers en Dapr (Pet Flows), eludimos el riesgo de tocar el Core de Netcomp en pleno proceso Leader/Follower.
| # | Cambio | Tipo | Esfuerzo |
|---|---|---|---|
| 1 | Solo Configuración: Setear close_inactive_encounters a false en colas específicas. |
Backoffice | 1 SP |
| 2 | En lugar de webhook de inactividad, interceptar el webhook de todos los mensajes (que ya se emite) para registrar inactividad (LastUpdated). | Pet Flows | - |
| 3 | Endpoint REST: POST /api/telemed/v1/encounters/{id}/close invocado por Pet Flows (Actualmente ya debe existir para backoffice/admin). |
Verificación | 2 SP |
[!TIP] Beneficio Colateral: Al no requerir agregar un nuevo webhook al core (Erlang
netcomp), el GoLive de MVP se desliga completamente de presiones del equipo Erlang. Todo el esfuerzo reside en la piezadkv-pet-flowsbajo Quarkus.
8. Comparativa: MVP Backlog vs MVP¶
| Dimensión | MVP Backlog (Encuesta) | MVP (Dinamización) |
|---|---|---|
| Trigger | Caso cerrado (webhook existente) | Inactividad paciente (webhook NUEVO) |
| Acción principal | Push con deep link a encuesta | Push con deep link a retomar conversación |
| Complejidad del flujo | Lineal: trigger → wait → push | Cíclico: trigger → push → check → push → check → close |
| Cambios en PET | Solo configurar URL webhook | Nuevo evento webhook + posible endpoint extend |
| Canales | Push + email fallback | Push (obligatorio, paciente nativo) |
| Nodos nuevos | 0 (todos del catálogo) | 2 (pet-patient-inactive, pet-close-encounter) |
| Reutilización | Base para todo lo demás | Reutiliza 80% de MVP Backlog |
| Valor demostrable | "El sistema envía encuestas" | "El sistema salva conversaciones" → mayor impacto de negocio |
| Riesgo | Bajo (webhook ya existe) | Medio (necesita cambio en PET → GoLive julio) |
9. Estimación de Esfuerzo (Opción B)¶
Si MVP Backlog ya está hecho (incremental)¶
| # | Story | SP | Prioridad |
|---|---|---|---|
| B.1 | Nuevo trigger pet-patient-inactive en Pet Flows |
3 | Must |
| B.2 | Nueva acción pet-close-encounter (POST a PET) |
3 | Must |
| B.3 | Cambio en PET: emitir webhook al alcanzar max_inactive_patient_warning_time |
5 | Must |
| B.4 | Flujo visual: P1 → Wait → Check → P2 → Wait → Close | 5 | Must |
| B.5 | Templates de push personalizados por cola | 3 | Must |
| B.6 | Deep link qcplus://encounter/{id}/resume en app QC+ |
3 | Must |
| B.7 | Verificar: ¿qué hace el warning_time hoy en PET? | 2 | Must |
| B.8 | Router por tipo de servicio (prevención/coach/general) | 3 | Should |
| B.9 | Dashboard: conversaciones en prórroga (SSE) | 5 | Should |
| Total incremental | 32 SP | ~3 semanas |
Si MVP Backlog NO está hecho (desde cero)¶
| Componente | SP |
|---|---|
| MVP Backlog completo | 65 |
| MVP incremental | 32 |
| Total combinado | ~75 SP (comparten ~22 SP de infra) |
| Duración | ~6-7 semanas |
10. Mapeo a Criterios de Aceptación¶
| # | Criterio | ¿Cubierto? | Cómo |
|---|---|---|---|
| 1 | Sistema identifica conversaciones abandonadas en servicios de continuidad | ✅ | Trigger pet-patient-inactive + filtro por component_type |
| 2 | Tiempo de cierre automático se incrementa | ✅ | max_inactive_patient_time configurable por cola |
| 3 | Durante la prórroga se envían push al cliente | ✅ | Nodos Push en flujo visual con Wait entre ellos |
| 4 | Notificaciones configurables por servicio, cola y motivo | ✅ | Router por servicio + templates por cola |
| 5 | Cliente puede retomar desde la notificación | ✅ | Deep link qcplus://encounter/{id}/resume |
| 6 | Si no hay interacción, cierre automático tras prórroga | ✅ | Check + Close al final del flujo |
| 7 | Alcance limitado a dinamización | ✅ | Flujo solo para conversaciones abandonadas |
11. Mapeo a Casos de Prueba¶
| Caso | Flujo Pet Flows | Verificación |
|---|---|---|
| Caso 1: Prórroga | Trigger → Cola prevención con max_inactive_patient_time = 240min |
Config en dkv-pet-admin |
| Caso 2: Push durante prórroga | Wait 30min → Push #1 al paciente | Log en ejecución + entry en Gorush |
| Caso 3: Retoma exitosa | Check: GET /encounters/{id} → status != inactive |
Flujo termina con LOG "resumed" |
| Caso 4: Cierre definitivo | Check: status = inactive → POST /encounters/{id}/close |
Encounter cerrado en PET |
12. Análisis de Riesgos¶
| Riesgo | Probabilidad | Impacto | Mitigación |
|---|---|---|---|
| Cambio en PET durante GoLive | 🔴 Alta | 🔴 Alto | Hacer el cambio SOLO en pet-cloud (no en netcomp). Si pet-cloud es follower, el webhook se activa solo cuando sea leader |
max_inactive_patient_warning_time no dispara nada hoy |
🟡 Media | 🟡 Medio | Spike: verificar código Java. Si no dispara, hay que añadir el listener |
| Deep link roto en app QC+ | 🟡 Media | 🟡 Medio | Verificar con equipo mobile. Schema qcplus:// debe estar registrado |
| Push no llega (token expirado) | 🟡 Media | 🟡 Medio | Fallback: ni email ni SMS — si push falla, se cierra sin notificación (aceptable para MVP Backlog) |
| Volumen alto de conversaciones abandonadas | 🟡 Media | 🟡 Medio | Dapr maneja volumen. Rate limiter en flujo |
13. Recomendación Estratégica¶
[!IMPORTANT] MVP tiene mayor impacto de negocio que MVP Backlog ("salvar conversaciones" > "enviar encuestas"). Pero MVP Backlog es la base técnica que MVP necesita.
Orden Recomendado¶
Opción 1 (Secuencial): MVP Backlog (5 sem) → MVP (3 sem) = 8 semanas
Opción 2 (Entrelazada): MVP Backlog+2 combinados (6-7 sem) = ganamos 1-2 semanas
La Opción 2 es factible porque MVP Backlog y MVP comparten:
• Motor de ejecución Dapr
• Webhook ingress
• Push via dkv-notifications/Gorush
• Store + serialización
• Wait/Timer activities
Sprint Plan Combinado (Opción 2)¶
| Sprint | Semanas | Entregable |
|---|---|---|
| Sprint 1 | 1-2 | Fundaciones: API, Store, Webhook ingress, Dapr MVP Backlog |
| Sprint 2 | 3-4 | MVP Backlog: Flujo encuesta E2E + Spike warning_time PET |
| Sprint 3 | 5-6 | MVP: Trigger inactividad + Flujo dinamización + Templates push |
| Sprint 4 | 7 | Polish: Dashboard prórroga + deep links + demo |
| Total | 7 sem | Ambos MVPs operativos |
Documentos Relacionados¶
| Documento | Propósito |
|---|---|
| 04 — Anatomía MVP Backlog | Flujo encuesta (nodo a nodo) |
| 03 — PET como App | Catálogo de módulos |
| aux_03 — Netcomp Webhooks | Webhooks y Leader/Follower |
| 05 — Direcciones Estratégicas | Sprint plan original |