Laroo — projet Laravel ERP

Solution ERP Laravel pour opérations, inventaire et productivité.

Laroo — projet Laravel ERP
Rôle
Fondateur, développeur full stack
Stack
Laravel 12 · Livewire 4
Architecture
24 modules installables
Statut
En ligne

Contexte

Odoo a fixé un modèle pour les ERP : des modules qu’on installe selon ses besoins, des règles d’accès enregistrement par enregistrement et plusieurs sociétés dans la même instance. Mais il impose Python et son propre framework. Laroo pose la question : peut-on retrouver cette logique modulaire dans l’écosystème Laravel ?

Défi métier

Livrer des modules ERP légers (stock, facturation, CRM) sur Laravel.

Solution

Un monolithe Laravel 12 découpé en 24 modules de style Odoo, chacun avec son manifeste module.json, ses dépendances et son service provider. Un gestionnaire installe les modules dans l’ordre de leurs dépendances. La logique métier vit dans une centaine de services reliés par des événements, et le multi-société passe par l’URL /app/{société}/… et des scopes Eloquent globaux.

Résultat

Un ERP en ligne avec back-office, portail client et API REST : CRM, ventes et achats, stock valorisé, comptabilité, RH, fabrication et qualité, marketing, et un Studio pour ajouter champs et vues sans code. Les écarts avec Odoo sont documentés module par module.

Mon rôle

Développeur lead

Architecture

Utilisateurs

  • Back-office /app/{société}
  • Portail client
  • API REST v1 (Sanctum)
  • Webhooks entrants

Application

  • Laravel 12 · Livewire 4
  • ModuleManager : 24 modules
  • 102 services · 120 policies
  • Scopes société et règles d’accès
  • Événements et listeners
  • File en base · 11 jobs · scheduler

Services externes

  • MySQL 8
  • Twilio · Vonage (SMS)
  • Resend (e-mail)
  • Sentry · PostHog
  • nginx · PHP-FPM (Docker)

Le parcours, étape par étape

  1. Société

    La requête /app/{société}/… vérifie que l’utilisateur y a accès, puis fixe la société courante.

  2. Commande

    La confirmation d’une commande client émet l’événement SaleOrderConfirmed.

  3. Confirmation

    Un listener met en file l’e-mail de confirmation au client.

  4. Stock

    La validation du mouvement de stock calcule le coût en FIFO ou en coût moyen et met à jour les quantités, dans une seule transaction.

  5. Réactions

    Des listeners créent les écritures de valorisation et, si besoin, les contrôles qualité.

  6. Comptabilité

    La comptabilisation vérifie l’équilibre débit-crédit à un centime près, puis passe l’écriture en « comptabilisée ».

Modèle de données

Les entités principales, leurs champs clés et leurs relations.

Company

  • name · slug
  • email
  • timezone
  • 1—n User
  • 1—n SaleOrder
  • 1—n AccountMove

Product

  • default_code · type
  • list_price · standard_price
  • qty_available
  • valorisation FIFO ou coût moyen
  • 1—n StockMove
  • 1—n StockQuant

SaleOrder

  • partner_id
  • order_ref
  • state
  • amount_total
  • 1—n SaleOrderLine
  • 1—n AccountMove

StockMove

  • product_id
  • location_from_id · location_dest_id
  • quantity · state
  • n—1 Location
  • 1—n StockValuationLayer

StockQuant

  • product_id · location_id
  • quantity
  • reserved_quantity
  • n—1 Product
  • n—1 Location

AccountMove

  • journal_id · ref · date
  • state · move_type
  • 1—n AccountMoveLine (débit, crédit)
  • n—1 AccountJournal

RecordRule

  • model
  • role_id
  • domain_expression
  • company_id
  • n—1 Role

Module

  • nom technique
  • dépendances
  • état d’installation

Fiche technique complète

Langages
PHP 8.4, JavaScript
Framework
Laravel 12
Front
Blade (742 vues), Livewire 4, Tailwind 4, Vite 7, Chart.js
Administration
Back-office maison de style Odoo, espace administrateur de plateforme
Base de données
MySQL 8, SQLite en mémoire pour les tests
Files et planificateur
File en base, worker Docker, 11 jobs ; tâches planifiées : actions automatisées, écritures récurrentes, reconnaissance de revenu, relances de paiement
Authentification et rôles
Session et Sanctum, rôles et permissions, 120 policies, règles d’accès par enregistrement
Multi-société
Scope global CompanyScope, enregistrements partageables entre sociétés
Intégrations
SMS Twilio et Vonage, e-mail Resend, webhooks entrants vérifiés, webhooks sortants signés HMAC-SHA256
Hébergement
Docker multi-étapes (nginx, PHP-FPM 8.4), Supervisor
CI/CD
GitHub Actions : PHPUnit et PHPStan sur PHP 8.4, hook pre-push
Tests
PHPUnit 11 (274 fichiers de tests), Playwright
Qualité
PHPStan niveau 6, Pint, Conventional Commits
Observabilité
Sentry, PostHog, journal d’activité, journal d’audit
Langues
Français et anglais complets, espagnol et néerlandais partiels

