Projet
Mecanist, SaaS de gestion de garage
Devis, ordres de réparation, facturation électronique, rendez-vous et gestion de parc, pour les garages indépendants. Conçu, développé et exploité seul. mecanist.com
Étude de cas
- Rôle
- Conception, développement, exploitation
- Période
- Avril 2026 à aujourd'hui
- Stack
- Laravel 13, PHP 8.4, Vue 3, MySQL
- Statut
- En production
Un garage indépendant travaille encore beaucoup sur carnet et tableur : le devis part par SMS, l'ordre de réparation est une feuille dans le pare-brise, la facture se retape à la main. Mecanist tient toute cette chaîne dans un seul outil, du devis à la facture, en gardant la trace de chaque véhicule et de chaque client.
L'échéance de la facturation électronique française a rendu le sujet urgent pour ces structures : elles doivent désormais émettre et recevoir leurs factures dans un format structuré, via une plateforme agréée. C'est devenu le cœur technique du produit.
Arrondi de TVA
Les factures sont émises au format Factur-X : un PDF qui embarque sa propre représentation XML, conforme à la norme européenne EN 16931 et aux règles françaises vérifiées par le schematron de la plateforme.
- TVA, arrondi ligne par ligne
- —
- TVA, arrondi par taux
- —
- Écart
- —
Tout le calcul de TVA passe donc par un point unique du code, jamais recalculé sur place : quand une règle doit être vraie partout, elle n'est écrite qu'une fois.
Isolation multi-tenant
La même règle vaut pour l'isolation entre comptes : un garage ne doit jamais voir les données d'un autre. Plutôt que de répéter un filtre de propriétaire dans chaque requête, ce qui se retient mal et s'oublie une fois de trop, la contrainte vit en un seul endroit : un global scope Eloquent appliqué par un trait à tous les modèles concernés, alimenté par un middleware qui pose le locataire courant sur la requête. Une liste ou une lecture ne filtre donc jamais à la main.
La conséquence est testable, et elle est testée : la ressource d'un autre compte répond
404 plutôt que 403, pour ne pas confirmer son existence. Les
rares chemins qui échappent au scope, les requêtes brutes du tableau de bord et les
routes publiques de réservation, sont identifiés et filtrent explicitement.
Numérotation continue
Une numérotation de factures ne souffre pas de trou : l'administration ne l'admet pas.
Un numéro dérivé d'un count() de lignes casse dès que deux requêtes
émettent en même temps, ou dès qu'un document est supprimé.
Les numéros sont donc alloués par un compteur dédié, verrouillé en base le temps d'une transaction, par compte, par type de document et par année. Les brouillons n'obtiennent ni numéro ni date d'émission : ils ne les reçoivent qu'au moment de l'émission, ce qui permet de supprimer un brouillon sans laisser de trou derrière lui.
Un dernier détail du même ordre : un rendez-vous est un instant, une date d'échéance est une date civile, et les confondre décale un jour selon le fuseau du navigateur. Les instants sont donc stockés en UTC, les dates civiles restent des dates nues, et la réservation publique est le seul endroit qui raisonne dans le fuseau du garage, puisque le visiteur réserve à l'heure du garage et non à la sienne.
Les tests Pest couvrent ce qui coûte cher à casser : l'isolation entre comptes, l'émission des documents et les transitions d'état.
Stack
- Laravel 13
- PHP 8.4
- Vue 3
- Pinia
- Vue Router
- Tailwind CSS
- MySQL
- Sanctum
- Stripe
- Pest
- GitHub Actions