- Mis leads: botón 'Agendo →' convierte el lead en oportunidad (etapa
Agendo Cita, con sus datos, asesor = vendedor del lead o quien
convierte), marca el lead Calificado y guarda el mapping
LeadOportunidad; 409 si ya fue convertido
- Mis oportunidades: se quitan No Asistio y Abandono (redundantes con
Descartar); quedan Cotizar, Afluencia, Agendo Cita y Aparto
- Mis apartados: 'Firma cliente (venta) →' abre el alta de cliente con
TODO lo recolectado prellenado (ficha del apartado + contacto +
oportunidad + cotización vinculada vía GET /altas/prefill-apartado/:id)
- El alta con apartadoMondayId se LIGA al apartado existente y lo
enriquece (curp, teléfono, email, precio final, enganche, forma de
pago, unidad) en vez de crear un duplicado
- monday.service: actualizarApartado + ApartadoMonday con curp, forma de
pago, enganche y monto apartado
- Tests: 470 API + 120 alta-clientes + 16 mi-dia, verde
- GET /api/contactos/:id/detalle: todas las columnas del contacto, la
propiedad comprada/en proceso (apartado relacionado por teléfono/email,
enriquecido con el desarrollo de la unidad), quién atiende cada item
relacionado (leads/oportunidades/apartados, columna people) y el
historial completo de atención (activity log de los 4 tableros +
capturas y alta local con nombre del capturista)
- monday.service: getContactoDetalle (columnas por título),
getHistorialItems (todos los eventos del activity log por items) y
ApartadoMonday enriquecido (teléfono, email, precio final, fecha compra)
- Landing: la lista de Contactos abre un modal por cliente con datos,
propiedad, relaciones CRM (con quién atiende) y timeline de historial
- Tests: 465 API + 12 landing, verde
- Mis leads: botón Interesado (label sembrado en Monday, mueve a Leads
Progreso); el botón Agenda cita ahora solo vive en Mis oportunidades
- Descarte: además de la categoría, subcategoría del catálogo de Monday
(workspace de referencia CRM FRASA); se guarda en la columna
Subcategoria del tablero Motivos No Compra y el item queda en el grupo
de su categoría
- Teléfonos con selector de lada 🇲🇽 +52 / 🇺🇸 +1 en captura rápida (Mi
día), Alta Afluencia y Alta de Cliente (tel. casa y celular); Monday
escribe countryShortName MX/US y el número compacto (rechaza espacios);
el dedup sigue comparando por los últimos 10 dígitos
- Origen nuevo en captura rápida y afluencia: PASE, PROSPECCION ASESOR,
ACTIVACION, FACEBOOK FRASA, REFERIDO, OTRO (sembrados en Leads.Origen y
Oportunidades.Origen del Lead)
- Tests: 461 API + 16 mi-dia + 116 alta-clientes, verde
- Mis oportunidades: 'Afluencia →' navega a /client/?afluencia=<id> con
nombre, contacto, desarrollo y modelo prellenados
- Alta Afluencia: con oportunidadId el envío ACTUALIZA la oportunidad en
Monday (perfil completo + etapa Afluencia) en vez de crear duplicado;
sin oportunidadId el flujo de captura nueva no cambia
- monday.service: actualizarOportunidadAfluencia (mismo builder de la
creación + name); moverAGrupoSegunEstado tras actualizar
- Tests: 457 API + 16 mi-dia + 116 alta-clientes, verde
- Resumen Mi día: misOportunidades.items (lista de trabajo con perfil y
último cambio) y misApartados (Vendedor = yo, estados no finales)
- Nuevos endpoints: POST /oportunidades/:id/etapa (Agendo Cita, Afluencia,
Cotizador, Aparto, No Asistio, Abandono; con fecha de cita) y
POST /apartados/:id/estado (pipeline Enkontrol: Pago Apartado →
Firma Cliente (Venta) / Cancelacion Apartado); ambos mueven el item al
grupo Monday correspondiente
- Mi día: tabs Mis leads / Mis oportunidades / Mis apartados; botón
Cotizar abre /quote con el cliente prellenado y la oportunidad ligada
- Cotizador: prefill desde query params (cliente, teléfono, email,
desarrollo, unidad) y envío de oportunidadId; al guardar, el API
actualiza ESE item (Precio final, Tipo propuesta, etapa Cotizador)
en vez de buscar por teléfono o crear duplicado
- grupos-estado: 'Cancelacion Apartado' → Historico
- Estados finales de apartado: agrega Firma Cliente (Venta) y
Cancelacion Apartado
- Tests: 455 API + 14 mi-dia + 88 cotizador, todo en verde
- Matriz de roles (vendedor, administracion_venta, director_ventas,
escrituracion, direccion_general, admin) con modulos visibles por rol;
auth/me y login incluyen 'modulos'; PATCH /usuarios/:id/rol (admin).
- Landing: Cobranza -> Clientes, Chat IA -> Chat Hermes, nuevo modulo
Contactos (vista interna leyendo el tablero Contactos), grid filtrado
por rol, rol visible en Configuracion de cuenta.
- Dashboards: tab 'Tablero comercial' y tabs filtrados por rol.
- Boton '<- Menu' en el header de todas las apps.
- Mi dia: cada lead muestra el ultimo cambio (que, quien, cuando) desde
el activity log de Monday (normalizacion de created_at 100ns/us/ms).
- Descarte: el motivo se crea en el grupo de su categoria en el tablero
Motivos No Compra.
- El alta (directa y progresiva) llena el Apartado con telefono, correo,
curp, Precio Final, Enganche, Fecha Compra, Vendedor (el capturista
con Monday vinculado) y Forma de Pago; el path webhook/cron hereda
contacto, precio y asesor de la oportunidad.
- Bidireccional: Mis clientes en /hoy muestra el estado actual del
Apartado leyendolo de Monday (si lo mueven en Monday, la app lo
refleja en el siguiente refresh).
- getApartados con la correccion value-null al leer Estado.
- Test del mapa de Tipo propuesta del cotizador (los 502 del log eran
de un proceso previo al fix 4f31d1c; queda cubierto).
- POST /api/leads: captura ligera al tablero Leads (sin oportunidad),
self-assign a Vendedor o round-robin; tambien cubre la captura manual
desde la UI de Monday (webhook create_item re-registrado).
- POST /api/afluencias (nuevo): la forma completa sigue cayendo en
Oportunidades con todo el perfil (etapa Afluencia, columna Asesor).
- Round-robin dual (ambos tableros), Mi dia mezcla leads+oportunidades
con insignia de origen, acciones con parametro fuente, reportes:
leads desde Leads, perfilamiento desde Oportunidades, funnel
Leads->Afluencia->...->Ganado.
- POST /api/leads crea UN solo item en Oportunidades (Estado Afluencia)
con todo el perfil (desarrollo, modelo, estado civil, credito, etc.)
en las columnas del board; dedup por telefono contra Oportunidades;
asignacion al capturista via columna Asesor o round-robin del equipo.
- Round-robin, escalado e inactividad operan sobre Oportunidades (solo
etapa Afluencia sin asesor entra al reparto).
- Acciones del vendedor (contactado/cita/descartar) escriben directo en
la oportunidad; descarte = Perdido + Motivo No Compra.
- Mi dia y reportes leen Oportunidades; el funnel de /dash arranca en
Afluencia; misOportunidades.porEtapa ya es real (columna Asesor).
- El picker del alta busca en Leads (historico) Y Oportunidades, con
insignia de origen; moverAAparto tolera ambos ids.
- Lectura de status con value null = vacio (quirk del default Monday).
- Script de migracion del historial de agosto Leads -> Oportunidades.
- obtenerVendedores ahora lee el team de Monday (MONDAY_RR_TEAM,
default 'vendedores') con cache de 1 h; MONDAY_RR_USER_IDS queda como
override manual.
- Escrituras a columnas status resuelven el label real sin importar
mayusculas: si renombran labels en la UI de Monday (paso con
NUEVO→Nuevo) el API sigue escribiendo en vez de tronar con 502.
- mapearLead: un status nunca escrito (value null) se lee como vacio;
Monday regresaba el label default del tablero como texto y el
round-robin creia que el lead estaba descartado.
Webhook change_column_value en los 5 tableros (Leads, Oportunidades,
Unidades, Apartado, Contactos) + mapeo central estado->grupo: el API
re-consulta el item y lo mueve con move_item_to_group (idempotente).
El funnel mueve la oportunidad de Afluencia al crearla (Monday la crea
en el grupo top del board). Incluye script de backfill one-off
(249 items reubicados) y tests del mapeo y del webhook.
- Cliente.capturadoPorId: el alta (directa y progresiva) registra al
usuario que la inicio; el panel Mi dia muestra 'Mis clientes' con su
estado (En captura / Cliente) sin depender de Monday.
- LeadMonday ahora lee las 11 columnas de perfil del tablero Leads
(estado civil, edad, rango salarial, tipo de empleo/economia,
califica, credito, modelo, etc.).
- GET /api/reportes/resumen agrega leads.perfil con conteos por
dimension (valores vacios se omiten; edad en buckets).
- /dash/ gana la seccion 'Perfilamiento de la afluencia' con
mini-graficas de barras por dimension.
'Al departamento o casa de interes' ahora es un select dependiente:
al elegir desarrollo se cargan sus modelos (MODELOS_POR_PROYECTO) y al
cambiar de desarrollo se resetea. En Monday la columna 'Tipo de
Propiedad' se renombro a 'Modelo de Interes' con los 16 modelos como
labels del status.
Agrega al formulario ligero y a POST /api/leads: tipo de propiedad,
medio de contacto, edad, estado civil, tipo de empleo, ocupacion,
rango salarial, credito, tipo de economia, califica y lo quiere para.
Selects obligatorios (estado civil, tipo de empleo, tipo de economia,
califica) con las etiquetas sembradas como labels status en el tablero
Leads de 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
- Captura rápida crea lead + oportunidad en etapa Afluencia (vinculadas
por nueva tabla LeadOportunidad); también aplica a leads creados
directo en Monday vía webhook
- Transiciones automáticas: AGENDA CITA → Agendo Cita, descarte →
Perdido (+ dropdown Motivo No Compra), cotización con mismo teléfono
ACTUALIZA la oportunidad (no duplica) → Cotizador, alta de cliente
con leadMondayId → Aparto (dedup previo para no duplicar Apartado)
- Columna Desarrollo agregada al board Oportunidades (color_mm6sa20t)
- Migración lead_oportunidad aplicada con migrate diff + resolve (la DB
tiene drift histórico por db push; migrate dev pedía reset)
- Tests: 322 verdes; smoke en vivo verificado y limpiado
- Columna 'Desarrollo' (status, 5 labels) creada en el board Leads de
Monday (color_mm6sw4c2)
- API: crearLead acepta email y desarrollo; el desarrollo se valida
contra los labels reales de la columna (mismo patrón que Origen)
- Mi día: formulario de captura con campos Email y Desarrollo de interés
(select con los 5 desarrollos, opcional)
- Tests: api 296, mi-dia 12
- App Mi día: KPIs, mis actividades, mis leads con acciones rápidas
(contactado/intento/agenda cita/descartar con motivo), captura rápida
de lead (409 en duplicado por teléfono), vista equipo para coordinadores
- API: GET /api/mi-dia/resumen, POST /api/leads, /leads/:id/estado,
/leads/:id/descartar; mapeo Usuario.mondayUserId (seed listo para
cuando inviten a los vendedores a Monday)
- Landing: tarjeta Mi día; tests api 188, mi-dia 8, landing 4
- Escalado: lead asignado sin contactar >48h genera actividad URGENTE
al coordinador (LEAD_ESCALADO_HORAS, MONDAY_COORDINADOR_USER_ID)
- Oportunidad en Aparto crea item en Apartado (fecha límite +7d);
en Ganado crea la Venta; ambos con dedup
- GET /api/reportes/resumen: leads, funnel, unidades por desarrollo,
cobranza y actividades en una respuesta (cache 60s)
- App dashboards (/dash): 8 KPIs + 3 gráficas Recharts, con auth
- Landing: tarjeta Tableros; docs/AUTOMATIZACIONES-MONDAY.md con las
recetas nativas para activar en la UI
- Tests: api 158, dashboards 7, landing 5 — todo verde
- Vocabulario funnel: labels Intento de contacto/Abandono en Leads,
etapas completas en Oportunidades (Cotizador, Ganado, Perdido...)
- Apartados: pipeline Enkontrol (8 estados) + checkboxes CURP/RFC/Comprobante
que la app de alta prende al subir documentos
- Motivos No Compra: board catálogo + dropdown + endpoint /oportunidades/:id/perder
- Perfil demográfico en Contactos mapeado desde el alta (estado civil,
vivienda, propósito, fecha nac., rango de edad calculado)
- Desarrollos: catálogo maestro sincronizado (precios, m2, tipo, entrega)
- Actividades: board nuevo + creación automática en round-robin e inactividad
- Cobranza: plan liquidado mueve el apartado a 'X Escriturar' en Monday
- Scripts: setup:crm y sync:desarrollos (idempotentes)
- Tests 119/119 verdes
- Motor de cálculo parametrizado por desarrollo (enganches, descuentos, splits,
fuente de N, quirk Infonavit-lista); DIAGONAL byte-idéntico
- 285 unidades (5 desarrollos) en seeds, API (?desarrollo=) y board Monday
- Selector de desarrollo en UI, propuestas por config, PDF multi-desarrollo
- Knowledge IA: catálogo por desarrollo + matriz de diferencias (10 docs)
- Tests: cotizador 53, api 99 — fixtures de los Excel validados al centavo
- Servicio de automatizaciones con estado persistido en SQLite (índice RR, dedup de recordatorios)
- Webhook Monday procesa create_item del board Leads y asigna vendedor
- Crons: polling cada 5 min (respaldo sin webhook público) + escaneo diario 9am
- Endpoints admin: /api/automatizaciones/estado, /round-robin/run, /inactividad/preview
- 15 tests nuevos (70/70 verdes)
- api-gateway: servicio Monday (retry 429/complejidad, paginacion cursor,
column IDs por titulo), endpoints unidades/cotizaciones/clientes/planes,
webhook con handshake challenge, Prisma SQLite dev, 55 tests
- cotizador: inventario desde /api/unidades con fallback a seed
- alta-clientes: POST /api/clientes + upload multipart de documentos
- cobranza: persistencia via API con respaldo offline en localStorage
- .env.example con board IDs del workspace Frasa-CAS