Full stack, a cargo de la planificación de stock
Inventia lo construimos en equipo, repartido por módulos. Yo trabajé en el frontend y en la API. Mi foco fue la parte que convierte datos de stock en decisiones: planificación por almacén, alertas, reposición entre sucursales, y además multimoneda y órdenes de compra.
Planificación por almacén
Cálculo de stock de seguridad, punto de pedido y lote óptimo por almacén. La demanda de un depósito es la suma de lo que abastece, calculada de forma recursiva por la cadena.
Alertas accionables
Un único criterio de alerta, igual en la lista y en el modal. Cada alerta trae la cantidad sugerida y desde dónde sale: "Reponer N desde Central" o "Comprar N".
Reposición entre almacenes
Pedido de reposición y bandeja de confirmación conectados al backend, con rutas alternativas cuando el origen preferido no tiene stock.
Gráficos de stock
Gráfico de diente de sierra propio (SVG, sin librerías nuevas) con proyección, zoom y guías paso a paso que muestran las fórmulas con los números del ejemplo.
Compras y multimoneda
Emisión formal de órdenes con PDF, facturas, y órdenes en otra moneda con tipo de cambio congelado al emitir.
Datos de demostración
Un seed completo de una empresa ficticia: 52 semanas de ventas, cadena de almacenes, proveedores y roles, para mostrar el sistema funcionando de punta a punta.
De dónde partimos
Una pyme típica con varias sucursales maneja el stock con planillas y la memoria del encargado. Cada sucursal compra por su cuenta y nadie ve el total.
Dolores detectados
- Quiebres de stock que se descubren cuando el cliente ya está en el mostrador.
- Sobrestock en un depósito mientras otra sucursal se queda sin nada.
- Compras a ojo, sin saber cuánto ni cuándo.
- Sin trazabilidad: no se sabe quién movió qué.
Objetivo
Un sistema único para catálogo, stock por almacén, compras, ventas y caja, que además diga qué hacer: cuándo reponer, cuánto y desde dónde.
Usuarios
AdministradorEncargado de comprasEncargado de depósitoVendedor de sucursalGerencia (BI)Proveedor (portal)
Resultado: pasar de "reaccionar al faltante" a "anticiparlo", con la decisión ya calculada.
Requisitos
| ID | Requisito | Tipo | Prioridad |
|---|---|---|---|
| RF-01 | Gestionar catálogo de artículos y variantes, con categorías, marcas y códigos estandarizados. | Funcional | Alta |
| RF-02 | Registrar stock por almacén (sucursales y depósitos) con movimientos trazables. | Funcional | Alta |
| RF-03 | Calcular stock de seguridad, punto de pedido y cantidad a pedir por almacén. | Funcional | Alta |
| RF-04 | Alertar faltantes y sugerir reponer desde otro almacén o comprar. | Funcional | Alta |
| RF-05 | Emitir órdenes de compra, recibir mercadería y registrar facturas de proveedor. | Funcional | Alta |
| RF-06 | Punto de venta con caja, medios de pago, comprobantes y cuenta corriente. | Funcional | Alta |
| RF-07 | Portal para que el proveedor confirme órdenes. | Funcional | Media |
| RF-08 | Operar en otra moneda con tipo de cambio congelado al emitir. | Funcional | Media |
| RF-09 | Tablero gerencial con indicadores y pronóstico de demanda. | Funcional | Media |
| RNF-01 | Control de acceso por permisos de negocio, validado siempre en el servidor. | No funcional | Alta |
| RNF-02 | Listados con paginación del lado del servidor. | No funcional | Alta |
| RNF-03 | Uso desde el celular en las pantallas de sucursal. | No funcional | Media |
| RNF-04 | Integración continua: build, lint, formato y tests en cada cambio. | No funcional | Media |
| RNF-05 | Baja lógica: nada se borra, todo se puede auditar y reactivar. | No funcional | Base |
Dentro del alcance
- Catálogo, stock multi-almacén, compras, ventas y caja.
- Planificación y reposición en cadena.
- Roles y permisos configurables.
- Portal de proveedor y BI.
Fuera del alcance
- Contabilidad general.
- E-commerce público.
- Logística de envíos a clientes.
Evolución natural
- Cambio de ruta de abastecimiento con recálculo automático.
- Pronóstico alimentando directamente la planificación.
Casos de uso
Cada caso está atado al permiso que lo habilita. El permiso es una capacidad de negocio, no un endpoint.
Ver alertas de stock
Lista las variantes con alerta, ordenadas por gravedad.
variante-articulo:consultar
Emitir orden de compra
Genera la orden formal en PDF para el proveedor.
orden-compra:enviar
Pedir reposición
Solicita mercadería a otro almacén de la cadena.
pedido-reposicion:solicitar
Confirmar reposición
El almacén que recibe confirma lo que llegó.
pedido-reposicion:confirmar
Rechazar reposición
Rechaza un pedido que no puede atender.
pedido-reposicion:rechazar
Cobrar una venta
Cierra la venta en caja con uno o más medios de pago.
venta:cobrar
Configurar roles
Arma roles combinando permisos del catálogo.
rol:modificar
Confirmar orden recibida
El proveedor acepta la orden desde su portal.
orden-compra:consultar
Arquitectura
Tocá un bloque para ver qué hace. La línea verde muestra el camino de una petición.
Tocá o pasá el mouse por un bloque.
El modelo de stock, en un gráfico
El "diente de sierra": el stock baja con las ventas; al cruzar el punto de pedido (R) se pide; cuando llega el pedido, sube de golpe. El stock de seguridad (SS) cubre la demora del proveedor.
Lote fijo (Q)
Cuando el stock toca R = d·L + SS, se pide siempre la misma cantidad Q* (lote económico).
Período fijo (P)
Se revisa cada cierto tiempo y se pide hasta llegar al máximo E. Útil cuando el proveedor visita en días fijos.
Demanda de la red
Un depósito no vende: su demanda es la de los almacenes que abastece, sumada de forma recursiva.
Proceso: de la alerta a la reposición
El flujo de negocio principal que diseñé e implementé. Usá "Animar" para seguir el recorrido.
Estructura de código
frontend/src
features/<dominio>/<feature>
api/src/modules
Tres principios
- Una sola decisión. La alerta de la lista y la del modal usan el mismo cálculo; nunca dos versiones de la verdad.
- El servidor manda. Permisos y paginación se resuelven en la API; el cliente solo acompaña.
- Capas finas. Rutas que solo apuntan a una página, servicios que solo envuelven el cliente HTTP.
Decisiones de arquitectura
- Contexto
- Cada pyme reparte tareas distinto; roles fijos no alcanzan.
- Decisión
- Catálogo de permisos con forma
recurso:acción(ej.venta:cobrar), validados en el servidor; los roles son combinaciones configurables. - Consecuencias
- Máxima flexibilidad y auditoría clara. A cambio, un catálogo grande que hay que mantener sincronizado entre backend y frontend.
- Contexto
- La lista de artículos y el modal de reposición calculaban la alerta por separado y a veces no coincidían.
- Decisión
- Centralizar la decisión en el backend y reutilizarla en la lista, el resumen, el modal y la proyección del gráfico.
- Consecuencias
- El usuario ve siempre lo mismo. Se resignó flexibilidad: cualquier ajuste al criterio impacta en todas las pantallas a la vez.
- Contexto
- Un depósito central no registra ventas, así que su demanda "propia" es cero y nunca dispararía compras.
- Decisión
- La demanda de un almacén es la suya más la de todos los que abastece, por la ruta preferida.
- Consecuencias
- Las compras se concentran donde corresponde. Costo: cambiar una ruta obliga a recalcular la cadena (quedó como evolución pendiente).
- Contexto
- El gráfico de diente de sierra necesita saltos verticales exactos, líneas de referencia y tooltips por evento.
- Decisión
- Componente SVG propio, sin sumar dependencias, con el estilo de los gráficos del BI.
- Consecuencias
- Control total del dibujo y cero peso extra. Se resignó lo que una librería da gratis (zoom, accesibilidad), que hubo que implementar a mano.
- Contexto
- Órdenes y facturas en dólares con una cotización que cambia todos los días.
- Decisión
- Guardar el tipo de cambio en el documento al momento de emitirlo.
- Consecuencias
- Los importes históricos no cambian solos. A cambio, las diferencias de cambio se ven pero no se contabilizan automáticamente.
Tecnologías
Frontend
React 19TypeScriptTanStack StartTanStack QueryTailwind v4shadcn/uiFormik + YupVite
Backend
NestJSTypeORMPostgreSQLJWTVitest
Calidad y equipo
GitHub ActionsESLintPrettierGit flowJira
Módulos
Artículos y variantes
Catálogo con códigos estandarizados, precios, stock sumado y estado de alerta por fila.
articulo:consultar
Abastecimiento
La cadena de cada sucursal en tabla o gráfico, con ruta preferida y demora.
almacen:consultar
Reposiciones
Pedido entre almacenes y bandeja de confirmación, también en celular.
pedido-reposicion:*
Órdenes de compra
Emisión formal en PDF, recepción y facturas, en pesos o en otra moneda.
orden-compra:*
Punto de venta
Venta en caja, medios de pago, remitos y cuenta corriente.
venta:cobrar
Accesos
Usuarios, roles y permisos configurables desde la interfaz.
rol:*
Portal de proveedor
El proveedor ve y confirma sus órdenes.
orden-compra:consultar
BI gerencial
Indicadores, Pareto ABC y pronóstico de demanda.
bi-overview:consultar
Problemas y soluciones
El depósito nunca pedía
Problema: sin ventas propias, su demanda daba cero.
Solución: demanda recursiva de la red de almacenes que abastece.
"Reponer" desde un origen vacío
Problema: se sugería reponer desde un almacén sin stock.
Solución: cantidad reponible acotada al stock del origen y oferta de la ruta alternativa.
Pedidos duplicados
Problema: la proyección volvía a pedir aunque la reposición ya venía en camino.
Solución: el cálculo descuenta lo que está "en camino" y lo muestra en la fila.
Líneas que no se dibujaban
Problema: la grilla del BI y el corte del Pareto desaparecían.
Solución: los colores oklch de los tokens no eran válidos en ese contexto; se resolvieron a valores compatibles.
Tooltip mostrando otro día
Problema: el gráfico de stock marcaba un día distinto al del cursor.
Solución: marcas alineadas a las mismas filas de datos del gráfico.
Tabla que no entraba
Problema: Artículos desbordaba a 1280 px.
Solución: se reorganizaron columnas (marca bajo el nombre, precios en dos líneas, "en camino" bajo el estado).
Referencias nulas tras una baja
Problema: registros históricos apuntaban a entidades dadas de baja y fallaban.
Solución: consultas que incluyen las bajas lógicas donde corresponde.
Una demo creíble
Problema: sin historia de ventas, la planificación no tenía nada que mostrar.
Solución: seed de una empresa ficticia con 52 semanas de ventas ancladas a la fecha actual.
