feat(api): modèle de données + API des scénarios de didacticiel (#42/#44 — socle backend) #58
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/tour-scenarios-backend"
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?
Premier volet du tutoriel guidé — tout le backend, entièrement testable en CI. Le moteur front (
driver.js), l'instrumentationdata-tour-*et le CRUD admin viennent après (voir « Suite » plus bas).#44révise directement la conception de#42: le registre de tours devient un modèle en base éditable depuis l'admin plutôt qu'un tableauTourDefinition[]figé en code, ettitle/contentd'une étape deviennent du texte libre (pas des clés i18n — même distinction que le nom d'une recette : le chrome de l'UI vient d'i18next, le contenu administré dynamiquement est du texte). Cette PR pose ce modèle.Schéma (
schema.prisma+ migration20260906120000_tour_scenarios)Les 4 modèles de
#44— 4 tables neuves, rien à backfiller :TourTarget(keyPK +description) — catalogue des cibles de surlignage valides, seedé, commeTechStep/Unit. Chaquekeycorrespond à undata-tour-<key>à poser côté front ; un admin choisit parmi ces cibles, il n'en invente pas.TourScenario(keystable,name,enabled) — un scénario rejouable.TourScenarioStep(order,route?,targetKey→ FKTourTarget,title,content) —@@unique([scenarioId, order]).TourProgress(userProfileId+scenarioId, PK composite, cascade des deux côtés) — présence d'une ligne = scénario vu.Seed (
reference-seed-data.ts)TourTargetcorrespondant auxdata-tour-*prévus (nav sidebar, grille planning, bouton+, bouton Cuisiner, liste de courses, description d'étape, sélecteur de technique).#42(general,techStepMetadata) — créés seulement s'ils sont absents (un admin en devient propriétaire ensuite ; un reseed en prod ne doit jamais écraser ses modifs). En test,resetDatabase()truncate d'abord, donc ils sont toujours recréés.techStepMetadatareste volontairement court :#36(le popover de correction se ferme en pleine sélection) est ouvert — v1 ne couvre que les gestes qui marchent déjà (sélectionner du texte, choisir une technique).API
GET /reference/tours(public)useTour()GET /profile/tours(session){ completedTourKeys: string[] }POST /profile/tours/:tourKey/complete(session){ "skipped": true }= passé (même effet « ne plus proposer »,analytics.recordEventdifférent). 404TOUR_NOT_FOUND(nouveau code4053) sur une clé inconnue/désactivée.Analytics « quasi gratuites » de
#44:tour.completed/tour.skippedsont émis ici — le dashboard admin agrège déjà tout type d'AnalyticsEventde façon générique, aucun changement front nécessaire.reset-db.tstruncate les 4 nouvelles tables (reseedées juste après, commediet/tech_step).Tests (Mocha)
reference.test.ts:GET /reference/toursrenvoie les scénarios seedés avec leurs étapes ordonnées ; un scénario désactivé est exclu.profile.test.ts:/profile/tours— 401 sans session ; vide pour un profil neuf ; marque vu + relit ; upsert idempotent (2× → une seule ligne) ;{ skipped: true }marque quand même vu ; 404 clé inconnue ; 404 tour désactivé ; isolation par profil.pnpm build+pnpm lintverts. Pas de Postgres local sur ce poste → les tests DB tournent en CI (prisma migrate deployapplique la migration écrite à la main, même pratique que les migrations existantes du repo).Suite (hors de cette PR)
#44) :/admin/api/tours*(list / create / patch-remplace-les-étapes-en-bloc / delete +/targets) + page/admin/didacticiels— la partie API est prête et attend juste d'être poussée.#42) : dépendancedriver.js,apps/web/src/features/tour/useTour()consommantGET /reference/tours, attributsdata-tour-*surAppLayout/PlanningPage/ShoppingListPage/StepDescription, déclenchement auto (tour général sur/, tour métadonnées suractiveCorrection), section « Revoir un tutoriel » dans les paramètres. À faire dans une session où le rendu des overlaysdriver.jspeut être vérifié visuellement (Cypress couvre la cible/le texte/l'appel de complétion, pas le placement pixel du halo). Tour 2 également conditionné par#36.Refs #42, #44
🤖 Generated with Claude Code