feat(recipes): régimes calculés depuis les ingrédients (#131) #137

Merged
kyuno merged 1 commit from feat/auto-recipe-diets into main 2026-09-09 15:20:16 +02:00
Owner

Contexte

Closes #131 (puce 4 de #3). RecipeDiet était explicitement manuel (« a manual reminder … not computed from its ingredients »). La donnée pour le calcul existait déjà : IngredientDiet (compat par ingrédient, exposée via IngredientView.diets). Option A retenue (validée) : dérivé pur, table supprimée.

Changements

Logique pure — packages/shared/src/logic/recipe-diets.ts : computeRecipeDietViews(ingredients, glutenFreeDiet) → un régime vegetarian/vegan/pescatarian ssi tous les ingrédients y sont compatibles ; glutenFree ssi aucun ingrédient ne porte l'allergène gluten ; [] si la recette a ≥ 1 ingrédient placeholder. DietViews empruntés aux ingrédients eux-mêmes (glutenFree passé par l'appelant).

Modèle — RecipeDiet droppé (Recipe.diets / Diet.recipes retirés). Migration 20260909130000_drop_recipe_diet : DROP TABLE, aucune donnée à conserver.

Contrat — createRecipeSchema perd dietIds ; RecipeSummaryView.diets reste DietView[] (doc mise à jour : calculé).

