feat(alta): guardado progresivo por etapa con réplica a Monday

- Al avanzar cada paso del wizard: upsert silencioso del borrador local
  + sync a Monday (iniciar → Contacto en PROSPECTO; pasos siguientes →
  PATCH con los campos mapeables: datos generales, dirección armada,
  actividad económica)
- Al completar: Contacto pasa a CLIENTE + Apartado + funnel (dedup)
- progresoId viaja con el borrador (se restaura solo); fallos de sync
  no bloquean el avance (aviso ámbar no bloqueante); submit final con
  fallback al endpoint legado si nunca hubo sync
- API: POST /clientes/progreso/iniciar, PATCH /clientes/progreso/:id,
  POST /clientes/progreso/:id/completar; POST /clientes legado intacto
- Tests: API 338 (+16), alta-clientes 112 (+4); smoke en vivo
  verificado (PROSPECTO → patch → CLIENTE + Apartado) y limpiado
This commit is contained in:
2026-09-01 21:03:47 +00:00
parent cd93aec91d
commit ccd4ca78ca
11 changed files with 876 additions and 40 deletions

View File

@@ -10,7 +10,10 @@ import {
obtenerCotizacionPublica,
} from '../controllers/cotizaciones.controller.js'
import {
actualizarProgreso,
completarProgreso,
crearCliente,
iniciarProgreso,
listarDocumentos,
obtenerCliente,
subirDocumentos,
@@ -90,6 +93,11 @@ apiRouter.get('/cotizaciones/:id/publico', obtenerCotizacionPublica)
apiRouter.get('/cotizaciones/:id', obtenerCotizacion)
apiRouter.post('/clientes', crearCliente)
// Alta progresiva: guardado etapa por etapa del wizard (Contacto PROSPECTO → CLIENTE).
// Van ANTES de /clientes/:id para no colisionar con el parámetro.
apiRouter.post('/clientes/progreso/iniciar', iniciarProgreso)
apiRouter.patch('/clientes/progreso/:id', actualizarProgreso)
apiRouter.post('/clientes/progreso/:id/completar', completarProgreso)
// Liga remota: endpoints públicos con token propio (scope 'firma-remota'); el
// scope se verifica dentro de cada controlador. Van ANTES de /clientes/:id.
apiRouter.get('/clientes/publico/:token', limitadorLiga, obtenerClientePublico)