📚 Documentation

MangeonsMieux · v1.12.0

← Retour au site

Présentation

MangeonsMieux analyse une liste de courses grâce à la base collaborative OpenFoodFacts. Pour chaque produit, l'application affiche le Nutri-Score, le niveau de transformation (NOVA), les additifs et les allergènes, puis calcule un score global du panier assorti de conseils. Aucune donnée n'est vendue, l'API OpenFoodFacts est gratuite et sans clé.

Comment saisir sa liste

Un produit par ligne. Chaque ligne peut être :

  • un nom de produit (ex : « Nutella », « yaourt nature ») ;
  • un code-barres (8 à 13 chiffres) — résultat exact et fiable.

Si tu colles depuis un tableau, la quantité et le prix (séparés par des tabulations) sont automatiquement ignorés pour la recherche, mais la ligne exacte reste affichée sous le produit.

Une analyse accepte au maximum 40 produits (garde-fou fixe, pour protéger le serveur et l'API OpenFoodFacts).

Trois autres moyens de remplir la liste :

  • Photo ou PDF (ticket de caisse, caddie, frigo, liste manuscrite, capture d'écran) : l'IA Mistral lit le document et en extrait les produits. Chaque document garde sa propre zone de texte modifiable, et plusieurs documents peuvent être ajoutés ; les doublons sont retirés du total.
  • Scanner de code-barres : via la caméra du téléphone ou de l'ordinateur.
  • Historique : les 20 dernières listes analysées sont gardées dans le navigateur (rien n'est envoyé au serveur) et se rechargent en un clic.

Comment fonctionne l'analyse

Pour chaque ligne, l'application procède ainsi :

  1. Code-barres ? → appel direct à la fiche produit (api/v3/product, la version recommandée de l'API).
  2. Article non alimentaire ? (lessive, papier toilette, mouchoirs…) → mis de côté, car OpenFoodFacts ne référence que l'alimentaire.
  3. Sinon, recherche par nom — voir le détail dans la section suivante : la requête est nettoyée (prix, quantité, formats comme 8x100g retirés), puis on interroge OpenFoodFacts en privilégiant les produits vendus en France.
  1. Rattrapage automatique des lignes non trouvées — voir la section dédiée plus bas.

Le rythme des appels dépend du moteur : 1 produit à la fois avec l'ancien moteur (celui utilisé aujourd'hui), 3 en parallèle avec le moteur moderne. Dans les deux cas il y a réessai automatique et un « coupe-circuit » qui garde l'appli rapide si OpenFoodFacts est momentanément indisponible. Les correspondances peu sûres sont signalées « ≈ approximative ».

Affichage : les produits s'affichent au fur et à mesure, et une barre de progression reste visible en bas de l'écran pendant les deux phases : « Analyse en cours… X / Y » puis « Rattrapage… X / Y ».

La recherche de produits en détail

Quand on cherche un produit par son nom, l'objectif est de proposer le bon produit, de préférence vendu en France. Voici les étapes, dans l'ordre :

Quel moteur OpenFoodFacts ? Il en existe deux : l'ancien (cgi/search.pl, celui du site OpenFoodFacts) et le moderne (plein-texte). L'application est aujourd'hui réglée sur l'ancien, jugé plus juste sur les libellés français. Elle ne bascule jamais sur le moderne : si l'ancien moteur ne répond pas (jusqu'à 4 tentatives de 15 s), le produit est marqué non trouvé, même s'il existe dans la base. Les étapes 2 et 3 ci-dessous (filtre France, repli mondial) ne concernent que le moteur moderne.

  1. Nettoyage de la requête : prix, quantités et formats (8x100g, 1,5 L…) sont retirés.
  2. Priorité France : on interroge d'abord OpenFoodFacts en ne demandant que les produits vendus en France, grâce au filtre countries_tags. La requête ressemble à nutella AND countries_tags:"en:france". On cherche ainsi dans tout le catalogue français, pas seulement les premiers résultats mondiaux.
  3. Repli mondial : si le filtre France donne moins de 5 résultats (produit étranger, ou recherche trop précise), on complète par la recherche mondiale (jusqu'à 100 produits), les français restant en tête. Un produit étranger reste donc trouvé.
  4. Choix du meilleur produit, par priorités successives (on ne départage au critère suivant qu'en cas d'égalité) :
    1. correspondance avec les mots recherchés ;
    2. vendu en France ;
    3. choix des utilisateurs (voir plus bas) ;
    4. popularité (produit souvent analysé) ;
    5. pertinence du moteur OpenFoodFacts.
  5. On charge enfin la fiche complète du produit gagnant (toutes les infos) via son code-barres.

Suggestions : jusqu'à 10 autres produits (avec image) sont proposés via le bouton « Autres suggestions », classés eux aussi France d'abord, puis ceux qui ont un Nutri-Score et un score NOVA. Chaque suggestion affiche son Nutri-Score, son NOVA et le drapeau du pays de vente.

L'app apprend des choix : quand on clique sur une suggestion pour remplacer un produit, ce choix est mémorisé (table mangeonsmieux_choices, terme → produit). La fois suivante, pour la même recherche, ce produit remonte en premier — pour tout le monde. La popularité globale (produits les plus souvent analysés) est également prise en compte.

Recherche par code-barres : si la ligne est un code-barres (8 à 13 chiffres), on va directement chercher la fiche exacte — c'est le résultat le plus fiable, sans ambiguïté.

Le rattrapage automatique des produits non trouvés

Un libellé de ticket de caisse est souvent illisible pour un moteur de recherche (PN CHOCO 4X125G). Quand une ligne ne donne rien, l'application tente donc un rattrapage, sans rien demander :

  1. l'IA reformule le libellé (abréviations développées, quantités et formats retirés) ;
  2. la recherche est relancée avec ce nouveau terme ;
  3. la ligne d'origine reste affichée, avec la mention ✨ IA et le terme proposé.

Le rattrapage a lieu une seule fois par produit (pas de boucle), et jamais sur un code-barres, qui est déjà sans ambiguïté. Une correction manuelle compte aussi comme rattrapage.

Tant qu'un rattrapage est en cours ou en attente, la carte affiche « 🔎 Recherche approfondie… ». Le verdict « Produit non trouvé » et le bouton « ✏️ Modifier la recherche » n'apparaissent qu'une fois toutes les tentatives épuisées.

Nutr'IA — l'avis du nutritionniste

Une fois le panier complet, un résumé (produits trouvés, Nutri-Score, NOVA, additifs, allergènes, note globale) est envoyé à l'IA, qui rend un avis rédigé : points forts, points de vigilance, suggestions de remplacement.

L'avis se déclenche tout seul, une seule fois, et seulement après la fin des rattrapages — pour porter sur le panier définitif et non sur une version incomplète.

Un chat permet ensuite de poser des questions libres sur le panier, avec des suggestions de relance. Aucune photo ni donnée personnelle n'est transmise : seulement la liste des produits et leurs notes.

Partager et recommencer

  • 🔗 Partager la page ouvre un menu à deux choix. Avec mon analyse : l'analyse est enregistrée et le lien (/?p=identifiant) la rouvre à l'identique. Sans mon analyse : on partage seulement l'adresse du site, aucune donnée n'est enregistrée. Sur mobile, le partage natif du téléphone est utilisé ; sinon le lien est copié.
  • ↻ Recommencer vide la liste, les documents envoyés (photos et leur texte) et les résultats, et revient en haut de page. L'historique des listes, lui, est conservé.

Le calcul du score

Chaque produit reçoit des points selon son Nutri-Score :

Nutri-ScoreABCDE
Points10080604020

Le score du panier est la moyenne de ces points, avec un malus jusqu'à −20 si beaucoup de produits sont ultra-transformés (NOVA 4). La note globale suit ces seuils : A (≥90), B (≥70), C (≥50), D (≥30), E (<30). Les produits sans Nutri-Score ne comptent pas dans la moyenne.

Détails par produit

Le bouton « Voir les détails » affiche toutes les informations d'OpenFoodFacts : tableau nutritionnel pour 100 g, repères nutritionnels (gras, sucres, sel…), ingrédients, additifs, allergènes et traces, Eco-Score, labels (bio…), régime (végétarien / végan / sans huile de palme), catégories, emballage et origine. Les liens produits pointent vers la version française fr.openfoodfacts.org.

Page Admin

La page /admin est protégée par une connexion Google (via Supabase), réservée à l'administrateur. Elle regroupe :

  • 📊 Statistiques : visiteurs uniques (total, du jour, par jour), analyses, produits, répartitions Nutri-Score, top produits ;
  • 🛒 Analyses : les analyses passées, rouvrables telles que le visiteur les a vues, suivies des documents envoyés (photos et PDF, conservés 30 jours puis effacés automatiquement) ;
  • 📄 Logs : journal des analyses avec le détail de chaque appel API (type, cible, statut, durée) ;
  • 🤖 IA : choix du modèle Mistral (c'est ici, pas dans Réglages) et prompts utilisés — lecture de document, nettoyage de liste, avis Nutr'IA, chat ;
  • 📚 Documentation : cette page.

Base de données (Supabase)

Les données sont stockées dans un projet Supabase, tables préfixées mangeonsmieux_. Voici le MCD (modèle conceptuel de données), c'est-à-dire la carte des tables et de leurs liens :

mangeonsmieux_visitorsvisitor_id (clé)first_seenlast_seenvisitsmangeonsmieux_visit_daysvisitor_id (clé)day (clé)mangeonsmieux_ticketsid (clé)kind : image | pdfpath (fichier stocké)byteslines_countvid → visiteurmangeonsmieux_analysesid (clé)created_atitems_countfound_countnotfound_countnonfood_countglobal_score / gradeshare_id → instantanémangeonsmieux_sharesid (clé, texte court)data (instantané JSON)created_atmangeonsmieux_productsid (clé)code (code-barres)namenutriscorecreated_atmangeonsmieux_choicesterm (clé)code (clé, code-barres)countupdated_atmangeonsmieux_settingskey (clé)value (JSON)updated_atmangeonsmieux_logsid (clé)created_atleveltypemessagedetail (JSON)1,N0,N0,1même code-barres OpenFoodFacts (pas de lien en base)

Comment lire ce schéma. Chaque cadre est une table ; en dessous du nom, ses colonnes principales. Les mentions (clé) repèrent l'identifiant. Les flèches se lisent « un visiteur peut avoir plusieurs documents » : 1,N = au moins un, 0,N = zéro ou plusieurs, 0,1 = au plus un. Le trait en pointillés n'est pas un lien : juste deux tables qui parlent du même code-barres. Les couleurs regroupent les usages : vert = visiteurs, orange = analyses, gris = recherche et technique.

À noter : il n'y a aucune clé étrangère en base. Les liens sont logiques : c'est l'application qui garantit la cohérence. C'est plus souple (une analyse survit à la suppression de son instantané) mais cela veut dire qu'aucun ménage n'est fait en cascade.

Le détail table par table :

  • mangeonsmieux_analyses — une ligne par analyse (compteurs, score, et le lien vers son instantané) ;
  • mangeonsmieux_shares — instantané complet d'une analyse : liste saisie, produits reconnus, notes et score. Créé pour chaque analyse et pour chaque lien de partage. Il se rouvre avec /?p=<identifiant>, ce qui permet à l'administration de revoir une analyse exactement telle que le visiteur l'a vue ;
  • mangeonsmieux_products — produits trouvés (top produits, répartitions) ;
  • mangeonsmieux_choices — choix des utilisateurs (terme → produit) pour affiner la recherche ;
  • mangeonsmieux_settings — réglages éditables (aujourd'hui : le modèle Mistral) ;
  • mangeonsmieux_visitors — un visiteur anonyme (identifiant tiré au hasard, date de première et dernière visite, nombre de visites) ;
  • mangeonsmieux_visit_days — un jour de visite par visiteur (pour la courbe « visiteurs par jour ») ;
  • mangeonsmieux_tickets — photos et PDF envoyés (fichier dans le stockage jvbm-tickets), effacés au bout de 30 jours ;
  • mangeonsmieux_logs — journal des appels API.

La sécurité repose sur des règles RLS : seul l'email admin peut lire les statistiques, les logs et modifier les réglages. Le suivi des visiteurs utilise un identifiant anonyme aléatoire (pas de cookie de pistage, aucune donnée personnelle).

Pile technique

  • Next.js 14 (Pages Router, JavaScript) + Tailwind CSS ;
  • @supabase/supabase-js pour l'authentification et la base ;
  • Données : OpenFoodFacts (API gratuite, sans clé) ;
  • IA : Mistral — modèle mistral-small-latest par défaut, modifiable dans l'onglet IA de l'admin. Il sert à la lecture des documents, le nettoyage de liste, le rattrapage des produits non trouvés et Nutr'IA. La clé reste côté serveur ;
  • Hébergement : VPS OVH (PM2 + Nginx, port 3007), prod sur mangeonsmieux.com.