← Tous les projets // étude de cas · 2026

NutriPetit

Symfony PHP Angular TypeScript PostgreSQL Doctrine ORM Docker PHPUnit PHPStan PHP-CS-Fixer Open Food Facts API PWA ZXing FrankenPHP Redis
Capture de NutriPetit

01Le besoin

En rayon, un parent n'a aucun outil fait pour son bébé. Yuka, le Nutri-Score et NOVA appliquent des barèmes pensés pour des adultes : une compote très sucrée peut y paraître correcte, un lait infantile y est mal classé.

NutriPetit répond à une question simple : « ce produit est-il adapté à mon enfant de 0 à 3 ans ? ». On scanne le code-barres, on obtient une note sur 100, expliquée règle par règle et adaptée à l'âge.

02Mes choix techniques

  • API Symfony 7.4 / PHP 8.4, PostgreSQL et Redis : toute la logique métier vit côté serveur, testable.
  • Données produits issues d'Open Food Facts, scoring basé sur les recommandations OMS, ANSES, EFSA et le règlement UE 2016/127.
  • Un moteur de règles déterministe : une vingtaine d'« évaluateurs » indépendants (risque d'étouffement, miel et botulisme, poissons contaminés, sucres et sel ajoutés, édulcorants, allergènes, fer, oméga-3…). Une règle = une classe = des tests.
  • L'IA est volontairement exclue du calcul : une note de santé doit être reproductible et vérifiable.
  • Front Angular en PWA installable (scan caméra, historique, profil bébé), qui consomme l'API en JSON. La vitrine et l'administration restent en Twig pour le référencement.
  • Caddy en point d'entrée unique : / pour la vitrine, /app pour l'Angular, /api pour l'API.

03La difficulté

Les laits infantiles ressortaient tous « au-dessus des seuils ». En comparant avec la table Ciqual de l'Anses, j'ai trouvé la cause : Open Food Facts stocke les valeurs de la poudre dans les champs censés contenir le lait reconstitué, soit environ 8 fois trop.

Plutôt que de bricoler un coefficient, j'ai sorti les laits du calcul nutriment par nutriment et écrit un calculateur dédié, basé sur ce qui distingue réellement deux laits : huile de palme, sucres ajoutés, prébiotiques, bio, protéines de soja. Chaque bonus et malus est rattaché à sa source réglementaire.

Deuxième difficulté, côté déploiement : le front et l'API sur deux domaines Railway différents bloquaient le cookie de session. J'ai réglé ça avec un reverse proxy : tout passe par un seul domaine, le cookie redevient first-party.

04Le résultat

  • En ligne sur un seul domaine : vitrine, application Angular et API.
  • 184 tests PHPUnit, PHPStan niveau 6 sans erreur, CI GitHub Actions à chaque push.

05En images

Projet suivant

Mon Avis Pro →

Poste, mission ou site à créer : parlons-en.