Plataforma B2B de comercio mayorista integral con un panel web de administración, una aplicación móvil Flutter para pedidos de clientes, y una API Laravel con inventario FEFO, una máquina de estados de pedidos estricta y precios multinivel.
284K
Revenue
41
Orders
98%
Stock
ORD-0041
Atlas Import Co.
ORD-0040
Souss Export Ltd
ORD-0039
Maghreb Transit
Browse catalog
AR/FR · 3 price tiers
Cart & checkout
Real-time sync
Order history
Status tracking
FEFO allocation
Lot 001 → 002 → 003 (expiry order)
Descripción general
Grossiste Pro es una plataforma B2B de comercio mayorista full-stack diseñada para distribuidores y sus clientes. Reemplaza los pedidos manuales por teléfono o WhatsApp con un flujo de trabajo digital estructurado: los clientes navegan por un catálogo bilingüe en la aplicación móvil, realizan pedidos con su nivel de precios negociado, y el equipo de almacén gestiona todo desde el panel de administración con visibilidad total del inventario.
El backend es un monolito modular Laravel 12 con 8 módulos de dominio, un sistema estricto de asignación de lotes FEFO, una máquina de estados de pedidos forzada y solicitudes firmadas con HMAC tanto para el panel web como para la aplicación móvil.
Objetivo
Ofrecer a los clientes mayoristas una aplicación móvil de autoservicio para navegar por el catálogo bilingüe, gestionar su carrito y realizar pedidos sin llamar al distribuidor
Reemplazar el seguimiento de stock en hojas de cálculo por un sistema de inventario de lotes FEFO que evita el sobrestock, rastrea la caducidad y registra cada movimiento
Aplicar un ciclo de vida de pedido estricto - desde la colocación hasta el procesamiento, entrega y devolución opcional - con cada transición registrada y protegida por reglas de negocio
Soportar precios multinivel (minorista, mayorista, semi-mayorista) y un canal POS para ventas presenciales en el establecimiento junto con el canal de la aplicación
Mi rol
Arquitectura de backend y API
Diseñé y construí el monolito modular Laravel 12 - 8 módulos de dominio, cada uno con sus propios modelos, capa de servicios, patrón repositorio, DTOs y rutas API. Autenticación HMAC, RBAC Spatie, Laravel Horizon para colas.
Sistema de inventario con estado
Implementé la asignación de lotes FEFO con bloqueo a nivel de fila y transacciones de base de datos para evitar condiciones de carrera. Los campos de lote rastrean cantidades iniciales, disponibles y reservadas por separado - los lotes vencidos nunca se asignan.
Máquina de estados de pedidos
Construí un grafo de transiciones forzadas (pendiente → procesando → entregando → entregado → devuelto, + canal presencial) a través de un OrderTransitionService - las transiciones inválidas son rechazadas, cada transición queda registrada con el usuario actuante.
Panel web de administración
SPA React + TypeScript con TanStack Router, stores Zustand, React Hook Form + Zod. Cubre productos, pedidos, POS, inventario, compras, devoluciones, clientes, proveedores, roles, reglas de precios y cuentas financieras.
Aplicación móvil B2B
Aplicación Flutter para clientes mayoristas con gestión de estado Riverpod, GoRouter, Dio con interceptor de actualización automática y flutter_secure_storage. Incluye navegación por catálogo, carrito, historial de pedidos y localización AR/FR.
Catálogo bilingüe
Campos en árabe y francés en toda la aplicación - nombres de productos, descripciones y categorías completamente bilingües. Las traducciones al francés faltantes se generan automáticamente con la API de Google Translate para que los administradores puedan añadir primero en árabe.
Backend
Admin Panel
Mobile App
Funciones principales
Product: Huile Olive Extra — Lot allocations (FEFO)
LOT-2024-001
Expires 2025-03-15
200
Initial
0
Available
0
Reserved
LOT-2024-018
Expires 2025-09-20
500
Initial
140
Available
60
Reserved
LOT-2025-003
Expires 2026-06-10
300
Initial
300
Available
0
Reserved
FEFO rule: Lot-2024-018 is allocated first — its expiry date is earliest among non-exhausted lots. available_quantity is the single source of truth for allocation.
Sistema de inventario
Esto no es un campo de stock CRUD - es un sistema de inventario con estado. Cada lote de producto rastrea tres cantidades separadas: inicial (referencia inmutable), disponible (puede asignarse) y reservada (retenida por pedidos activos). FEFO garantiza que el lote con caducidad más próxima siempre se consuma primero.
Prevención de condiciones de carrera
Toda la asignación se ejecuta dentro de transacciones de base de datos con SELECT FOR UPDATE. Dos pedidos concurrentes no pueden sobreasignar el mismo lote.
Asignación parcial de lotes
Un único artículo de pedido puede abarcar varios lotes - FEFO rellena desde el lote con caducidad más próxima y desborda al siguiente.
Ciclo de vida por canal
Los pedidos de la app reservan stock (disponible −cant, reservado +cant). Los pedidos presenciales/POS consumen inmediatamente (disponible −cant, movimiento OUT). Las cancelaciones liberan las reservas.
Registro completo de movimientos
Cada cambio de stock - IN (compra), OUT (entrega), RETURN - queda registrado como un movimiento de inventario para auditoría e informes.
Máquina de estados de pedidos
Las transiciones inválidas son rechazadas. Cada transición válida añade una entrada al registro de estado con el usuario actuante, el estado anterior, el nuevo estado y una marca de tiempo.
Crear (app / mayorista)
El cliente móvil realiza el pedido. Stock reservado mediante asignación FEFO.
Channel: app
Crear (app / minorista)
El cliente minorista realiza el pedido. Se trata como en procesamiento de inmediato.
Channel: app · retail
Crear (presencial / POS)
El administrador crea un pedido presencial. El stock se consume inmediatamente, sin reserva.
Channel: onsite
Procesar
El administrador confirma el pedido. Guardias: sin reservas de lotes vencidos.
Channel: admin
Entregar
Libera las reservas y registra el movimiento OUT en el inventario.
Channel: admin
Devolver
Restaura available_quantity y registra el movimiento RETURN en los artículos reponibles.
Channel: admin
Panel de administración
El panel de administración React cubre todos los módulos del backend - desde el catálogo y los pedidos hasta los movimientos de inventario, órdenes de compra, devoluciones, CRM de clientes y RBAC.
Capturas de pantalla
Panel de administración

