// 05 · inventario
Stockhub
Gestión de inventario multi-tenant para cadenas de restaurantes y franquicias.
STACK
NestJS 11 · Next.js 16 · TypeScript · PostgreSQL 18 · Prisma 6 · Redis · JWT · TailwindCSS · ShadCN UI
STATUS
private
Stockhub es un SaaS multi-tenant serio para empresas que mueven mucho stock entre ubicaciones — cadenas de restaurantes, franquicias, operaciones multi-almacén. Es una reescritura desde cero sobre un stack moderno después de que la v1 validara el caso de uso.
Arquitectura
- Backend — servicios modulares en NestJS 11. Prisma 6 como ORM contra PostgreSQL 18. Redis para store de sesiones y caché. Autenticación JWT con rotación de refresh token.
- Frontend — Next.js 16 (App Router, Server Components), TypeScript estricto, TailwindCSS + ShadCN UI. Cliente Axios con interceptores para refrescar token.
- BBDD — 26 tablas en un esquema Postgres; multi-tenant aplicado en la capa de query con
companyIden cada lectura/escritura.
Funcionalidades
- Catálogo de productos — SKU + códigos de barras, productos simples y compuestos (recetas), fechas de caducidad, múltiples unidades de medida, categorización profunda.
- Multi-almacén — cualquier número de ubicaciones (almacén, restaurante, cocina), transferencias con aprobaciones, geolocalización por almacén.
- Monitorización en tiempo real — eventos de stock instantáneos, alertas de stock bajo, puntos de reorden automáticos, historial completo de movimientos.
- Órdenes de compra — workflow de aprobaciones, multi-proveedor, control de precios/costes, recepción parcial.
- RBAC — acceso basado en roles sobre una tabla de permisos dedicada con 43 permisos predefinidos. Los permisos se comprueban por ruta.
- Multi-sesión — sesiones activas listadas por usuario con capacidad de revocación remota en tiempo real.
- Auditoría — cada escritura queda registrada con quién/cuándo/qué/antes/después.
Un trozo del middleware de auth
// backend — guard de permisos en NestJS
@Injectable()
export class PermissionsGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(ctx: ExecutionContext): boolean {
const required = this.reflector.get<string[]>('permissions', ctx.getHandler());
if (!required) return true;
const { user } = ctx.switchToHttp().getRequest();
const userPerms = new Set(user.permissions);
return required.every((perm) => userPerms.has(perm));
}
}
// uso
@Get('products/:id')
@Permissions('inventory.products.read')
async getProduct(@Param('id') id: string) { /* ... */ }
Por qué una v2
La Stockhub original (Python + Jinja + WebSockets en crudo) validó la idea pero se quedó corta en el modelo de autorización y el frontend. La v2 conserva el aprendizaje del dominio y reconstruye sobre un stack que escala: tipado end-to-end, modular en servidor, basado en componentes en cliente.
26
tablas BBDD
43
permisos RBAC
multi
aislamiento tenant