Skip to content
Usuario

Commercial Actions

Automatizacion controlada

Alertas MedSync y jobs

Alertas MedSync

  • alerts.expiredTrials: trials ya vencidos.
  • alerts.trialsExpiringNext7Days: trials por vencer.
  • alerts.suspendedBusinesses: negocios suspendidos.
  • alerts.pastDueBusinesses: negocios con pago pendiente.
  • alerts.cancelledBusinesses: negocios cancelados.

Jobs MedSync

El dashboard consulta el estado de automatizacion y permite un dry-run seguro. Por defecto los jobs estan apagados y no modifican negocios sin variables explicitas.

ConfiguracionVariableModifica BD?Uso recomendado
Jobs apagadosSAAS_JOBS_ENABLED=falseNoProduccion inicial.
Trial job apagadoSAAS_TRIAL_EXPIRATION_JOB_ENABLED=falseNoEvita cambios automaticos.
Modo alertaSAAS_TRIAL_EXPIRATION_JOB_MODE=alert_onlyNoMonitoreo seguro.
Marcar pago pendienteSAAS_TRIAL_EXPIRATION_JOB_MODE=mark_past_dueSi, solo si jobs estan habilitadosUsar con control explicito.
Dry-rundryRun=trueNoPruebas seguras desde Super Admin.

Job existente actualmente

El backend tiene un job MedSync real: saas_trial_lifecycle. Su objetivo es revisar el ciclo de vida de negocios en trial, detectar trials vencidos, detectar trials por vencer y, solo si la configuracion lo permite, convertir trials vencidos a past_due.

No hay otros jobs MedSync productivos documentados en el codigo actual. Pagos, notificaciones externas, emails, WhatsApp, facturacion y licencias avanzadas quedan fuera de este job.

Que hace el boton dry-run

El boton del dashboard ejecuta el endpoint POST /api/super-admin/jobs/saas/trial-lifecycle/run enviando { dryRun: true }. Eso obliga al backend a simular la ejecucion sin actualizar negocios, aunque el servidor tenga jobs habilitados.

El resultado sirve para responder: cuantos trials estan vencidos, cuantos estan por vencer, que negocios entran en cada grupo y si la configuracion actual permitiria mutar datos en una ejecucion real.

Mapa actual de jobs MedSync

Para evitar confusion: en el codigo actual solo existe un job MedSync implementado. Las otras cards muestran automatizaciones naturales del roadmap, pero no existen todavia como jobs productivos.

saas_trial_lifecycle

Estado: implementado.

Detecta trials vencidos y trials por vencer. Puede convertir trials vencidos a past_due solo con configuracion explicita.

saas_payment_reconciliation

Estado: no implementado.

Seria el job futuro para conciliacion de pagos o facturacion. No existe en el backend actual y no se ejecuta.

saas_external_notifications

Estado: no implementado.

Seria el job futuro para avisos por email, WhatsApp o SMS. No existe actualmente y no envia notificaciones.

Endpoints operativos de jobs MedSync

EndpointMetodoUso en dashboardModifica datos?Proteccion
/api/super-admin/jobs/saas/statusGETCargar estado de automatizacion, modo y conteos.No.Token.Auth + requireRole(‘super_admin’)
/api/super-admin/jobs/saas/trial-lifecycle/runPOSTEjecutar dry-run desde el boton del dashboard.No, si dryRun=true.Token.Auth + requireRole(‘super_admin’)

Variables para habilitar o deshabilitar jobs

La configuracion vive en src/config/saasJobs.js. Si una variable viene ausente, invalida o fuera de rango, el codigo cae a defaults seguros.

VariableDefault seguroQue controlaPara habilitar cambios reales
SAAS_JOBS_ENABLEDfalseInterruptor global de jobs MedSync.Debe estar en true.
SAAS_TRIAL_EXPIRATION_JOB_ENABLEDfalseInterruptor especifico del job de trials.Debe estar en true.
SAAS_TRIAL_EXPIRATION_JOB_MODEalert_onlyDefine si solo detecta o tambien convierte a past_due.Debe ser mark_past_due.
SAAS_TRIAL_EXPIRING_SOON_DAYS7Ventana para trials por vencer.No habilita cambios; solo cambia la ventana de alerta.

