batchCooking/apps/api/src/modules/reference/reference.routes.ts
Nicolas 766d48eaa5 feat(recipes): préférences de sources par foyer + distinction officielle/non-officielle
Répond à deux besoins : permettre à chaque foyer de choisir quelles
sources apparaissent dans ses onglets de recettes, et distinguer les
sources à API officielle des sources scrapées.

- RecipeSourceAdapter.official (booléen, sans défaut — chaque
  adaptateur doit le déclarer explicitement) synchronisé sur
  Source.official par syncRecipeSources.
- HouseSource : table de jointure opt-in (House <-> Source) — aucune
  ligne = source masquée. Un foyer nouvellement créé ne voit aucune
  source tant qu'il ne les active pas explicitement.
- GET /reference/sources (catalogue des sources implémentées, avec le
  flag officiel).
- GET/PATCH /house/current/sources (lecture/remplacement complet des
  sources activées par le foyer courant).
- recipe.service.ts : sourceVisibilityWhere() filtre désormais TOUS
  les onglets (perso/foyer/publique/favoris) — une recette sans
  source reste toujours visible ; une recette importée ne l'est que
  si sa source est activée pour le foyer du viewer. Un viewer sans
  foyer ne voit aucune recette sourcée.

Côté web :
- Nouvelle étape /onboarding/sources dans le wizard d'inscription,
  atteinte uniquement si un foyer vient d'être créé/rejoint (sinon on
  saute direct aux allergènes) ; s'auto-saute aussi si aucune source
  n'est encore implémentée (catalogue vide aujourd'hui).
- Nouvelle section « Sources de recettes » dans /parametres/foyer
  (masquée dans les mêmes conditions), avec sauvegarde à la volée
  (même pattern que les autres préférences hot-saved).
- SourceSelect (features/house/), grille de cases à cocher avec badge
  officiel/non-officielle, sur le même principe qu'AllergySelect.

172 tests backend passent (dont 25 nouveaux). Build et lint propres.
Vérifié manuellement en navigateur : le parcours d'onboarding saute
bien l'étape sources (catalogue vide) et affiche « 4 sur 4 » quand un
foyer a été créé ; la section paramètres reste invisible tant
qu'aucune source n'existe.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 09:22:54 +02:00

63 lines
1.6 KiB
TypeScript

import { wrapAsyncHandler } from "@batch-cooking/express-tools";
import { Router } from "express";
import {
getAllergies,
getDiets,
getIngredients,
getSources,
getTechSteps,
getUnits,
} from "./reference.service.js";
/**
* Router mounted at `/reference` in app.ts. Every route is deliberately
* public (no `requireAuth`) — this is static reference data, not
* per-household state, and the signup wizard (household/regime/allergen
* steps) needs to read it before an account — and therefore a session —
* exists. `/ingredients` follows the same reasoning even though it's only
* consumed post-login (the recipe catalog) — it's still non-administrable
* reference data, no reason to require a session to read it.
*/
export const referenceRouter = Router();
referenceRouter.get(
"/diets",
wrapAsyncHandler(async (_req, res) => {
res.status(200).json(await getDiets());
}),
);
referenceRouter.get(
"/allergies",
wrapAsyncHandler(async (_req, res) => {
res.status(200).json(await getAllergies());
}),
);
referenceRouter.get(
"/ingredients",
wrapAsyncHandler(async (_req, res) => {
res.status(200).json(await getIngredients());
}),
);
referenceRouter.get(
"/units",
wrapAsyncHandler(async (_req, res) => {
res.status(200).json(await getUnits());
}),
);
referenceRouter.get(
"/tech-steps",
wrapAsyncHandler(async (_req, res) => {
res.status(200).json(await getTechSteps());
}),
);
referenceRouter.get(
"/sources",
wrapAsyncHandler(async (_req, res) => {
res.status(200).json(await getSources());
}),
);