- 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
- Mis apartados (Mi día): botón Documentos con precarga del expediente —
captura del cotizador y captura de pago apartado (obligatorios) más
documentos generales; los archivos se guardan en el cliente ligado al
apartado (se crea la ficha mínima si no existe). Endpoints
GET/POST /apartados/:id/documentos (multipart, 10 MB, pdf/jpg/png)
- Cotizador: se oculta el editor de descuento (usan los % del Excel);
enganche seleccionable con mínimo 2.5% del valor de la propiedad, solo
en esquemas con crédito (bancario/Infonavit); mensualidades se
recalculan con el enganche elegido y nunca quedan en negativo
- Cotizador: buscador de cliente en Monday (lead u oportunidad) que
prellena nombre/contacto/desarrollo y vincula la cotización a la
oportunidad al guardar
- Alta Afluencia: buscador que jala nombre, contacto, origen, desarrollo
y modelo desde leads y oportunidades existentes
- buscarLeads devuelve desarrollo y modelo de interés
- Landing: el módulo Clientes vuelve a llamarse Cobranza
- Tests: 456 API + 94 cotizador + 14 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.
POST /api/leads con sesion y Monday vinculado asigna el lead a quien lo
registro (mas su actividad de contacto) en vez del round-robin; sin
vinculo o sin token sigue el reparto. Bandera rr:skip para que el
webhook create_item no pise la asignacion durante la propagacion de
Monday (la carrera se observo en el smoke). Mensajes de exito en
/hoy y /client reflejan a quien quedo asignado.
Headers sticky con marca y acciones, contenedores max-w-[1280px],
grids de contenido con rails laterales sticky (cotizador, mi-dia,
detalle de cobranza), stepper vertical en el wizard de alta, toolbar+
tabla unificadas en cobranza, tabs como segmented control en
dashboards, chat con barra de entrada fija y preguntas sugeridas,
landing con navbar + hero + grid de modulos + footer.
Del look editorial (verde #1B4332, esquinas a 0, botones en mayusculas)
al sistema NovaSpark: primario azul #2563EB, detalle naranja #F97316,
fondo #F8FAFC con tarjetas blancas rounded-xl + shadow-sm, chips
rounded-full semanticos, focus ring azul, transiciones 100-200ms.
Incluye headers de tabla en los PDFs (cotizador y estado de cuenta).
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.
Nueva GUIA-FLUJO-COMPLETO.md (mapa del embudo + paso a paso para
Ventas, Coordinacion, Administracion, Cobranza, Escrituracion, SAC,
DG/Obra y Agente IA, con tabla de que se ve en Monday en cada momento).
GUION-DEMO actualizado con captura completa de afluencia, Mis capturas,
Mis clientes y perfilamiento.
- bucketSalario: el texto libre del rango salarial ('$80k', '4,500 DLLS',
'50-80 MIL') se agrupa en rangos por moneda para que la grafica sea
legible; valores sin monto se omiten.
- scripts/importar-afluencia-agosto.py: importa el historial de
afluencia al tablero Leads con normalizacion de catalogos, dedup por
telefono y desregistro temporal del webhook create_item (para no
disparar round-robin ni oportunidades con datos historicos).
- 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.
Nueva tabla LeadCaptura (quien capturo cada lead, algo que Monday no
guarda porque el creador del item siempre es el token del API). El
POST /api/leads la registra con el usuario del token y el resumen de
Mi dia la enriquece con el estado/origen actual del lead en Monday.
La captura rapida refresca el panel al registrar.
'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.
- Nueva columna status 'Desarrollo' (color_mm6s39s9) con los 5 labels;
migrados los 288 valores desde la columna texto (text_mm6ehqqb,
eliminada)
- sync-estatus-maestro.py y sync-obra-estatus.py reapuntados al nuevo
column id; el API lee por título y quedó verificado (288 unidades,
misma distribución por desarrollo)
- Columnas y grupos agregados en los 9 tableros existentes segun el
workspace viejo (sin tocar columnas/labels que usan las
automatizaciones; solo se agrego)
- Tableros nuevos en carpeta Ventas: Cobranza (18429260549) y
Seguimiento Preventa (18429260580), replicas de los originales
- Pendientes manuales documentados: orden de columnas, vistas,
labels de dropdowns existentes y relaciones/mirror
Sin headers, el navegador cacheaba el HTML de entrada y los deploys
nuevos no se veían hasta limpiar caché (el caso del botón de Alta
Afluencia). Los assets de Vite llevan hash y no se afectan.
- Script sync-obra-estatus.py (idempotente, --dry-run, retry/backoff):
parsea ESTATUS OBRA, SENDA-ACT-AGO2026, SENDA/SOLE DG, Diagonal 38 y
las hojas de ventas; mapea a Unidades vía maestro-unidades.json
- Board Unidades: +12 columnas (% avance obra, meses atraso, contratista,
clave catastral, no. oficial, vendedor, broker, venc. autorización,
fecha entrega obra, 4 checkboxes de hitos documentales) — 147 items
actualizados (DIAGONAL 38/38, SENDA 109/142)
- Board nuevo 'Flujo Escrituras' (18429252054): 32 items mayo–ago/2026
por proyecto/semana con escrituras e ingreso
- Board nuevo 'Saldos a Favor' (18429252069): 7 pendientes (Estanza/Sole)
- Receta nativa documentada: recordatorio 7 días antes de Venc.
autorización al coordinador
- SOLE y MUTUO no existen como inventario en Monday: sus datos de obra
se reportan como saltados (no se crean unidades)
- 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
Tras registrar la afluencia, la pantalla de éxito ofrece 'Pasar a Alta
de Cliente': abre el wizard prellenado con los datos recién capturados
(nombre, email, celular) y el leadMondayId ya ligado, sin rebuscar el
lead. Quedan también 'Capturar otro' y 'Volver'.
- Nueva pantalla de entrada en /client con dos opciones:
· Alta Afluencia: captura ligera (nombre, teléfono, email, origen,
desarrollo de interés, notas) → POST /api/leads (lead + oportunidad
Afluencia + round-robin, todo ya existente en el API)
· Alta de Cliente: formato completo actual (picker + wizard intactos)
- Manejo de duplicado por teléfono (409 con nombre del lead existente)
- ?cotizacion=<id> sigue saltando directo al wizard
- Tests: 107 verdes (11 nuevos); smoke en vivo OK y limpio
- 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
API:
- GET /api/monday/usuarios: usuarios activos no-guest del workspace
- PATCH /api/usuarios/me/monday: vincula/desvincula el mondayUserId del
usuario autenticado (valida contra el workspace)
- GET /api/leads/buscar?q=: búsqueda de leads por nombre/teléfono/email
(sin acentos, orden updatedAt desc, límite 15)
- aPublico/me ahora incluyen mondayUserId
Landing (/):
- Nueva sección 'Configuración de cuenta': login inline, selector del
usuario de Monday, guardar/desvincular, cerrar sesión
Alta de clientes (/client):
- Búsqueda de leads de Monday con debounce en la pantalla de entrada;
al elegir uno prellena nombre/email/celular y guarda leadMondayId
- El picker (borradores + alta nueva + búsqueda de lead) es ahora
siempre la pantalla de entrada
Tests: api 294, landing 8, alta-clientes 96 — todos verdes
- Webhook Oportunidades: cambio de etapa dispara escaneo (Aparto→Apartado,
Ganado→Venta) además del round-robin de leads por create_item
- Acepta los nombres reales de los eventos de Monday: create_pulse/pulseId
y update_column_value (verificados en vivo)
- Token interno (X-Internal-Token) para que los syncs locales llamen
POST /cotizaciones/alertas-inventario sin JWT de usuario
- sync-estatus-maestro.py notifica los cambios aplicados al endpoint de
alertas (actividad al vendedor con cotizaciones recientes)
- Fix P1008 SQLite: escaneos del poll cron secuenciales +
connection_limit=1 en DATABASE_URL
- Webhooks registrados en Monday sobre https://frasa.consultoria-as.com
(Leads create_item, Oportunidades change_column_value); crons quedan
como red de seguridad
- Docs: sección 0 en AUTOMATIZACIONES-MONDAY.md con la matriz de eventos
y los quirks de Monday
- POST /api/auth/cambiar-password (bcrypt 12, política ≥8+1 número) +
modal en las 6 apps con auth
- PWA: manifest + íconos de marca en las 7 apps (sin service worker a
propósito, documentado); instalable en celular
- Dashboards: 'Mi tablero' para vendedor (sus KPIs y funnel) y sección
Equipo para coordinador/corporativo/admin
- mi-dia: equipo.porVendedor gana leadsNuevosSemana
- Tests: api 271, cotizador 88, alta 88, cobranza 81, agente-ia 19,
dashboards 15, mi-dia 11, landing 4
- PlanPago.vendedorId + filtro ?mios=1; toggle Mis planes/Todos en /pay
- Motor de recordatorios: próximos a vencer (3d) y vencidos (re-cada 7d),
canal Monday Actividad + stub WhatsApp listo para WA CRM, log persistente,
cron diario 9:30, run manual con dry-run, historial en /api/cobranza/recordatorios
- Agente IA: memoria por usuario (conversaciones aisladas) y tool calling:
cotizar_unidad (motor real por desarrollo) y buscar_unidad (inventario Monday)
- Tests: api 261, cobranza 75, agente-ia 13
- Borradores por vendedor (guardar/continuar/eliminar), se limpia al registrar
- Pre-llenado con ?cotizacion=<id> (cliente, contacto, proyecto, montos);
botón 'Iniciar alta' en Mis cotizaciones del cotizador
- Liga remota pública /client/firma/<token> (JWT scope firma-remota, 72h,
rate limit, solo datos mínimos sin PLD): firma digital + subida de
documentos que prende checkboxes en Monday Apartado
- Tokens de liga no sirven como sesión y viceversa
- Tests: api 228, alta 82, cotizador 82
- Mis cotizaciones (guardar con cliente, retomar, nueva) asociadas al vendedor del token
- Compartir: resumen copiable + deep link wa.me; PDF con folio, vigencia y QR
- GET /api/cotizaciones/:id/publico (público, datos mínimos sin PII del cliente)
- Comparador lado a lado de 2 unidades (mismo o distinto desarrollo)
- POST /api/cotizaciones/alertas-inventario: avisa al vendedor si una unidad
cotizada cambia de estatus (dedup; wire con syncs documentado)
- Fix: labels de propuesta mapeados a los reales del board Oportunidades
- Tests: api 201, cotizador 82
- 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
- MODELOS_POR_PROYECTO con los modelos reales del inventario
(DIAGONAL, SENDA, ATELIER, ESTANZA, SOLANA); texto libre en OTRO/Montebello
- PROYECTOS ampliado con ATELIER, ESTANZA y SOLANA
- Limpia el modelo al cambiar de proyecto si no aplica
- SENDA-410-1-G102, SENDA-410-1-G201, SENDA-401-1-L41 agregadas a Monday,
seeds y conocimiento IA (inventario 288 unidades; solo existían en el
reporte de estatus de venta, todas VENDIDO)
- PDFs del alta verificados exhaustivamente (5 documentos × 4 variantes,
contenido extraído con pdfplumber + renders visuales):
- firma huérfana en página propia (PLD) corregida
- encabezados de contacto huérfanos (checklist) corregidos
- modelo duplicado y enums crudos en perfil corregidos
- Tests pdf 6→16; suites: alta 76, cotizador 71, api 168
- API: viviendaCredito.ubicacion ahora opcional (la app web no la exigía;
el desfase causaba 400 que la app mostraba como fallo de red)
- App: crearAltaCliente distingue conexion/validacion; el 400 muestra
banner rojo con el detalle de los issues en vez del banner ámbar
- Tests: api 160, alta-clientes 66
- 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
- Modelo Usuario + seed desde lista de vendedores (18 usuarios, bcrypt cost 12)
- POST /api/auth/login + /api/auth/me; middleware Bearer en todo /api
excepto health, login y webhook Monday; flag AUTH_ENABLED
- Username = nombre completo normalizado (case/acentos insensible),
password inicial Frasa2026, admin vía ADMIN_PASSWORD
- Apps: LoginScreen + AuthGate (StudioBlank), token en localStorage,
header Authorization en todas las llamadas, logout en 401
- Tests: api 136, cotizador 71, alta 65, cobranza 71, agente-ia 13, landing 4