NorteAR
Producto propio
En construcción · Next.js · TypeScript
Sistema de gestión para pymes de servicio que mide el margen real, no la facturación.

Ver el panel completo

El caso, en seis tiempos
01
Problema
Un negocio de servicios factura bien y a fin de mes no le queda nada. El sistema le muestra ventas; lo que no le muestra es cuánto insumo se consumió para producir cada una de esas ventas — el pomo de color que rinde unas pocas aplicaciones, el producto que se descartó, el turno que salió más caro de lo que se cobró.
Casi todos los sistemas de gestión miden lo que entra. Muy pocos miden lo que se gastó para que entrara. Y sin eso, «vendimos más» y «ganamos más» son la misma frase — hasta que dejan de serlo.
02
Decisión
El margen es la métrica central, no un reporte más en un menú: es la cifra que el sistema devuelve por defecto. Si la métrica principal es la facturación, el usuario sigue mirando lo que ya miraba.
Servicios, no retail. Un comercio que revende conoce su costo unitario. Un negocio de servicios no: el insumo se consume de a fracciones y nadie las anota. Ese es el hueco.
Multi-tenant desde el modelo de datos, no como capa encima: cada tabla filtra por empresa. La alternativa — una base por cliente — escala peor apenas hay que tocar todas a la vez, y acá el negocio es justamente medir y comparar, no aislar.
03
Mecanismo
El problema difícil no es contable, es de modelado: cómo saber cuánto insumo consumió un servicio si nadie lo pesa. La respuesta fue atar cada servicio a sus insumos y descontar contra el stock real.
- Turno
- Insumos
- Stock
- Margen
// Every service carries its supplies (serviceSupplies): what it consumes and // how much of each. Selling it draws down real stock, not an estimate. const consumptions = serviceItems.flatMap((item) => { const service = services.find((s) => s.id === item.serviceId)!; // quantityNeeded counts service uses; convert to base-unit stock consumption. return service.serviceSupplies.map((ss) => ({ supplyId: ss.supplyId, consumed: unitsPerUse(ss.packageContent, ss.servingsPerPackage) * Number(ss.quantityNeeded) * item.quantity, })); }); const stockDelta = new Map<string, number>(); for (const { supplyId, consumed } of consumptions) { stockDelta.set(supplyId, (stockDelta.get(supplyId) ?? 0) + consumed); }04
Trade-off
Cargar los insumos es trabajo del usuario, y ese trabajo es la barrera de entrada del producto: sin insumos cargados no hay margen, y con el sistema vacío no se ve el valor. Todo lo demás se subordina a bajar ese costo inicial.
Lo que quedó afuera a propósito: facturación electrónica (AFIP/ARCA no existe en el schema), multi-sucursal y app nativa. Alcance corto por decisión, no por límite técnico — el producto está pensado para un tipo de negocio, no para todos.
05
Resultado
- Negocios activos
- 2
- Trial → pago
- 2
- Retención 3 meses
- 2/2
- En producción desde
- Junio 2026
06
Después
Si arrancara de nuevo, no alargaría el alcance desde el principio. Fui sumando complejización — multi-sucursal, roles, reportes por profesional — para un uso que, en esta primera instancia, es un puñado de clientes conocidos. Esa complejidad se paga en tiempo de desarrollo que no vuelve, y el producto todavía no la necesitaba para probar si funcionaba.