API recipe.service.ts — recipeInclude retire le diets de niveau recette (garde IngredientDiet sur les ingrédients) ; toRecipeSummaryView/toRecipeView calculent diets ; loadReferenceDiets/loadGlutenFreeDiet mémoïsés. suitableForHouseholdWhere → suitableForHousehold renvoie { allergenWhere (SQL), requiredDietKeys } ; listRecipes applique la contrainte régime foyer et le filtre dietIds en post-filtre sur diets calculé (omnivore = pas de contrainte). assertDietsExist + DIET_NOT_FOUND sur la création recette supprimés (le code d'erreur reste — utilisé par PATCH /profile diet).

Frontend — RecipeFormPage + RecipeImportForm : DietTagSelect, dietIds, getDiets retirés. recipe-import-draft.ts idem. DietBadges inchangé. RecipePickerDialog garde son filtre régime (marche via le post-filtre).

Vérification locale

pnpm lint ✓ · pnpm build ✓ (Prisma régénéré) · Cypress : recipe-form.feature 10/10 (nouveau scénario « pas de sélecteur de régime »), recipes.cy.ts 12/12, recipe-sources.feature 7/7, recipes/planning régression OK. Mocha non exécutable ici — recipe-diets.test.ts (7 cas purs) + recipe.test.ts réécrit (4 nouveaux cas régimes calculés, 2 tests DIET_NOT_FOUND retirés) + dietIds retiré des fixtures recipe-placeholder/sources — à valider en CI.

🤖 Generated with Claude Code

## Contexte `Closes #131` (puce 4 de #3). `RecipeDiet` était **explicitement manuel** (« a manual reminder … not computed from its ingredients »). La donnée pour le calcul existait déjà : `IngredientDiet` (compat par ingrédient, exposée via `IngredientView.diets`). **Option A retenue** (validée) : dérivé pur, table supprimée. ## Changements **Logique pure** — `packages/shared/src/logic/recipe-diets.ts` : `computeRecipeDietViews(ingredients, glutenFreeDiet)` → un régime `vegetarian`/`vegan`/`pescatarian` ssi **tous** les ingrédients y sont compatibles ; `glutenFree` ssi **aucun** ingrédient ne porte l'allergène `gluten` ; `[]` si la recette a **≥ 1 ingrédient placeholder**. `DietView`s empruntés aux ingrédients eux-mêmes (glutenFree passé par l'appelant). **Modèle** — `RecipeDiet` droppé (`Recipe.diets` / `Diet.recipes` retirés). Migration `20260909130000_drop_recipe_diet` : `DROP TABLE`, aucune donnée à conserver. **Contrat** — `createRecipeSchema` perd `dietIds` ; `RecipeSummaryView.diets` reste `DietView[]` (doc mise à jour : calculé). **API `recipe.service.ts`** — `recipeInclude` retire le `diets` de niveau recette (garde `IngredientDiet` sur les ingrédients) ; `toRecipeSummaryView`/`toRecipeView` calculent `diets` ; `loadReferenceDiets`/`loadGlutenFreeDiet` mémoïsés. `suitableForHouseholdWhere` → `suitableForHousehold` renvoie `{ allergenWhere (SQL), requiredDietKeys }` ; `listRecipes` applique la contrainte régime foyer **et** le filtre `dietIds` en **post-filtre** sur `diets` calculé (`omnivore` = pas de contrainte). `assertDietsExist` + `DIET_NOT_FOUND` sur la création recette supprimés (le code d'erreur reste — utilisé par `PATCH /profile` diet). **Frontend** — `RecipeFormPage` + `RecipeImportForm` : `DietTagSelect`, `dietIds`, `getDiets` retirés. `recipe-import-draft.ts` idem. `DietBadges` inchangé. `RecipePickerDialog` garde son filtre régime (marche via le post-filtre). ## Vérification locale `pnpm lint` ✓ · `pnpm build` ✓ (Prisma régénéré) · Cypress : `recipe-form.feature` 10/10 (nouveau scénario « pas de sélecteur de régime »), `recipes.cy.ts` 12/12, `recipe-sources.feature` 7/7, `recipes`/`planning` régression OK. Mocha non exécutable ici — `recipe-diets.test.ts` (7 cas purs) + `recipe.test.ts` réécrit (4 nouveaux cas régimes calculés, 2 tests `DIET_NOT_FOUND` retirés) + `dietIds` retiré des fixtures `recipe-placeholder`/`sources` — à valider en CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kyuno added 1 commit 2026-09-09 15:01:21 +02:00
feat(recipes): régimes d'une recette calculés depuis ses ingrédients (#131)
All checks were successful
CI / lint (push) Successful in 2m58s
CI / build (push) Successful in 2m58s
CI / intent-service-test (push) Successful in 4m57s
CI / e2e (push) Successful in 10m45s
CI / test (push) Successful in 18m56s
CI / build-android (push) Has been skipped
e8596a55bc
`RecipeDiet` (tag manuel) est supprimé — table droppée, `dietIds` retiré de
`createRecipeSchema`, `DietTagSelect` retiré des formulaires de recette
(création + import). `RecipeSummaryView.diets` / `RecipeView.diets` sont
désormais **dérivés** via `computeRecipeDietViews` (`@batch-cooking/shared`,
pur, testé isolément) :

- un régime (vegetarian / vegan / pescatarian) est retenu ssi *tous* les
  ingrédients y sont compatibles (`IngredientDiet`, exposé par
  `IngredientView.diets`) ;
- `glutenFree` est dérivé des allergènes (aucun ingrédient ne porte
  `gluten`) — cohérent avec le fait que le seed ne le stocke pas dans
  `IngredientDiet` ;
- `[]` dès qu'une recette contient un ingrédient placeholder (hors-catalogue) :
  un ingrédient inconnu ne certifie rien.

Filtres du sélecteur de planning (`suitableForHousehold`, `dietIds`) : ne
peuvent plus être du SQL sur une colonne stockée — devenus des post-filtres
sur `diets` calculé dans `listRecipes` ; `omnivore` traité comme « aucune
contrainte ». `assertDietsExist` / `ErrorCode.DIET_NOT_FOUND` sur la création
recette supprimés (le code d'erreur reste, utilisé par la préférence profil).

`DietBadges` inchangé (affiche `diets` tel quel). `RecipePickerDialog` garde
son filtre régime (fonctionne via le post-filtre).

Tests : `recipe-diets.test.ts` (fonction pure) + `recipe.test.ts` réécrit
(régimes calculés attendus, tests DIET_NOT_FOUND retirés) ; Cypress OK
(formulaire sans sélecteur de régime, régression recettes/sources/planning).
Migration `DROP TABLE recipe_diet` — aucune donnée à conserver.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
kyuno merged commit 81b4a149ff into main 2026-09-09 15:20:16 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: kyuno/batchCooking#137
No description provided.