Éditeur de bannières homepage (slides)
backend/src/controllers/slides.controller.js + slide_elements.controller.js + frontend/src/views/backoffice/SlidesEditor.vue (édition) + frontend/src/views/public/HomeView.vue (consommation publique).
Vérifié le 2026-08-13.
1. Modèle : une slide, plusieurs éléments positionnables
slides (image de fond, couleur de fond, actif, ordre, opacité d'overlay) a une relation 1—N vers slide_elements (suppression en cascade). Chaque élément est un text ou button positionné en pourcentage (pos_x/pos_y/width), avec sa propre police, couleur, lien.
2. L'éditeur (SlidesEditor.vue)
Éditeur WYSIWYG plein écran : positionnement libre par glisser-déposer, redimensionnement, guides d'alignement magnétiques, annuler/refaire (historique 60 étapes, Ctrl+Z/Ctrl+Y), déplacement au clavier, aperçu responsive (mobile/tablette/desktop/large).
Pas de champ d'ordre d'empilement explicite — l'ordre visuel des éléments suit l'ordre du tableau, pas un z-index dédié.
handleImageUpload/handleDrop convertissent le fichier choisi en data URL base64 côté client (limite 5 Mo) — l'image finit encodée en base64 directement dans image_url, pas de vrai upload vers un stockage fichier/S3. Alternative : coller une URL externe, ou choisir parmi 3 images statiques prédéfinies.
3. Sauvegarde : remplacement atomique (corrigé le 2026-08-13)
La sauvegarde faisait auparavant une séquence DELETE/POST multiples non transactionnelle depuis le frontend (un crash en cours de route pouvait laisser la base sans aucune slide active). Un nouvel endpoint PUT /api/slides (slidesService.replaceAll) enveloppe désormais tout le remplacement — suppression des anciennes slides/éléments et recréation des nouvelles, éléments imbriqués inclus (écriture Prisma imbriquée elements: { create: [...] }) — dans une seule transaction Prisma (prisma.$transaction). ContentView.vue::saveSlides() envoie maintenant le tableau complet en un seul appel au lieu d'orchestrer les créations une par une.
La fonction save() locale de SlidesEditor.vue reste du code mort (écrit dans localStorage, jamais appelée) — la vraie logique vit dans ContentView.vue/le nouvel endpoint backend, pas dans cette fonction.
Mapping camelCase (frontend : x/y/width/fontSize/isActive/bgColor/textColor/overlayOpacity) ↔ snake_case (API : pos_x/pos_y/width/font_size/is_active/bg_color/text_color/overlay_opacity) fait à la main dans ContentView.vue, à l'aller comme au retour — deux points de duplication non factorisés, à garder synchronisés si un champ est ajouté.
4. Consommation publique : HomeView.vue, pas HeroBanner.vue
Attention à ne pas confondre : HeroBanner.vue est un composant générique de bannière statique par page (Assurances, Contact, Mentions légales...), sans aucun lien avec slides/slide_elements. Le vrai carrousel de la page d'accueil est géré directement dans HomeView.vue (fetchSlides()) : récupère les slides actives, repli sur fallbackSlides codé en dur si vide/erreur, transition d'opacité CSS, positionnement des éléments identique à l'éditeur, rotation automatique pilotée par site-settings/banner_scroll_duration.
5. Pièges connus pour un futur développeur
save()locale deSlidesEditor.vueest du code mort — ne pas perdre de temps à la déboguer si un problème de sauvegarde survient, la vraie logique est dansContentView.vueetPUT /api/slides.- Cache API 5 minutes sur
GET /slides(apicache) — une modification backoffice peut mettre jusqu'à 5 min à apparaître publiquement si l'invalidation du cache (apicache.clear(), appelée dans les contrôleurs create/update/delete) échoue ou est contournée. GET /slide-elements(toutes) etGET /slide-elements/slide/:idne sont pas protégées parverifyToken, contrairement aux routes d'écriture.- L'ancien système
banniere/pagequeslidesavait remplacé a été supprimé le 2026-08-13 (contrôleur, service, routes) — voir Contenu vitrine.