Retail / operaciones / PyME mexicana multi-almacen

Sistema de Inventario Multi-Almacen para PyME

Sistema completo de inventario con kardex, transferencias atomicas entre almacenes, alertas de stock minimo, auditoria completa y exportes CSV — Next.js 14 + Prisma + Auth.js v5 + 4 roles.

Next.js 14TypeScript strictPrisma 5PostgreSQL 15Auth.js v5Argon2Vitest+Playwright
Antes de nosotros

El Reto

Una PyME mexicana con 2-3 almacenes (central + sucursales) opera con Excel: cada almacen lleva su archivo, las transferencias se anotan a mano, los ajustes por inventario fisico no quedan documentados, y nadie sabe cuanto vale el inventario total. Cuando llega Hacienda o un comprador interesado en la empresa, la respuesta es 'damos un par de dias para ordenar'.

El reto no era solo digitalizar — era garantizar consistencia bajo concurrencia. Si dos usuarios crean simultaneamente una salida del mismo producto y el stock disponible es 1, NUNCA puede haber stock negativo. Si una transferencia entre almacenes falla a la mitad (decrementa origen pero no incrementa destino), el inventario queda corrupto.

Adicionalmente: 4 roles con permisos estrictos (SUPERADMIN, ADMIN, ALMACENISTA, CONSULTA), auditoria completa en AuditLog (before/after de cada cambio), validacion estricta con Zod, rate limiting en logins (5 intentos/15min/IP) y exports CSV solo para roles autorizados.

Lo que construimos

La Solucion

Stack Next.js 14 App Router con TypeScript strict (noUncheckedIndexedAccess: true), Prisma 5 + PostgreSQL 15 en docker-compose, Auth.js v5 con Credentials Provider y Argon2id (memoryCost 19456, timeCost 2). Validacion estricta con Zod schemas .strict() — rechaza campos extra del body. Logging estructurado con pino. Rate limiting Upstash Redis.

Motor de stock en movimiento.service.ts: cada operacion (ENTRADA/SALIDA/AJUSTE/TRANSFERENCIA) se ejecuta en transaccion Prisma serializable con SELECT FOR UPDATE sobre InventarioBalance. Validacion ANTES de mutar: si disponible < cantidad, error STOCK_INSUFICIENTE. Transferencia es transaccion atomica: 4 operaciones (decrementar origen, incrementar destino, crear movimiento SALIDA, crear movimiento ENTRADA) linkeadas con campo transferenciaPar — rollback total si cualquier paso falla.

Auditoria: cada mutacion (crear producto, editar, soft delete, mover stock, cambiar minimo) crea AuditLog con tabla, registroId, accion, cambios JSONB (before/after), userId, IP, userAgent. Soft delete via campo activo — nunca borrar fisicamente. Tests: Vitest para unit (movimiento.service, inventario.policy) + integration (api.movimientos, api.productos) + Playwright para E2E (flujo completo + permisos).

Funcionalidades

Features Clave

Stock Nunca Negativo (RN-01)

Validacion en service layer: si cantidad solicitada > disponible, error 'Stock insuficiente: disponible [X], solicitado [Y]'. Sin excepciones. Probado con tests de carrera concurrente.

Transferencia Atomica entre Almacenes (RN-02)

4 operaciones en transaccion Prisma: decrementar origen, incrementar destino, crear TRANSFERENCIA_SALIDA, crear TRANSFERENCIA_ENTRADA. Ambos movimientos linkeados via transferenciaPar. Si cualquier paso falla → rollback total.

Kardex Completo por Producto

Vista detalle de producto con balance por almacen + tabla kardex (historial completo de movimientos): fecha, tipo, almacen, cantidad, saldo acumulado, motivo, usuario. Filtros por rango de fechas + tipo + almacen. Export CSV del kardex.

4 Roles con Permisos Granulares

