Quand le catalogue seede ne couvre pas un ingredient, l'utilisateur pouvait etre bloque (creation manuelle) ou perdre silencieusement la ligne (import). Une ligne de recette accepte desormais `placeholderName` (texte libre) au lieu de `ingredientId` : l'API cree une ligne `Ingredient` `isPlaceholder` (cle `placeholder:<uuid>`, `displayName`, `createdById`) dans la transaction de la recette, et emet `ingredient.placeholder_created`. Ces lignes sont exclues de `GET /reference/ingredients` et de `ingredient-matcher`. Front : bouton "Ajouter << ... >>" dans l'etat vide de `IngredientPicker` (formulaire + import), badge "a completer" sur la ligne, helper `ingredientLabel` applique partout ou un libelle d'ingredient est rendu. Admin : `/admin/catalog/*` (+ page `apps/admin-web`) liste les placeholders regroupes par nom normalise, "marquer traite" (`reviewedAt`) et purge des orphelins. La promotion en vraie entree catalogue reste manuelle. Migration `ingredient_placeholder` ecrite a la main (Postgres indisponible). Suites Mocha DB-backed ecrites, non executees en session ; test pur `normalizePlaceholderName` + Cypress admin-web/web verts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
22 lines
1,014 B
TypeScript
22 lines
1,014 B
TypeScript
import { Router } from "express";
|
|
import { adminAuthRouter } from "./admin-auth.routes.js";
|
|
import { adminCatalogRouter } from "./admin-catalog.routes.js";
|
|
import { adminMetricsRouter } from "./admin-metrics.routes.js";
|
|
import { adminMonitoringRouter } from "./admin-monitoring.routes.js";
|
|
import { adminTechStepsRouter } from "./admin-tech-steps.routes.js";
|
|
|
|
/**
|
|
* Aggregator for the admin application's API surface, mounted at `/admin`
|
|
* in `app.ts`. Every sub-router here is for `apps/admin-web` only —
|
|
* `/admin/auth` is public (login), everything added later
|
|
* (`/admin/metrics`, `/admin/monitoring`, `/admin/tech-steps/*`,
|
|
* `/admin/catalog/*`) sits behind `requireAdmin`
|
|
* (`middlewares/require-admin.ts`).
|
|
*/
|
|
export const adminRouter = Router();
|
|
|
|
adminRouter.use("/auth", adminAuthRouter);
|
|
adminRouter.use("/metrics", adminMetricsRouter);
|
|
adminRouter.use("/monitoring", adminMonitoringRouter);
|
|
adminRouter.use("/tech-steps", adminTechStepsRouter);
|
|
adminRouter.use("/catalog", adminCatalogRouter);
|