B2B PlatformLaravel 12React + FlutterMulti-channelEn desarrollo

Grossiste Pro

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.

3Clientes de la plataforma
8+Módulos Laravel
FEFOModelo de inventario
AR/FRCatálogo bilingüe
Grossiste Pro · Admin Panel
Admin Panel
React SPA

284K

Revenue

41

Orders

98%

Stock

ORD-0041

Atlas Import Co.

delivering

ORD-0040

Souss Export Ltd

processing

ORD-0039

Maghreb Transit

delivered
Mobile App
Flutter

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

Un ecosistema de pedidos B2B completo

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

Full-stack en solitario - backend, panel de administración y aplicación móvil

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

Laravel 12PHP 8.2+MySQLRedisLaravel HorizonSpatie PermissionSpatie MediaLibraryLaravel SanctumHMAC AuthFEFO AllocationOrder State MachineAuto-translation (Google)Repository PatternService LayerDTOs

Admin Panel

ReactTypeScriptViteTanStack RouterZustandReact Hook FormZodAxiosi18n (EN/FR/AR)POS mode

Mobile App

FlutterRiverpodGoRouterDioflutter_secure_storageAR/FR locale

Funciones principales

Más que un catálogo - un flujo de trabajo B2B completo

Catálogo de productos

  • Campos en árabe y francés con traducción automática
  • Categorías jerárquicas con traducciones
  • Precios multinivel: minorista, mayorista, semi
  • Gestión de imágenes con Spatie MediaLibrary
  • Seguimiento de lotes: cantidad inicial, disponible y reservada
  • Importación masiva de productos desde plantilla

Gestión de pedidos

  • Máquina de estados estricta: 6 transiciones forzadas
  • Multicanal: app (B2B) + presencial (POS)
  • Asignación de lotes FEFO al crear el pedido
  • Historial completo de estados por pedido (usuario + marca de tiempo)
  • Validación del límite de crédito para clientes con pago aplazado
  • Devoluciones de pedidos con lógica de reabastecimiento de lotes

Inventario y lotes

  • FEFO: los lotes con caducidad más próxima se asignan primero
  • Bloqueo a nivel de fila evita la doble asignación
  • available_quantity nunca llega a negativo
  • Seguimiento separado de cantidad reservada vs disponible
  • Registro de movimientos IN / OUT / RETURN
  • Bloqueo de lotes vencidos en el momento de la asignación

Aplicación móvil B2B

  • App Flutter con Riverpod + GoRouter
  • Catálogo bilingüe (AR/FR) con imágenes
  • Carrito con sincronización en tiempo real con la API
  • Realización de pedidos e historial
  • Token de actualización automática con interceptor Dio
  • Almacenamiento seguro de tokens (flutter_secure_storage)
Inventory · Lot Management

Product: Huile Olive Extra — Lot allocations (FEFO)

LOT-2024-001

Expires 2025-03-15

exhausted

200

Initial

0

Available

0

Reserved

LOT-2024-018

Expires 2025-09-20

active

500

Initial

140

Available

60

Reserved

LOT-2025-003

Expires 2026-06-10

queued

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

Inventario FEFO con garantías de concurrencia

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

Cada transición es forzada, registrada y protegida

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.

-pending

Crear (app / mayorista)

El cliente móvil realiza el pedido. Stock reservado mediante asignación FEFO.

Channel: app

-processing

Crear (app / minorista)

El cliente minorista realiza el pedido. Se trata como en procesamiento de inmediato.

Channel: app · retail

-delivered

Crear (presencial / POS)

El administrador crea un pedido presencial. El stock se consume inmediatamente, sin reserva.

Channel: onsite

pendingprocessing

Procesar

El administrador confirma el pedido. Guardias: sin reservas de lotes vencidos.

Channel: admin

processingdelivering

Entregar

Libera las reservas y registra el movimiento OUT en el inventario.

Channel: admin

deliveredreturned

Devolver

Restaura available_quantity y registra el movimiento RETURN en los artículos reponibles.

Channel: admin

Panel de administración

Gestión empresarial completa en una sola SPA

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.

Dashboard
Products
Categories
Orders
POS (Onsite Sales)
Inventory & Movements
Purchases
Returns
Clients
Suppliers
Payments
Financial Accounts
Pricing Rules
Tax & Settings
Users & Roles (RBAC)
Print Settings

Capturas de pantalla

Un vistazo a la plataforma

En desarrollo

Panel de administración

Grossiste Pro · Dashboard
Dashboard

Dashboard

Grossiste Pro · Orders
Order Management

Order Management

Grossiste Pro · Order #0041
Order Details

Order Details

Grossiste Pro · Products
Product Details

Product Details

Grossiste Pro · Inventory
Inventory

Inventory

Grossiste Pro · Settings
Print Settings

Print Settings

Grossiste Pro · لوحة التحكم
Arabic Support

Arabic Support

Aplicación móvil

Product Catalog

Product Catalog

Shopping Cart

Shopping Cart

Arquitectura

Monolito modular con límites de dominio estrictos

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.

  • 8 módulos Laravel - cada uno autocontenido con su propio ServiceProvider
  • Patrón repositorio: todo el acceso a datos detrás de interfaces, bindings en providers
  • Solicitudes firmadas con HMAC: web y móvil usan secretos separados para evitar suplantación
  • Laravel Horizon (Redis) para gestión de colas - trabajos asíncronos para procesamiento de medios y emails
  • Tres servicios críticos que nunca deben saltarse: AllocationService, InventoryService, OrderTransitionService
  • La SPA React y la app Flutter consumen la misma API REST - despliegue independiente

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

¿Necesitas una plataforma B2B bien construida?

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.