Portrait de Patrice GADEGBEPatrice GADEGBE

Sanu

Sanu est un progiciel de gestion et de caisse destiné au commerce de détail en Afrique de l’Ouest, que j’ai fondé et dont j’assure l’essentiel du développement depuis janvier 2025.

Rôle
Fondateur et développeur principal, en charge du produit, de l’architecture et du développement, avec deux autres développeurs
Période
De janvier 2025 à aujourd’hui
État
En développement. En développement, déployé en préproduction
Technologies
Java 21, Spring Boot 4, Spring Modulith, PostgreSQL, React, Flutter
Dépôts
Sept
Architecture d’ensemble de SanuTrois interfaces, la caisse en Flutter, le backoffice et la console en React, appellent en HTTPS un proxy nginx. Celui-ci transmet les appels ordinaires par /api et le canal temps réel par /api/ws à une API Spring Boot découpée en modules, laquelle s’appuie sur une base PostgreSQL.CaisseFlutter, terminal enregistréBackofficeReact, 72 pagesConsoleReact, administrationnginxproxy inverseAPISpring Boot 4, Java 21, Spring Modulithregistersalesorderpurchasingstocktreasuryaccesset douze autres modules, dont les frontièressont vérifiées à chaque exécution des testsPostgreSQLmigrations FlywayHTTPS/api/api/wsWebSocket
Figure 1. Architecture d’ensemble de Sanu en septembre 2026. Le trait interrompu désigne le canal temps réel, qui circule dans les deux sens.

Contexte

Une première version de Sanu, composée d’une API Django et d’une application Flutter, a été développée à partir de janvier 2025. La version actuelle, engagée en septembre 2026, sépare une API écrite en Java, un backoffice et une console d’administration en React, et une application de caisse en Flutter.

Elle a été précédée d’un travail de spécification, qui a produit un manuel d’utilisation organisé par profil et par module, publié sous la forme d’un site statique, ainsi qu’un prototype navigable des écrans. Ce prototype tient lieu de référence pour les trois interfaces, si bien qu’aucune d’elles ne décide seule de la forme d’un écran.

Écran de vente du prototype : à gauche le catalogue de boissons avec ses conditionnements et ses prix en francs CFA, à droite la commande en cours, vide, et les modes de règlement.
Figure 2. Écran de vente du prototype, qui sert de référence à l’application de caisse.
Tableau de bord des ventes et de la caisse : chiffre d’affaires du jour, ventes par heure, encaissements par moyen de paiement, produits les plus vendus et caisses ouvertes.
Figure 3. Tableau de bord du backoffice dans le prototype, avec des données fictives.

Problème

La difficulté principale tient au modèle d’accès. Une même personne peut appartenir à plusieurs sociétés, chaque société compose ses profils à partir de codes de permission, et un poste de caisse partagé entre plusieurs vendeurs doit permettre une connexion rapide par code PIN sans que cette facilité soit ouverte à n’importe quel appareil.

Trois interfaces écrites dans deux langages consomment par ailleurs la même API, ce qui suppose que les règles d’accès ne soient énoncées qu’à un seul endroit, faute de quoi elles finiraient par diverger d’une interface à l’autre.

Réponse apportée

Modèle d’accès

Le serveur résout les permissions à chaque requête, à partir des appartenances de la personne et du profil que la société lui a attribué. Le code PIN n’est accepté que depuis un terminal préalablement enregistré, et une personne ne dispose que d’une session à la fois. Ces décisions sont consignées dans un document d’architecture, que les trois interfaces prennent pour contrat.

L’API est une application Spring Boot unique, découpée en modules dont Spring Modulith vérifie les frontières à chaque exécution des tests ; la figure 1 en donne la disposition générale.

Canal temps réel

Le canal temps réel passe par un point d’accès WebSocket, /api/ws, ce qui suppose de lui réserver un emplacement dans la configuration de nginx. Sans transmission des en-têtes de mise à niveau, le proxy répond 400 et aucun client ne se connecte ; avec le délai de lecture par défaut, de soixante secondes, un canal inactif est coupé chaque minute. L’emplacement est déclaré avant celui de /api, afin que ces en-têtes ne soient pas posés sur les appels ordinaires.

location /api/ws {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;
}
Extrait 1. Emplacement nginx réservé au canal temps réel.

Méthode

La nouvelle version est écrite pour l’essentiel avec un assistant, Claude Code, que je conduis par rôles : un architecte arrête la structure, un développeur écrit à l’intérieur de ces règles, un testeur rend un verdict et un responsable du déploiement livre. Chaque rôle transmet au suivant un bloc de faits sourcés, et un travail n’est tenu pour terminé qu’une fois la commande de vérification passée. Sur les quatre dépôts de code, la plupart des commits portent la cosignature de l’assistant. Ces rôles sont décrits dans l’étude du dépôt de plugins.

Vérification

Chaque dépôt possède une commande unique de vérification, exécutée à l’identique sur le poste de développement et dans le pipeline, qui enchaîne le contrôle du formatage, la compilation et les tests. Côté serveur, les tests d’intégration s’exécutent sur une base PostgreSQL réelle, démarrée dans un conteneur.

La couverture exigée est de 100 % sur les paquets de domaine et de données de l’application Flutter. Elle a été assouplie pour les paquets de présentation, après qu’une fonctionnalité eut demandé plus de temps en tests de widgets qu’en développement.

Tableau 1. Dépôts du projet au 1er octobre 2026.
DépôtContenuTechnologies
sanu-backend-javaAPISpring Boot, PostgreSQL
sanu-app-reactBackofficeReact, Vite
sanu-apps-flutterApplication de caisseFlutter
sanu-app-prototypePrototype des écransJavaScript
sanu-erp-specificationManuel et carnet de produitMkDocs
sanu-console-reactConsole d’administrationReact, Vite
sanu-apps-portalPortail d’accès aux servicesJavaScript

Limites et perspectives

Le backoffice atteint soixante-douze pages, dont la plupart restent des écrans d’attente tant que les lots fonctionnels correspondants ne sont pas traités. L’application de caisse couvre pour l’heure la vente au comptoir, et les applications destinées à la livraison et aux clients ne sont pas commencées.

La nouvelle version n’est par ailleurs déployée qu’en préproduction, si bien que les choix décrits ici n’ont pas encore été éprouvés par un usage réel. Il conviendra de reprendre cette étude une fois les premiers points de vente équipés, afin d’y consigner ce que l’usage aura confirmé ou démenti.

Retour aux autres projets