Consult AS Technology cfc0acb5d3 fix(crm): re-captura tras limpieza, bitacora compartida, origen en oportunidades y privacidad del buscador
1. Re-captura: el dedup por telefono/email ya no considera etapas cerradas
   (Descartado, Perdido, Cancelo, Cancelacion Apartado). Los restos de la
   ultima limpieza (17 filas de APARTADO cancelados sin contraparte activa)
   bloqueaban a los vendedores al re-capturar; los registros activos siguen
   bloqueando con 409 como siempre.
2. Bitacora compartida: GET /recordatorios con leadId/clienteClave devuelve las
   notas de TODOS los usuarios de ese cliente (antes cada quien solo veia las
   suyas). Mi dia pide la bitacora con esos filtros; la lista personal sigue
   siendo propia.
3. Origen en oportunidades: el resumen de mi-dia ya devuelve origen y la card
   de cada oportunidad lo muestra (telefono · desarrollo · canal · modelo).
4. Privacidad del buscador: /leads/buscar y /buscar filtran por dueno cuando
   el rol es vendedor (leads por usuarioId, contactos por capturadoPorId,
   cotizaciones por vendedorId). Los roles de supervision siguen viendo todo.
   Ya no aparecen leads de otros asesores con nombre y telefono al teclear.

Verificado en vivo contra el API: 10/10 comprobaciones (re-captura del
telefono cancelado 201, duplicado activo 409, nota del admin visible para la
vendedora, origen presente en 27/27 oportunidades, buscador del vendedor sin
datos ajenos y del admin completo). 716 pruebas del API y 32 de mi-dia en verde.
Los tests de roles ahora usan prisma mockeado (la BD viva cambia cuando el
cliente edita permisos desde la UI).
2026-09-24 09:49:41 +00:00

FRASA Ecosystem

Ecosistema comercial de Frasa Desarrollos S.A.P.I. de C.V.

Componentes

Componente Ruta Descripción
apps/landing / Entrada al ecosistema
apps/cotizador /quote/ Cotizador financiero (4 propuestas, PDF ANEXO A)
apps/alta-clientes /client/ Alta de clientes (wizard, firma digital, PDFs PLD)
apps/cobranza /pay/ Planes de enganche, vencidos, estados de cuenta
apps/dashboards /dash/ Tableros KPI (leads, oportunidades, inventario, cobranza)
apps/mi-dia /hoy/ Agenda del vendedor (mis leads, actividades, acciones CRM)
apps/agente-ia /ai/ Asistente IA con documentos del ecosistema
api-gateway /api/ Express 5 + Prisma + integración Monday.com

PWA (instalabilidad básica)

Las 7 apps son instalables (manifest + íconos): cada una tiene public/manifest.webmanifest ("Frasa · <app>", display: standalone, theme_color/background_color) e íconos 192/512 en public/icons/ (generados con scripts/generar-iconos-pwa.py, venv /root/.venv-tools).

Decisión: NO hay service worker. Solo se busca instalabilidad básica (ícono en el teléfono que abre la app a pantalla completa). Un SW con caché arriesga servir bundles viejos tras cada deploy (los usuarios son vendedores en campo; no van a limpiar caché a mano). Si algún día se quiere modo offline, hay que diseñar primero la estrategia de invalidación de caché.

Desarrollo local

Cada app es un proyecto Vite independiente: npm install && npm run dev (o npm run preview tras npm run build). Tests: npx vitest run en cada paquete. El API: cd api-gateway && npm install && npx prisma migrate dev && npm run dev.

Variables de entorno: copiar .env.example a .env y completar (el .env nunca se commitea).

Servidor actual (LXC sin Docker)

Esta máquina es un contenedor LXC sin nesting: Docker no puede correr contenedores. El stack corre directo en el host:

  • NGINX (apt) sirve los dist/ de las apps y proxifica /api/ → 127.0.0.1:3000. Config: deploy/nginx-host.conf → /etc/nginx/sites-available/frasa.
  • API como servicio systemd: deploy/frasa-api.service → frasa-api.service (systemctl status frasa-api, logs en /var/log/frasa-api.log).
  • Rebuild de apps tras cambios: VITE_API_URL=/api npm run build en cada app + systemctl reload nginx (no requiere restart).

Acceso público: Cloudflare Tunnel

El stack se expone en https://frasa.consultoria-as.com mediante Cloudflare Tunnel (Zero Trust), sin abrir puertos ni depender del DDNS:

  • Túnel administrado desde el dashboard (Zero Trust → Networks → Tunnels); el ingress vive en Cloudflare: public hostname frasa.consultoria-as.com → http://localhost:80. No hay config.yml local.
  • Servicio systemd cloudflared (instalado con cloudflared service install <token>, token en /etc/cloudflared/token). SSL lo termina Cloudflare automáticamente; Certbot ya no aplica en este servidor.
  • NGINX de host sigue en puerto 80 con server_name _ (catch-all), así que cualquier hostname del túnel funciona sin cambios.
  • Las ligas de firma remota se construyen con window.location.origin, así que ya salen con el dominio público al usarlas desde ahí.