Condicion exacta para que una ejecucion real pueda modificar negocios: SAAS_JOBS_ENABLED=true, SAAS_TRIAL_EXPIRATION_JOB_ENABLED=true, SAAS_TRIAL_EXPIRATION_JOB_MODE=mark_past_due y request con dryRun=false.

# Configuracion recomendada para produccion inicial: observar sin mutar
SAAS_JOBS_ENABLED=false
SAAS_TRIAL_EXPIRATION_JOB_ENABLED=false
SAAS_TRIAL_EXPIRATION_JOB_MODE=alert_only
SAAS_TRIAL_EXPIRING_SOON_DAYS=7

# Configuracion que permite cambios reales, solo con control explicito
SAAS_JOBS_ENABLED=true
SAAS_TRIAL_EXPIRATION_JOB_ENABLED=true
SAAS_TRIAL_EXPIRATION_JOB_MODE=mark_past_due
SAAS_TRIAL_EXPIRING_SOON_DAYS=7

Respuesta del dry-run: como leerla

CampoSignificadoUso operativo
dryRunConfirma si la ejecucion fue simulada.Debe ser true desde el boton del dashboard.
expiredTrialsCantidad de trials vencidos encontrados.Indica negocios que ya no deberian operar como trial vigente.
trialsExpiringSoonCantidad de trials que vencen dentro de la ventana configurada.Sirve para seguimiento comercial preventivo.
updatedBusinessesCantidad de negocios actualizados.En dry-run debe ser 0.
canMutateIndica si la configuracion permitiria cambios reales.Ayuda a detectar si el servidor esta armado para mark_past_due.
blockedReasonExplica por que una ejecucion real no podria modificar negocios.Util para diagnosticar variables apagadas o modo incorrecto.
expiredTrialBusinessesPrimeros negocios vencidos, compactados.Permite revisar candidatos sin exponer datos clinicos.
updatedBusinessIdsIDs actualizados en una corrida real.En dry-run debe venir vacio.

Flujo: consulta de status

  1. Dashboard carga fetchSaasJobsStatus().
  2. Servicio llama GET /api/super-admin/jobs/saas/status.
  3. Backend valida token y rol Super Admin.
  4. DAO llama getTrialLifecycleStatus().
  5. El job corre en modo lectura con dryRun=true.
  6. Devuelve configuracion, trials vencidos y trials por vencer.

Flujo: boton dry-run

  1. Usuario pulsa ejecutar validacion dry-run.
  2. Frontend envia { dryRun: true }.
  3. Backend calcula snapshot de trials.
  4. No ejecuta UPDATE.
  5. No crea auditoria de cambio real.
  6. Frontend muestra vencidos, por vencer, actualizados y bloqueo si aplica.

Flujo completo del job

flowchart TD
A[Inicio saas_trial_lifecycle] --> B[Leer saasJobs config]
B --> C[Consultar trials vencidos]
B --> D[Consultar trials por vencer]
C --> E{dryRun es false?}
D --> R[Armar resumen]
E -- No --> R
E -- Si --> F{canMutateTrials?}
F -- No --> G[No modificar y devolver blockedReason]
F -- Si --> H[UPDATE business a past_due]
H --> I[Insertar auditoria SUPER_ADMIN_TRIAL_EXPIRED_TO_PAST_DUE]
I --> R
G --> R
R --> Z[Respuesta controlada al dashboard]

SQL real del snapshot

Estas consultas leen solo la tabla business. No consultan pacientes, expedientes, recetas, citas, documentos clinicos, tratamientos ni odontograma.

-- Trials vencidos
SELECT id_business, name, subscription_status, plan, trial_ends_at
FROM business
WHERE subscription_status = 'trial'
 AND active = 1
 AND trial_ends_at IS NOT NULL
 AND trial_ends_at < NOW()
ORDER BY trial_ends_at ASC;

