Consult AS Technology 8a2584438d fix(auditoria general): 25 errores encontrados en la revision modulo por modulo
SEGURIDAD (agente IA):
- Conversaciones: GET /ai/conversations/:id y el reanudar chat verifican
  propiedad (antes cualquier usuario leia/continuaba la conversacion de otro).
- /ai/documents pasa a solo-admin (antes cualquien podia inyectar o borrar
  documentos de la base de conocimiento).

DATOS / CORRUPCION:
- Cotizador: elegir un cliente del maestro en el buscador ya no crea un lead
  fantasma "Registro previo (CRM anterior)" en el embudo.
- Afluencia con oportunidadId inexistente: 404 en vez de crear sombra fantasma.
- Cobranza: los 103 planes importados quedaron con vendedor asignado (7 con su
  asesor real segun el Excel, el resto al admin) y el motor de recordatorios
  cae al admin cuando un plan no tiene vendedor: antes los 411 recordatorios
  se registraban 'sin-destinatario' y no los veia nadie.
- Backups: script reescrito para el host real (sqlite .backup + uploads + env
  en /root/backups) y cron instalado (antes: script que asumia docker y sin
  cron programado = cero respaldos).

REPORTES / METRICAS:
- Mi tablero: el embudo ya excluye cancelaciones reales (Cancelo/Cancelacion
  Apartado) y cuenta como vendidos Firma Cliente/Escriturado/Titulado (antes
  41 "apartados" donde habia 13 activos y vendidos buscaba una etapa que no
  existe); tasa de descarte ya compara el mismo periodo.
- Scoring: etapa real 'Agendo Cita' (antes 'AGENDO' nunca aplicaba) y los
  descartados/perdidos ya no reciben score.
- ver_cobranza (IA): ignora planes cancelados y no cuenta como vencido el pago
  que vence hoy.

UI / FLUJOS:
- mi-dia: typo CANCO -> CANCELO (los cancelados reaparecen en Escrituracion);
  confirmar cita ya no retrocede la etapa de Cotizador/Aparto (boton y kanban).
- alta-clientes: la firma ya no se borra al navegar fuera del paso de firmas;
  toast de exito solo cuando el API confirma; prefill de apartado trae
  direccion, estado civil y fecha de nacimiento desde el alta.
- Auditoria: el filtro por usuario funciona (el front enviaba 'usuario' y el
  API esperaba 'usuarioId') y 'hasta' incluye todo el dia.
- Contactos: paginacion aplicada despues de fusionar fuentes (antes saltaban o
  se repetian contactos entre paginas y 'Siguiente' se deshabilitaba antes de
  tiempo).
- Buscador global: leads -> /hoy/, contactos -> /; el cotizador entiende
  ?cotizacion=<id> para retomar desde la liga.
- Export mi-dia: columnas Desarrollo/Origen rellenas y sin duplicados.
- Recibo de cobranza: "Recibio" es FRASA (el cliente paga, no recibe).
- Alta de plan de cobranza: proyecto libre con sugerencias del catalogo real
  (antes limitado a 3 proyectos que no cubrian la cartera).

Verificado en vivo: autorizacion IA (3x 403), filtro de auditoria, 404 de
afluencia. Suites: 717 API + 124 alta-clientes + 115 cotizador + 92 cobranza +
89 landing + 32 mi-dia en verde. Backup de hoy generado en /root/backups.
2026-09-24 10:54:09 +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%