Dashboard

Order Management

Order Details

Product Details

Inventory

Print Settings

Arabic Support
Aplicación móvil

Product Catalog

Shopping Cart
Arquitectura
El backend es un monolito modular Laravel 12 - no una aplicación CRUD. Cada módulo (Producto, Pedido, Inventario, Carrito, Cliente, Proveedor, Compra, Media) tiene su propia capa de servicios, interfaz de repositorio, DTOs y políticas. Los controladores son delgados: solo validación y respuesta. Toda la lógica de dominio reside en los servicios.
Conclusiones clave
Las invariantes de dominio son código, no documentación
FEFO, la no negatividad del stock y las transiciones de la máquina de estados se aplican en los servicios - no en los controladores ni en los comentarios. Si la regla no está en el código, no existe.
La concurrencia requiere diseño explícito
Cada operación de stock necesita una transacción de base de datos y bloqueo a nivel de fila. Una plataforma B2B de alto tráfico encontrará asignaciones concurrentes - tiene que ser correcta por diseño, no por suerte.
El cliente móvil cambia el contrato de UX
Una app de pedidos móvil para clientes B2B transforma el producto por completo - la UX del catálogo, la sincronización del carrito y el estado del pedido deben funcionar de forma tolerante a desconexiones y rápida en móvil, no solo en escritorio.
El bilingüismo es una decisión del modelo de datos
Campos AR/FR en cada entidad - no una tabla de traducción que se une más tarde - mantiene las consultas simples y eficientes en caché. La traducción automática elimina la fricción de introducir ambos idiomas manualmente.
Trabaja conmigo
Ya sea un sistema de pedidos mayoristas, un backend con inventario intensivo o una aplicación móvil para tus clientes - te ayudo a diseñar el modelo de datos correcto antes de escribir una línea de código.