IvánDíazLab

Tu cliente arma el viaje. Tus márgenes se quedan contigo.

El cliente elige su viaje. El servidor protege tus márgenes.

Ilustración conceptual: Cotizador sin fuga de márgenes.
Cotizador sin fuga de márgenesIlustración conceptual

Monorepo pnpm · Fastify 5 · Drizzle · PostgreSQL 16 · Vite · React 19 · TypeScript · Tailwind 4 · TanStack

Hecho. Y comprobado.

1
único lugar donde se calcula el precio: el servidor
v1.2.0
versión en producción
SHA-256
huella que invalida la selección si el vendedor edita
~250 MB
de RAM ahorrados por la elección de stack
Cómo está construido.Decisiones, evidencia y detalles

Ficha técnica

Cliente
Tour operador en Chiapas (anónimo)
Periodo
Julio – agosto 2026
Estado
v1.2.0 en producción
Rol
Producto, arquitectura, construcción y despliegue
Reemplaza
Un flujo de cotización hecho a mano con hojas de cálculo y documentos de texto

Contexto

Un tour operador en Chiapas vendía paquetes cotizando en hojas de cálculo y pasando el resultado a un documento de texto con el diseño de la marca. Cada cambio del cliente —una habitación más, un traslado menos— obligaba a rehacer las dos cosas a mano.

El objetivo era doble: quitarle al vendedor el trabajo repetitivo y darle al cliente algo mejor que un archivo adjunto. Es decir, un enlace donde pueda mover las variables que de verdad le importan y ver el efecto en su total, sin tener que escribir «¿y si vamos cuatro en vez de dos?».

Con una condición de fondo: en este negocio, el margen es información reservada. El cliente debe poder jugar con su paquete sin acercarse nunca a lo que ese paquete le cuesta a la agencia.

El problema

Un enlace público que calcula precios es, por definición, un enlace que puede filtrar cómo se calculan.

En cuanto el cliente puede recalcular su total en el navegador, aparece la tentación de mandarle los datos para que el navegador haga la cuenta. Y ahí es donde se filtra el negocio: costos por ítem, escalas de margen, nombres de proveedores. No hace falta enseñarlo en pantalla; basta con que viaje en la respuesta.

Vi de cerca el otro camino y su factura. En un proyecto hermano el motor de cálculo se duplicó en el navegador y en el servidor, y esa duplicación es hoy su peor deuda: los dos motores nunca coinciden exactamente, y cada divergencia es una discusión con un cliente que vio un número distinto al que aparece en el documento final.

También estaba el problema del tiempo. Una cotización enviada y no respondida es dinero potencial enfriándose, y el vendedor no tiene forma de saber cuáles vale la pena perseguir.

Decisiones clave

Una guardia que revisa cada respuesta pública

Todo lo que sale por la ruta pública pasa por una función que inspecciona el contenido y lanza excepción si detecta costo, margen o datos de proveedor. No es una convención del equipo: es una comprobación que corre en producción, en cada petición.

Las reglas que dependen de que todos se acuerden se rompen el día que alguien agrega un campo con prisa. Una guardia en runtime convierte «no debemos filtrar» en «no podemos filtrar», y falla ruidosamente en desarrollo antes de fallar callada en producción.

El precio se calcula solo en el servidor

El navegador del cliente muestra el total que le da el servidor; no tiene el motor de cálculo ni los datos para reproducirlo.

Duplicar el motor es duplicar la verdad. Lo vi convertirse en la peor deuda de un proyecto hermano: dos implementaciones que nunca coinciden al último decimal y una discusión recurrente sobre cuál de las dos es la buena.

Congelar el costo y firmar la selección

Cada ítem guarda una instantánea de su costo en el momento de cotizar, el folio es atómico y no se recicla, y la selección del cliente lleva una huella SHA-256 que la invalida si el vendedor edita la cotización después.

Sin instantánea, una cotización de la semana pasada cambia sola cuando cambia una tarifa. Sin huella, el cliente puede aceptar una versión que ya no existe, y el negocio queda obligado a algo que nunca ofreció.

Elegir el stack por lo que consume, no por lo que está de moda

Se usó una capa de acceso a datos ligera en vez de la opción habitual, y un generador de PDF en proceso en vez de levantar un navegador completo para renderizar. La diferencia es del orden de 250 MB de memoria.

Todo esto vive en un servidor de 16 GB donde ya corren más de 60 contenedores. Ahí, 250 MB no son una optimización prematura: son el margen entre convivir con los demás servicios o empezar a competir con ellos.

La pantalla que paga el proyecto

Una vista lista las cotizaciones que el cliente abrió y no ha aceptado, ordenadas por un puntaje determinista cuyas reglas la interfaz explica en palabras: «La abrió 3 veces · Leyó 2 min · Caduca en 2 días».

Cero inteligencia artificial y funciona desde el primer día, porque las reglas son visibles y el vendedor puede estar de acuerdo o no con ellas. Un puntaje que nadie entiende no se usa; uno que se explica solo, sí.

Del cotizador interno al enlace del cliente

El precio nace y muere en el servidor. El navegador del cliente pinta un total, nunca lo calcula, y la respuesta pasa por una guardia antes de salir.

  1. El vendedor arma la cotización

    Elige servicios e ítems; los costos quedan congelados en una instantánea por ítem.

  2. Folio atómico, sin reciclaje

    Cada cotización recibe un folio único que jamás se reutiliza.

  3. Enlace con token

    El cliente abre su enlace y elige ocupación y opcionales, con el total en vivo.

  4. assertNoLeak()

    Toda respuesta pública se revisa: si trae costo, margen o proveedor, se lanza excepción.

  5. PDF de marca on-demand

    El documento se genera al momento, con la selección firmada por su huella.

La solución

Es un monorepo con un backend en Fastify sobre PostgreSQL y una interfaz en React con TypeScript. El vendedor trabaja en una aplicación instalable que arma la cotización; el cliente recibe un enlace con token que abre su propia vista, donde elige ocupación y opcionales y ve el total actualizarse.

Cuando el cliente confirma, el PDF con el diseño de la marca se genera al momento, con la selección ya firmada. El documento no se guarda de antemano ni se regenera distinto: sale de la misma fuente que el total que el cliente vio en pantalla.

Y del lado interno está la pantalla de seguimiento, que convierte «tengo muchas cotizaciones enviadas» en una lista ordenada por probabilidad de cierre, con el porqué escrito al lado de cada una.

Resultados

  • v1.2.0 en producción, sustituyendo el flujo de hojas de cálculo y documentos de texto.
  • Cada respuesta pública pasa por la guardia anti-fuga: costo, margen y proveedor no pueden salir por esa puerta.
  • El precio tiene una sola implementación, en el servidor: no hay dos motores que puedan discrepar.
  • Folio atómico sin reciclaje, costos congelados por ítem y huella SHA-256 que invalida una selección obsoleta.
  • La elección de stack ahorra del orden de 250 MB de memoria en un servidor compartido con más de 60 contenedores.

Lo que aprendí

Que la confidencialidad se diseña o no existe. Escribir «no expongas márgenes» en una guía de estilo no evita nada; una comprobación que revienta la petición, sí.

Que ver la deuda de otro proyecto de cerca vale más que leer sobre ella. La duplicación del motor de cálculo no se evitó por doctrina, sino porque ya había visto la factura mensual que cobra.

Y que la funcionalidad que paga el proyecto casi nunca es la más sofisticada. Aquí fue una lista ordenada con reglas explicadas en español, sin una línea de inteligencia artificial.

Tu operación también puede dar el salto.

PlatiquemosVer más proyectos