Fonctionnalités clés

  • CRM

    Pipeline kanban, scoring des prospects et règles d’affectation.

  • Ventes et achats

    Commandes, réceptions, commandes-cadres et listes de prix.

  • Stock

    Mouvements, lots, réapprovisionnement, valorisation FIFO ou au coût moyen.

  • Comptabilité

    Écritures, rapprochement bancaire, avoirs, écritures récurrentes, relances.

  • RH et fabrication

    Congés, présences, paie ; nomenclatures, ordres de fabrication, contrôles qualité.

  • Studio

    Champs personnalisés, vues et actions automatisées sans code.

Problèmes résolus

  1. Isolation entre sociétés

    ProblèmeChaque requête doit ne voir que les données de la société courante, sauf ce qui est explicitement partagé.

    SolutionUn scope global qui accepte aussi les enregistrements partagés via une table dédiée.

  2. Numérotation concurrente

    ProblèmeDeux factures créées en même temps pouvaient recevoir le même numéro.

    SolutionVerrou de ligne (lockForUpdate) sur la séquence.

  3. Stock et valeur cohérents

    ProblèmeUn mouvement validé à moitié laissait les quantités et la valorisation divergentes.

    SolutionConsommation des couches de coût et mise à jour des quantités dans une seule transaction.

  4. URL par société

    ProblèmeLa société courante vivait seulement en session, ce qui rendait les liens ambigus.

    SolutionRefonte du routage : la société passe dans l’URL et dans les valeurs par défaut des routes.

  5. Durcissement

    ProblèmeDes contrôleurs sensibles ne vérifiaient pas toujours les droits.

    SolutionAutorisation systématique, Form Requests et vérification des signatures de webhooks.

Choix techniques

Choix Pourquoi
Modules à la manière d’Odoo Un manifeste avec dépendances : on n’installe que ce dont on a besoin, dans le bon ordre.
Règles d’accès par domaine Un analyseur d’expressions inspiré des domaines Odoo filtre les enregistrements par rôle.
Livewire plutôt qu’une SPA Des centaines d’écrans de gestion, rendus côté serveur, sans API à maintenir pour chacun.
Observabilité désactivable Sans DSN, Sentry est coupé sans aucun appel réseau.

Chronologie

  1. Mars 2026 Premier commit du dépôt actuel, schéma ERP
  2. Mars 2026 Services, policies, API et Studio
  3. Mai 2026 Comptabilité, ventes, stock, fabrication et qualité
  4. Juin 2026 Marketing SMS et audit de sécurité
  5. Août 2026 Sentry, PostHog et Resend
  6. Août 2026 Routage par société

En chiffres

24
modules
253
modèles
306
migrations
1 256
routes

Relevé dans le code source et l’historique Git du projet le 8 octobre 2026. Aucun chiffre d’usage ou de revenu n’est publié.

Projets similaires

SaaS
oct. 2024 — présent
Vetzy — projet Laravel SaaS
Plateforme SaaS vétérinaire de prise de rendez-vous pour cliniques et propriétaires d’animaux.
PHP, Laravel, Livewire, TailwindCSS, SaaS
Voir le projet
SaaS
janv. 2024 — présent
StreamCrea — tableau de bord des créateurs
Synchro Twitch, YouTube et Kick, publication multi-réseaux et blog pour abonnés.
PHP, Laravel, Livewire, Stripe
Voir le projet
SaaS
janv. 2022 — déc. 2022
MissionsCMS — projet Web App
Système de gestion de missions avec suivi et tableaux de bord.
Laravel, Livewire, Alpine.js, TailwindCSS
Voir le projet
SaaS
sept. 2025 — présent
Lodate — projet Web App
Système de gestion de rendez-vous avec rappels et interface épurée.
Laravel, Livewire, Alpine.js, TailwindCSS
Voir le projet

Disponible pour missions PHP / Laravel / WordPress / Silverstripe en Belgique et remote EU.