MES / IIoT pour une usine de cuir
jiarun.techCommandes, opérations, déclarations de production, rémunération à la pièce et supervision machines. Un back-end unique alimente six surfaces : la console d'administration, la console plateforme, le site public, et trois terminaux Android en atelier.
LA CONTRAINTE
- Échelle cible : 100 sites × ~110 identités ≈ 10 000 comptes. Aucune lecture ne peut charger une collection entière côté client — pagination et filtrage serveur partout.
- Six clients, un seul contrat. Web, plateforme, site public, tablette d'atelier, mobile opérateur et écran de production doivent rester cohérents sans synchronisation manuelle.
- Données sensibles. Les salaires à la pièce ne doivent jamais franchir la frontière client, et aucune erreur serveur ne doit exposer de SQL, de trace ou de donnée personnelle.
L'ARCHITECTURE
Le contrat change → les six surfaces cassent à la compilation, pas en production.
TROIS DÉCISIONS QUE J'ASSUME
Pagination par curseur plutôt que par numéro de page, sur l'historique des commandes.
Pourquoi : l'historique est une UNION de plusieurs sources ;
un OFFSET par-dessus perd et duplique des lignes dès qu'une écriture arrive entre deux pages.
Le coût : plus de « aller à la page 12 », et un état de curseur à gérer côté client.
C'est un prix que j'ai accepté sciemment.
Re-plateformage de la console Vue 3 vers React 19.
Pourquoi : le modèle de lecture devait de toute façon être réécrit pour l'échelle — c'était la seule fenêtre où changer de plateforme coûtait peu. TanStack Query pour le cache et l'invalidation, TanStack Router pour un routage typé à la compilation, et la génération de types depuis l'OpenAPI. Le coût : une console Vue 3 fonctionnelle mise au rebut. Si le produit était resté sur un seul site, je serais resté sur Vue 3 — la migration ne se serait pas payée.
Contrat d'erreur : code métier stable + identifiant de trace opaque, jamais de prose serveur.
Pourquoi : les exceptions, le SQL, les valeurs soumises et les données personnelles
restent dans les journaux serveur sous un traceId ; le client ne reçoit qu'un code
et des arguments structurés qu'il traduit lui-même. Le support relie l'incident par le
traceId sans jamais exposer la donnée. Le coût : un adaptateur unique à maintenir
sur chaque client, et l'interdiction d'afficher un message renvoyé par le serveur.
QUALITÉ ET EXPLOITATION
- ~330 classes de tests back-end et tests d'architecture ArchUnit ; côté web Vitest + Testing Library + MSW, recette visuelle Playwright sur 4 résolutions.
- Budget de bundle tenu à 250 Ko gzip sur le JS initial, vérifié à chaque build
(
size-limit). - Internationalisation FormatJS avec pseudo-localisation et détection de dérive entre catalogues.
- Déploiement Docker Compose + Nginx + HTTPS, supervision Micrometer / Prometheus, tracing Zipkin, erreurs remontées dans Sentry.
- Frontière de secrets vérifiée mécaniquement par un hook de pré-commit — aucune valeur réelle dans les dépôts de code.