B2B PlatformLaravel 12React + FlutterMulti-channelWork in progress

Grossiste Pro

End-to-end B2B wholesale platform with an admin web panel, a Flutter mobile ordering app for clients, and a Laravel API with FEFO inventory, a strict order state machine, and multi-tier pricing.

3Platform clients
8+Laravel modules
FEFOInventory model
AR/FRBilingual catalog
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)

Overview

A complete B2B ordering ecosystem

Grossiste Pro is a full-stack B2B wholesale platform built for distributors and their clients. It replaces manual phone/WhatsApp ordering with a structured digital workflow - clients browse a bilingual catalog on the mobile app, place orders with their negotiated pricing tier, and the warehouse team processes everything from the admin panel with full inventory visibility.

The backend is a Laravel 12 modular monolith with 8 domain modules, a strict FEFO lot allocation system, an enforced order state machine, and HMAC-signed requests for both the web panel and the mobile app.

Objective

  • Give wholesale clients a self-service mobile app to browse the bilingual catalog, manage their cart, and place orders without calling the distributor

  • Replace spreadsheet-based stock tracking with a FEFO lot inventory system that prevents overselling, tracks expiry, and records every movement

  • Enforce a strict order lifecycle - from placement through processing, delivery, and optional return - with every transition logged and guarded by business rules

  • Support multi-tier pricing (retail, wholesale, semi-wholesale) and a POS channel for in-person onsite sales alongside the app channel

My Role

Solo full-stack - backend, admin panel, and mobile app

Backend Architecture & API

Designed and built the Laravel 12 modular monolith - 8 domain modules each with its own models, service layer, repository pattern, DTOs, and API routes. HMAC authentication, Spatie RBAC, Laravel Horizon for queues.

Stateful Inventory System

Implemented FEFO lot allocation with row-level locking and DB transactions to prevent race conditions. Lot fields track initial, available, and reserved quantities separately - expired lots are never allocated.

Order State Machine

Built an enforced transition graph (pending → processing → delivering → delivered → returned, + onsite channel) via an OrderTransitionService - invalid transitions are rejected, every transition is logged with the acting user.

Admin Web Panel

React + TypeScript SPA with TanStack Router, Zustand stores, React Hook Form + Zod. Covers products, orders, POS, inventory, purchases, returns, clients, suppliers, roles, pricing rules, and financial accounts.

B2B Mobile App

Flutter app for wholesale clients with Riverpod state management, GoRouter, Dio with auto-refresh interceptor, and flutter_secure_storage. Features catalog browsing, cart, order history, and AR/FR localization.

Bilingual Catalog

Arabic and French fields throughout - product names, descriptions, and category names all bilingual. Missing French translations are auto-generated via the Google Translate API so admins can add Arabic-first.

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

Core Features

More than a catalog - a full B2B workflow

Product Catalog

  • Arabic + French fields with auto-translation
  • Hierarchical categories with translations
  • Multi-tier pricing: retail, wholesale, semi
  • Spatie MediaLibrary image management
  • Lot tracking: initial, available, reserved qty
  • Bulk product import from template

Order Management

  • Strict state machine: 6 enforced transitions
  • Multi-channel: app (B2B) + onsite (POS)
  • FEFO lot allocation on order creation
  • Full status history per order (user + timestamp)
  • Credit limit validation for pay-later clients
  • Order returns with lot restock logic

Inventory & Lots

  • FEFO: first-expiry lots allocated first
  • Row-level locking prevents double-allocation
  • available_quantity never goes negative
  • Separate reserved vs available tracking
  • IN / OUT / RETURN movement log
  • Expired lot blocking at allocation time

B2B Mobile App

  • Flutter client app with Riverpod + GoRouter
  • Bilingual catalog (AR/FR) with images
  • Cart with real-time API sync
  • Order placement and history
  • Auto-refresh token with Dio interceptor
  • Secure token storage (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.

Inventory System

FEFO inventory with concurrency guarantees

This is not a CRUD stock field - it's a stateful inventory system. Each product lot tracks three separate quantities: initial (immutable reference), available (can be allocated), and reserved (held by active orders). FEFO ensures the earliest-expiry lot is always consumed first.

  • Race condition prevention

    All allocation runs inside DB transactions with SELECT FOR UPDATE. Two concurrent orders cannot over-allocate the same lot.

  • Partial lot allocation

    A single order item can span multiple lots - FEFO fills from the earliest-expiry lot first and overflows into the next.

  • Lifecycle per channel

    App orders reserve stock (available −qty, reserved +qty). Onsite/POS orders consume immediately (available −qty, OUT movement). Cancellations release reservations.

  • Full movement log

    Every stock change - IN (purchase), OUT (delivery), RETURN - is recorded as an inventory movement for audit and reporting.

Order State Machine

Every transition is enforced, logged, and guarded

Invalid transitions are rejected. Every valid transition appends a status log entry recording the acting user, the previous status, the new status, and a timestamp.

-pending

Place (app / wholesale)

Mobile client places order. Stock reserved via FEFO allocation.

Channel: app

-processing

Place (app / retail)

Retail client places order. Treated as processing immediately.

Channel: app · retail

-delivered

Place (onsite / POS)

Admin creates onsite order. Stock consumed immediately, no reservation.

Channel: onsite

pendingprocessing

Process

Admin confirms the order. Guards: no expired lot reservations.

Channel: admin

processingdelivering

Deliver

Releases reservations and records OUT movement in inventory.

Channel: admin

deliveredreturned

Return

Restores available_quantity and records RETURN movement on restockable items.

Channel: admin

Admin Panel

Full business management in one SPA

The React admin panel covers every module of the backend - from catalog and orders to inventory movements, purchase orders, returns, client CRM, and 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

Screenshots

A look inside the platform

Work in progress

Admin Panel

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

Mobile App

Product Catalog

Product Catalog

Shopping Cart

Shopping Cart

Architecture

Modular monolith with strict domain boundaries

The backend is a Laravel 12 modular monolith - not a CRUD app. Every module (Product, Order, Inventory, Cart, Client, Supplier, Purchase, Media) has its own service layer, repository interface, DTOs, and policies. Controllers are thin: validation + response only. All domain logic lives in services.

  • 8 Laravel modules - each self-contained with its own ServiceProvider
  • Repository pattern: all data access behind interfaces, bindings in providers
  • HMAC-signed requests: web and mobile use separate secrets to prevent spoofing
  • Laravel Horizon (Redis) for queue management - async jobs for media processing and emails
  • Three critical services that must never be bypassed: AllocationService, InventoryService, OrderTransitionService
  • React SPA and Flutter app both consume the same REST API - independent deployment

Key Takeaways

Domain invariants are code, not documentation

FEFO, stock non-negativity, and state machine transitions are enforced in services - not in controllers or comments. If the rule isn't in code, it doesn't exist.

Concurrency requires explicit design

Every stock operation needs a DB transaction and row-level locking. A high-traffic B2B platform will hit concurrent allocation - it has to be correct by design, not by luck.

Mobile client changes the UX contract

A mobile ordering app for B2B clients shifts the product entirely - the catalog UX, cart sync, and order status need to work offline-tolerant and fast on mobile, not just on desktop.

Bilingual is a data model choice

AR/FR fields on every entity - not a translation table that joins later - keeps queries simple and cache-friendly. Auto-translation removes the friction of entering both languages manually.

Work with me

Need a B2B platform built right?

Whether it's a wholesale ordering system, an inventory-heavy backend, or a mobile app for your clients - I help you design the right data model before writing a line of code.