Calculer automatiquement les régimes d'une recette à partir de ses ingrédients #131
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte
Origine : ticket #3, puce 4 — « Faire en sorte que les régimes alimentaires associés aux recettes soient calculés automatiquement à partir des ingrédients ».
Aujourd'hui,
RecipeDietest explicitement manuel — le commentaire de schéma le dit : « a manual reminder set by whoever creates/edits the recipe, not computed from its ingredients » (schema.prisma:399-412). Choisi viaDietTagSelect(grille de cases à cocher, DietTagSelect.tsx) dansRecipeFormPage/RecipeImportForm, stocké tel quel parcreateRecipe/updateRecipe(diets: { create: input.dietIds.map(...) }, recipe.service.ts:705), affiché parDietBadges.La donnée pour le calcul existe déjà :
IngredientDiet(schema.prisma:614-635) — les régimes avec lesquels chaque ingrédient est compatible, seedés par catégorie avec overrides. Exposée viaIngredientView.diets(reference.service.ts:143-176, types/reference.ts:283-304).IngredientDietomet volontairementomnivore(tout ingrédient qualifie) etglutenFree(dérivable de l'absence de l'allergènegluten).Régimes seedés :
omnivore,vegetarian,vegan,pescatarian,glutenFree(catalog.diets.*).Comportement souhaité
Les régimes d'une recette sont dérivés : une recette suit un régime ssi tous ses ingrédients y sont compatibles.
glutenFree: cas spécial, dérivé des allergènes (cohérent avec la raison pour laquelleIngredientDietne le stocke pas).omnivore: jamais affiché comme tag (déjà la posture actuelle).isPlaceholder, sans lien diet) : ils cassent toute garantie ⇒ tant qu'une recette en contient un non promu, elle ne peut être certifiée sur aucun régime (afficher un « ? » / rien). À confirmer.Décision structurante (à trancher — bloquante)
Option A — Dérivé,
RecipeDietsupprimé.dietIdsdisparaît decreateRecipeSchema,DietTagSelectest retiré du formulaire,RecipeDietest droppé,RecipeSummaryView.dietsest calculé à la volée depuis les ingrédients. Le plus propre ; perd le tag manuel (peu de perte réelle : les 4 régimes non-triviaux sont tous décidables depuis les ingrédients) ; le filtre « convient au foyer » (suitableForHouseholdWhere, recipe.service.ts:318-359) doit passer d'undiets: { some: { dietId } }SQL à un filtre calculé.Option B — Calculé + surchargeable.
RecipeDietreste, pré-rempli/verrouillé par le calcul, avec possibilité de retirer un régime (jamais en ajouter un que les ingrédients contredisent). Plus de code, migration douce.Recommandation : Option A, alignée sur la formulation de la puce.
Logique pure partagée (
packages/shared)Colocalisée avec la logique recette, testable isolément (convention
specs/dev-conventions.md:matchXxx()pur séparé du DB-backed).Fichiers à toucher (Option A)
apps/api/prisma/schema.prisma— dropRecipeDiet+ relationRecipe.diets; migration.packages/shared—computeRecipeDiets;createRecipeSchemaretiredietIds(schemas/recipe.ts:56-67) ;RecipeSummaryView.dietsreste dans le type (toujours renvoyé, juste calculé).recipe.service.ts—toRecipeSummaryView/toRecipeViewcalculentdietsviacomputeRecipeDiets(ingredients)au lieu derecipe.diets.map(...)(recipe.service.ts:140-156) ;createRecipe/updateRecipene stockent plus rien ;assertDietsExistsupprimé ;suitableForHouseholdWhere+ le filtredietIdsdelistRecipesrepensés (post-filtre en mémoire, ou colonne dérivée — à trancher).apps/web— retirerDietTagSelectdeRecipeFormPage(RecipeFormPage.tsx:313) etRecipeImportForm(RecipeImportForm.tsx:423) ;DietBadgesinchangé ; retirerdietIdsdes payloads ; petite légende « calculé automatiquement » sur le détail.Découpage proposé
computeRecipeDiets+ tests, sans branchement.toRecipeView/toRecipeSummaryViewdériventdiets; les tags manuels existants sont ignorés à la lecture (transition).DietTagSelect/dietIds, dropRecipeDiet, refonte des filtressuitableForHousehold/dietIds.Tests (obligatoires, cf.
specs/dev-conventions.md)computeRecipeDiets(tous vegan ⇒ vegan+vegetarian ; un ingrédient viande ⇒ ∅ ; un placeholder ⇒ ∅ ; aucun ingrédient gluten ⇒ glutenFree) ;GET /recipes/:idrenvoie les régimes dérivés ;listRecipes({ dietIds })etsuitableForHouseholdfiltrent sur la base calculée ; non-régression liste de courses/planning.Documentation à mettre à jour
specs/batch-cooking-modele.md— suppression derecipe_diet, note sur la dérivation.specs/backend-architecture.md— section recettes (régimes calculés,computeRecipeDiets, impact filtres planning).Points restant à trancher en revue
suitableForHousehold/dietIds: post-filtre en mémoire (simple, lecture large) vs colonne dérivée maintenue à l'écriture (rapide, redondeRecipeDietsous un autre nom).🤖 Filed by Claude Code
Implémenté par la PR #137 (
feat/auto-recipe-diets), mergée dansmain(81b4a14). Option A retenue :RecipeDietdroppé (migration20260909130000_drop_recipe_diet),dietIdsretiré decreateRecipeSchema,DietTagSelectretiré des formulaires.RecipeView.diets/RecipeSummaryView.dietsdérivés viacomputeRecipeDietViews(@batch-cooking/shared, pur, testé). Placeholder ⇒ aucun régime certifié. FiltressuitableForHousehold/dietIdsdevenus des post-filtres en mémoire. Vérifié présent surmain.