← Todos los proyectos

Cotizly

Un SaaS multi-tenant que convierte hojas de cálculo dispersas en un solo flujo — arma una cotización, llévala por su ciclo de vida y convierte la aprobada en un pedido real, por empresa.

NestJSTypeORMPostgreSQLAngularRedisTailwind CSS

Casi todo el dinero que una empresa pierde entre el “aquí está su cotización” y el “aquí está su factura” no se va en un gran error — se filtra. Un precio vive en una hoja de cálculo, los datos del cliente en otra, la versión aprobada en un hilo de correo, y el pedido se vuelve a teclear a mano en un tercer lugar donde un dígito cambia sin que nadie lo note. La cotización estaba bien; el pedido, no; y nadie puede decir dónde se torció.

Cotizly cierra esa brecha. Es un SaaS web que permite a una empresa armar cotizaciones, moverlas por un ciclo de vida real y convertir las aprobadas en pedidos — todo en un mismo lugar, con los números arrastrados en lugar de retecleados.

Qué hace

  • Espacio por empresa. Cada empresa entra a su propio espacio — sus usuarios, sus clientes, su catálogo. Nada se cruza entre inquilinos.
  • Gestión de catálogo. Productos y categorías se administran por empresa, con imágenes, para que una cotización se arme con artículos reales a precios reales, no con texto libre.
  • Un constructor dinámico de cotizaciones. Eliges un cliente, traes productos del catálogo, fijas cantidades — el subtotal, el impuesto y el total se calculan sobre la marcha, y el servidor se niega a guardar una cotización cuyos números no cuadran.
  • Un ciclo de vida de la cotización. Una cotización no está solo “abierta” o “cerrada.” Avanza por borrador → pendiente → aprobada (o rechazada / expirada), y solo por las transiciones que el sistema realmente permite.
  • Conversión cotización → pedido. Una cotización aprobada se convierte en un pedido que queda enlazado a la cotización de la que salió — la trazabilidad que el hilo de correo nunca tuvo.
  • Historial filtrable y exportable. Cada cotización es buscable, y cualquiera puede exportarse a PDF o Excel para el cliente o el archivo.
  • Un tablero. Conteos de productos, clientes y cotizaciones, cotizaciones desglosadas por estado y la actividad más reciente — la vista de un vistazo que la hoja de cálculo no daba.

Por dentro

Lo interesante es que Cotizly es un verdadero SaaS multi-tenant, y el aislamiento se aplica donde importa — en el servidor.

Aislamiento de inquilino como guardia, no como convención. El alcance por empresa no se deja a la confianza de que la UI mande el ID correcto. Un CompanyIsolationGuard dedicado compara la empresa del usuario autenticado contra la empresa de la petición — ruta y body — y rechaza cualquier intento de leer o escribir datos de otro inquilino, incluso si los IDs se manipulan a propósito. Cada consulta de servicio además se acota por companyId, así que un cliente, producto o cotización solo puede ser tocado por la empresa que lo posee.

El ciclo de vida está modelado, no insinuado. El estado es un enum tipado, y los movimientos permitidos entre estados viven en una tabla de transiciones explícita en el servidor. Pide un salto inválido — por ejemplo, revivir una cotización rechazada — y la API te dice exactamente qué transiciones son válidas en lugar de corromper el registro en silencio.

Las escrituras son transaccionales y se auto-verifican. Crear o editar una cotización corre dentro de una transacción de base de datos: se validan las relaciones (empresa, usuario, cliente, cada producto), se guardan los ítems, y los totales se recalculan y reconcilian contra lo que envió el cliente dentro de una tolerancia — el servidor es la fuente de verdad sobre el dinero, no el navegador.

Una API NestJS tipada. El backend es NestJS en TypeScript estricto sobre TypeORM / PostgreSQL, con tokens JWT de acceso + refresh (Passport), guardias por rol (admin / manager / user), y un modelo de borrado lógico con restauración en las entidades clave para que nada se pierda de verdad. Redis respalda una caché de respuestas — con bloqueo single-flight para que una clave fría no estampide la base de datos — y el limitador de peticiones. La superficie se endurece con Helmet, IDs de contexto de petición, validación global y una especificación Swagger / OpenAPI documentada.

El stack

  • Frontend — Angular 19 con Tailwind CSS y Angular Material/CDK, RxJS; exportación a PDF (jsPDF) y Excel (SheetJS/xlsx) en el cliente. Desplegado en Firebase Hosting.
  • Backend — NestJS en TypeScript estricto, REST documentado con Swagger/OpenAPI.
  • Datos — PostgreSQL vía TypeORM; Redis para caché de respuestas y almacenamiento del rate limit.
  • Auth y seguridad — JWT acceso/refresh con Passport, control de acceso por rol, bcrypt, Helmet, throttling, un guardia de aislamiento por empresa.
  • Ops — build Docker multi-etapa con usuario no-root y health check, listo para despliegues tipo Railway en contenedor.

Vale la pena notar

Construí Cotizly solo, de punta a punta — frontend, backend y base de datos. Es un producto propio, actualmente en pausa más que en desarrollo activo.

Lo que lo hace digno de una mirada no es una lista larga de funciones — es la disciplina debajo de un producto más bien pequeño. Aislamiento multi-tenant aplicado en el servidor, un ciclo de vida de la cotización modelado como transiciones de estado explícitas y validadas, dinero recalculado del lado del servidor en vez de confiarse al cliente, y una caché que falla de forma segura si Redis no está — estas son las decisiones que separan un demo de algo sobre lo que un negocio podría de verdad llevar sus cotizaciones sin perder dinero en silencio por las rendijas.

¿Un café y platicamos?

¿Te gustó lo que leíste? Construyo productos así de punta a punta — y siempre estoy para una buena plática. Hablemos del tuyo, o nomás intercambiamos ideas con un café.

Rentheria · Guadalajara, México