-- Trials por vencer
SELECT id_business, name, subscription_status, plan, trial_ends_at
FROM business
WHERE subscription_status = 'trial'
 AND active = 1
 AND trial_ends_at IS NOT NULL
 AND trial_ends_at >= NOW()
 AND trial_ends_at <= DATE_ADD(NOW(), INTERVAL :days DAY)
ORDER BY trial_ends_at ASC;

SQL real cuando se permite modificar

Este UPDATE solo ocurre si dryRun=false y canMutateTrials() devuelve verdadero. No cambia active, status, plan, fechas de trial, usuarios ni datos clinicos.

UPDATE business
 SET subscription_status = 'past_due',
     status_reason = 'Trial vencido automaticamente',
     updated_at = NOW(),
     updated_by = 'saas_job'
WHERE id_business = :business_id
 AND subscription_status = 'trial'
 AND trial_ends_at IS NOT NULL
 AND trial_ends_at < NOW();

Auditoria generada por cambio real

Si un trial vencido cambia realmente a past_due, el job registra SUPER_ADMIN_TRIAL_EXPIRED_TO_PAST_DUE en admin_audit_log con actor tecnico system y rol saas_job.

{
"business_id": "...",
"previous_subscription_status": "trial",
"new_subscription_status": "past_due",
"trial_ends_at": "...",
"job": "saas_trial_lifecycle",
"mode": "mark_past_due"
}

La metadata no debe incluir passwords, hashes, tokens, refresh tokens, secrets, credenciales ni datos clinicos.

Que ejecuta en arranque del backend

La funcion startSaasTrialLifecycleJob() revisa la configuracion. Si los jobs estan apagados, escribe un log operativo y no programa nada. Si estan activos, ejecuta una primera corrida y despues agenda una ejecucion cada 24 horas con setInterval.

EstadoComportamientoRiesgo
Jobs apagadosNo agenda ejecuciones automaticas.Bajo; requiere operacion manual.
alert_onlyDetecta y reporta, pero no actualiza negocios.Bajo; util para monitoreo.
mark_past_dueConvierte trials vencidos a pago pendiente.Medio; requiere configuracion explicita y supervision.

Modelo MedSync

Reglas de negocio

Separacion clave

business.active es estado tecnico. business.subscription_status es estado comercial MedSync. El dashboard observa y resume; las acciones comerciales se ejecutan desde Negocios.

trial vigente

Opera hasta trial_ends_at. Requiere seguimiento comercial.

active

Cliente activo comercial. Tenant opera si active = 1.

past_due

Pago pendiente. Por regla actual, bloquea tenant.

suspended

Bloqueo comercial temporal. No elimina datos.

cancelled

Cancelacion comercial. No elimina negocio ni datos.

active = 0

Apagado tecnico. Bloquea tenant aunque la suscripcion sea valida.

PlanCodigoCapacidad basePacientes
Individualbasic1 profesional + 1 auxiliarIlimitados con uso razonable
Profesionalpro1 profesional + 3 auxiliaresIlimitados con uso razonable
Clinicaenterprise3 profesionales + 8 auxiliaresIlimitados con uso razonable

Uso diario

Casos operativos

Caso 1: Trial por vencer

Que ve: alerta de trials por vencer en 7 dias.

Accion: revisar negocio y decidir extender trial o activar.

Donde: ir a /super-admin/businesses.

Caso 2: Trial vencido

Que ve: card y alerta de trials vencidos.

Impacto: tenant bloqueado con TRIAL_EXPIRED.

Accion: activar, extender o marcar seguimiento comercial.

Caso 3: Cliente suspendido

Que ve: suspendidos MedSync.

No hacer: no borrar negocio ni usuarios.

Accion: revisar auditoria y reactivar si corresponde.

Caso 4: Jobs apagados

Que ve: automatizacion inactiva.

Por que: es normal en produccion inicial.

Accion: usar dry-run para validar conteos.

Caso 5: Dashboard en ceros

Causas: filtros, rango, backend apagado o token invalido.

Accion: limpiar filtros y revisar Network.

Caso 6: Pago pendiente

Que significa: past_due.

Impacto: tenant bloqueado por regla actual.

Accion: resolver pago o reactivar desde Negocios.