El docker-compose.yml queda listo para cuando el stack se mude a una VM con Docker.

Deploy con Docker (VM futura)

git clone https://git.consultoria-as.com/consultoria-as/FRASA-CAS.git /opt/frasa-ecosystem
cd /opt/frasa-ecosystem
cp .env.example .env && nano .env        # completar secretos

# SSL: webroot (funciona con nginx corriendo y renueva sin downtime)
docker compose up -d nginx               # primer arranque SIN ssl: ver nota abajo
certbot certonly --webroot -w /var/www/certbot -d frasadesarrollos.ddns.net

docker compose build && docker compose up -d
docker compose logs -f api
curl https://frasadesarrollos.ddns.net/api/health

Modo local sin SSL (LAN): .env con NGINX_CONF=nginx.http.conf hace que NGINX sirva todo por HTTP en el puerto 80. Cuando el DDNS apunte a este servidor: certbot certonly --webroot -w /var/www/certbot -d frasadesarrollos.ddns.net, quita NGINX_CONF del .env (vuelve nginx.conf con 443) y docker compose restart nginx. Renovación: certbot renew --deploy-hook "docker compose -f /opt/frasa-ecosystem/docker-compose.yml restart nginx".

Backup: scripts/backup.sh (cron sugerido 17 2 * * *).

Monday.com

Workspace Frasa-CAS, organizado en carpetas como el CRM original del cliente:

  • CRM: Leads, Oportunidades, Apartado, Actividades
  • Ventas: Unidades (inventario), Ventas, Flujo Escrituras, Saldos a Favor, Cobranza, Seguimiento Preventa
    • Cobranza (board 18429260549) y Seguimiento Preventa (board 18429260580): estructura replicada del CRM anterior, sin flujo automático por ahora. Creados por API; pendiente moverlos a la carpeta Ventas (folder 21263260) a mano en la UI.
  • Postventa: Comunicación (bitácora postventa: unidad, canal, estado, fecha)
  • Generales: Contactos, Motivos No Compra, Desarrollos

Los board IDs están en .env.example. Webhook: POST /api/webhooks/monday (responde el challenge de activación).

Board Unidades — columnas de obra/estatus

Alimentadas por api-gateway/scripts/sync-obra-estatus.py desde el Reporte_EstatusVenta.xlsx del cliente (idempotente, --dry-run disponible; ver docstring del script):

  • % Avance obra, Meses atraso (numbers), Contratista, Clave catastral, No. oficial, Vendedor, Broker (text), Venc. autorización (date).
  • Fecha entrega obra (date): la columna original Fecha entrega ya traía datos de habitabilidad, por eso se creó una nueva.
  • Hitos documentales (checkbox): Cert. Gas, TO / C4, Régimen inscrito, Lista avalúo. Se encienden cuando la fecha del hito en el Excel ya pasó; el script nunca los apaga.
  • Nota: en No. oficial / Clave catastral el Excel del cliente trae fechas programadas (no números oficiales); se cargan como texto ISO tal cual.

Boards operativos nuevos

  • Flujo Escrituras: un item por mes/semana/proyecto con Escrituras (numbers) e Ingreso (numbers) del Flujo Calendario del cliente. Idempotencia por nombre único (AGOSTO SEM 3 AL 7 - SOLE).
  • Saldos a Favor: name CLIENTE / UNIDAD; columnas Desarrollo (status), Unidad (text), Monto (numbers), Estado (Pendiente/Devuelto), Comentario. Idempotencia por Unidad+Desarrollo.

Las unidades SOLE y MUTUO no existen en el board Unidades: el script las reporta como saltadas (sus vendedor/broker/venc. autorización no se cargan por ahora).

Pendientes conocidos

  • Migrar Prisma de SQLite a Postgres 16 (dinero a Decimal).
  • Auth JWT, helmet, rate-limit, CORS restringido (hoy: red interna).
  • Self-hostear worker/wasm de tesseract.js (OCR sin internet).
  • Automatizaciones Monday (round-robin, recordatorios 10 días) y cron de cobranza en el API.
Description
Integracion de operacion con monday para los departamentos de Cobranza, Ventas y Servicio al cliente de FRASA DESARROLLOS
Readme 14 MiB
Languages
TypeScript 94.9%
Python 2.8%
JavaScript 1.9%
CSS 0.2%
HTML 0.1%