SUPERADMIN (eliminar registros), ADMIN (CRUD productos/almacenes), ALMACENISTA (crear movimientos), CONSULTA (solo lectura). Verificacion via inventory.policy.ts: canCreateMovimiento, canManageProductos, canExportData, canManageAlmacenes, canDeleteRegistros.

Alertas de Stock Minimo

Vista /alertas con productos donde disponible <= stockMinimo (stockMinimo > 0 — minimo 0 no genera alerta). Columnas: SKU, nombre, almacen, disponible, minimo, diferencia, % restante, accion 'Registrar entrada' (pre-llena formulario).

Exports CSV con Permisos

GET /api/reportes/existencias y /api/reportes/movimientos retornan Content-Type: text/csv. Solo accesibles para ADMIN, ALMACENISTA, SUPERADMIN. CONSULTA recibe 403. Rate limit 10 exports/hora/usuario.

Auditoria Completa con before/after

AuditLog.cambios es JSONB con { before, after }. Cada UPDATE captura el estado anterior antes de mutar. Incluye IP del request y userAgent. Indices por (tabla, registroId), userId, createdAt para queries forenses.

Screenshots

Como se Ve

Screenshot

Dashboard con KPIs y Grafica

4 KPI cards (productos activos, en alerta, valorizacion total, movimientos hoy) + grafica de barras apiladas movimientos por dia ultimos 14 dias (recharts) + tabla ultimos 10 movimientos + top 5 productos con menor stock relativo.

Screenshot

Formulario Inteligente de Movimiento

Paso 1 selecciona tipo (ENTRADA/SALIDA/AJUSTE/TRANSFERENCIA). Paso 2 campos cambian segun tipo: ENTRADA pide costo unitario, AJUSTE pide motivo min 10 chars con contador. Feedback en tiempo real del disponible.

Screenshot

Vista Detalle de Producto + Kardex

Header con SKU + nombre + badges. Panel izquierdo (60%) datos + edicion. Panel derecho (40%) balance por almacen. Tabla kardex con saldo acumulado por movimiento + boton exportar CSV.

Screenshot

Alertas de Stock Minimo

Tabla de productos en alerta con SKU, almacen, disponible, minimo, diferencia, % restante. Boton 'Registrar entrada' por fila pre-llena el formulario de movimiento.

Stack

Detalles Tecnicos

ComponenteTecnologia
FrameworkNext.js 14 (App Router) + TypeScript 5 strict + noUncheckedIndexedAccess
UITailwind CSS v3 + shadcn/ui + react-hook-form + Zod resolvers
ORM + DBPrisma 5 + PostgreSQL 15 (docker-compose) + Decimal(12,4) para dinero
AuthAuth.js v5 + Argon2id (@node-rs/argon2) + JWT 8h
ValidacionZod 3 con .strict() y .trim()
Rate limiting@upstash/ratelimit + Upstash Redis (login 5/15min, mutaciones 30/min, exports 10/hora)
TestingVitest unit + integration + Playwright E2E
Loggingpino structured
Chartsrecharts
Export CSVpapaparse
Headers seguridadX-Content-Type-Options, X-Frame-Options DENY, Referrer-Policy strict-origin
Metricas reales

Resultados

4 (SUPERADMIN/ADMIN/ALMACENISTA/CONSULTA)

Roles con permisos granulares

5 (ENTRADA, SALIDA, AJUSTE, TRANSFERENCIA_SALIDA, TRANSFERENCIA_ENTRADA)

Tipos de movimiento

15 (RN-01 a RN-15)

Reglas de negocio testeadas

Si — noUncheckedIndexedAccess

Stack TypeScript strict

Cada mutacion + IP + userAgent

Auditoria

Unit + Integration + E2E

Coverage de tests

¿Llevas tu inventario en Excel y rezas para que nadie sobrescriba la celda?

Sistema multi-almacen con transferencias atomicas, kardex completo, alertas de stock minimo y auditoria. Sin Excel, sin perdidas.