Ce que nous avons amélioré pour vous
Lalla Kenza évolue chaque semaine. Voici toutes les nouveautés livrées, de la plus récente à la plus ancienne.
- Version 2026-06-11.0211 juin 2026(Email Resend prod : sweep surface `.co` + unit tests + runbook)
Les emails de Lalla Kenza (invitations RSVP, confirmations) partent maintenant depuis le vrai domaine lallakenza.co vérifié — fini les liens et expéditeurs sur un domaine qui n'est pas le nôtre.
- Version 2026-06-11.0111 juin 2026(Go-live domaine custom : lallakenza.co câblé bout-en-bout)
Le site a désormais sa vraie adresse : lallakenza.co. Les liens que vous partagez (blog, liste de cadeaux, portail) pointent maintenant vers lallakenza.co, l'inscription et la réinitialisation de mot de passe fonctionnent sur le nouveau domaine, et Google peut enfin indexer le site.
- Version 2026-06-03.103 juin 2026(Sprint P1 perf — client cookie-free + budget bundle + images annuaire)
Les pages publiques se chargent plus efficacement : les photos de l'annuaire sont plus légères (qualité optimisée, invisible à l'œil), et un garde-fou interne empêche désormais le poids du site de gonfler avant le lancement.
- Version 2026-06-03.093 juin 2026(hotfix — dates avis : pin UTC contre un mismatch d'hydratation)
Correctif technique invisible : sur les fiches prestataires et l'espace avis du vendeur, les dates des avis s'affichent de façon identique entre le rendu serveur et le navigateur, quel que soit le fuseau horaire du visiteur.
- Version 2026-06-03.083 juin 2026(Perf-2 §2.1 (7) — messagerie paginée : boîte de réception + fil)
La messagerie se charge plus vite : la boîte de réception affiche les conversations récentes avec un bouton « Charger plus de conversations », et un fil ouvre les messages les plus récents avec un bouton « Charger les messages précédents » pour remonter l'historique.
- Version 2026-06-03.073 juin 2026(Perf-2 §2.1 (6) — reviews paginés : annuaire public + dashboard vendeur)
Sur une fiche prestataire très commentée, les avis se chargent maintenant par lots avec un bouton « Afficher plus d'avis » — la page s'ouvre plus vite. La note moyenne et l'histogramme des étoiles restent toujours exacts (calculés sur la totalité des avis, pas seulement ceux affichés). Côté espace prestataire, votre liste d'avis se charge aussi par lots, avec des compteurs par statut toujours justes.
- Version 2026-06-03.063 juin 2026(Perf-2 §2.1 — clôture : reviews + private-messages différés pré-lancement)
Aucun changement visible — clôture du chantier interne « over-fetch » (suivi technique).
- Version 2026-06-03.053 juin 2026(Perf-2 §2.1 (5) — livre d'or dashboard reclassé borné)
Aucun changement visible — ajustement interne de classification (suivi technique).
- Version 2026-06-03.043 juin 2026(Perf-2 §2.1 (4) — file de modération photos paginée par état)
La file de modération des photos d'invités (
/photos-moderation) charge par lots de 24 par onglet avec un bouton « Charger plus », au lieu de tout charger d'un coup. Les compteurs (en attente / approuvées / rejetées) restent exacts, et approuver ou rejeter une photo la déplace entre onglets instantanément. - Version 2026-06-03.033 juin 2026(Perf-2 §2.1 (3) — galerie photo publique « Le jour J » paginée)
L'onglet « Le jour J » de la galerie photo publique (
/p/<slug>/photos) charge les photos des invités par lots de 24 avec un bouton « Charger plus », au lieu de toutes les charger d'un coup. Le compteur de l'onglet reste exact. Pages plus légères pour les mariages avec beaucoup de photos d'invités. - Version 2026-06-03.023 juin 2026(Perf-2 §2.1 (2) — livre d'or public paginé)
Le livre d'or public (
/p/<slug>/livre-dor) charge ses messages par lots de 20 avec un bouton « Charger plus », au lieu de tout afficher d'un coup. Le compteur du titre (« X messages partagés ») reste exact même quand tous les messages ne sont pas encore chargés. - Version 2026-06-03.013 juin 2026(Perf-2 §2.1 (1) — blog public paginé + 3 domaines bornés reclassés)
Le journal public d'un couple (
/p/<slug>/blog) charge désormais ses articles par lots de 12 avec un bouton « Charger plus », au lieu de tout charger d'un coup — page plus légère et rapide, surtout pour un couple qui publie beaucoup. - Version 2026-06-02.072 juin 2026(Refonte ruban « Votre parcours » v2 — avancement par bande + accordéon inline)
Le ruban « Votre parcours » du tableau de bord a été repensé. Chaque étape affiche désormais sa propre progression — une barre de remplissage proportionnelle, le ratio « 2/5 », et un ✓ quand elle est bouclée — avec un repère explicite pour l'étape en cours : plus besoin de deviner le sens des couleurs. Cliquer sur une étape la déroule SUR PLACE pour voir ses tâches restantes (avec une coche rapide pour les valider d'un geste), au lieu de quitter le tableau de bord. Les « prochains pas » sont maintenant intégrés directement dans l'étape en cours, et toute étape sans tâche explique pourquoi (bouclée, à jour, ou à venir) plutôt qu'un « Aucune tâche » sec.
- Version 2026-06-02.062 juin 2026(Perf-2 (1/2) — garde-fou anti-over-fetch + résilience RSC)
Si une page lourde tarde à charger (serveur/réseau lent), un bouton « Réessayer » apparaît après ~12 s au lieu d'un chargement qui semble bloqué indéfiniment.
- Version 2026-06-02.052 juin 2026(Perf-1 — notifications : count SQL agrégat + pagination curseur + realtime delta)
La cloche de notifications et la page
/notificationsse chargent beaucoup plus vite : le compteur de non-lues est un calcul direct (plus aucune liste ramenée juste pour afficher un chiffre), la liste arrive par paquets de ~20 avec un bouton « Charger plus », et le badge affiche le vrai total (« 99+ » au lieu d'un « 9+ » plafonné à tort). - Version 2026-06-02.042 juin 2026(Ruban « Votre parcours » navigable → /planning filtré par étape)
Les 5 bandes du ruban « Votre parcours » (dashboard) sont maintenant cliquables : un clic ouvre
/planningfiltré sur les tâches de cette étape — l'étape passée pour revoir ce qui est fait, l'étape courante pour agir, les étapes futures pour prévisualiser. Avant, les bandes étaient nommées (« Les fondations », « Les grands prestataires »…) mais inertes — elles invitaient au clic sans rien faire. - Version 2026-06-02.032 juin 2026(Filet E2E — boutons « Signaler » + queue /admin/reports)
— (rien de visible ; couverture de tests anti-régression.)
- Version 2026-06-02.022 juin 2026(V026 — perf dashboard vendor : RPC consolidée + index submitted_by)
Le tableau de bord prestataire se charge plus vite : ses données (fiche + avis + statistiques 30 jours) sont récupérées en un seul aller-retour à la base, au lieu de trois en cascade.
- Version 2026-06-02.012 juin 2026(BUG-304 — hydratation : dates des pages annuaire déterministes SSR↔CSR)
Les pages prestataire de l'annuaire (
/annuaire/...) ne « clignotent » plus au chargement. Le bloc des disponibilités (et la date de réponse d'un prestataire à un avis) pouvait s'afficher une fraction de seconde dans la mauvaise langue ou avec un jour décalé, le temps que le navigateur recalcule. Corrigé : la date s'affiche directement dans la langue de la page, identique côté serveur et navigateur. - Version 2026-05-31.1931 mai 2026(Sprint 2 — réactivation du gate de drift schéma/migrations)
— (rien de visible côté utilisateur ; durcissement du process de release.)
- Version 2026-05-31.1831 mai 2026(Sprint 1 — boutons « Signaler » : activation du pipeline de modération)
Les couples et prestataires peuvent désormais signaler un contenu abusif (message du livre d'or, demande reçue, fiche prestataire, avis) en un clic — un bouton « Signaler » ouvre un petit formulaire (catégorie + description) qui alimente la file de modération
/admin/reports. - Version 2026-05-31.1731 mai 2026(Sprint 1 — bannières d'erreur auth accessibles + vérif login silencieux)
Les messages d'erreur de connexion et d'inscription (« Email ou mot de passe incorrect », etc.) sont désormais annoncés par les lecteurs d'écran dès qu'ils apparaissent — avant, une personne non-voyante ne recevait aucun retour après un échec.
- Version 2026-05-31.1631 mai 2026(Sprint 1 — révocation de session au bannissement)
Quand un·e administrateur·rice bannit un compte, la session de la personne bannie est désormais réellement coupée : elle ne peut plus se reconnecter, et sa session active cesse de fonctionner au lieu de continuer comme si de rien n'était. Débannir lève la restriction.
- Version 2026-05-31.1531 mai 2026(Onboarding-2 Phase B — F4 : merge solo→couple sans perte de données)
Quand un·e conjoint·e qui avait déjà commencé à organiser de son côté (invités, budget, prestataires shortlistés) rejoint le couple partagé, ses données le suivent au lieu d'être silencieusement supprimées.
- Version 2026-05-31.1431 mai 2026(Onboarding-2 Phase B — F2 : accueil partenaire)
Quand un·e conjoint·e rejoint via l'invitation, il/elle voit une carte d'accueil récapitulant ce qui est déjà en place (date, ville, invités, budget) — au lieu d'atterrir sur un dashboard sans contexte. Et son statut « a terminé l'onboarding » est enfin enregistré.
- Version 2026-05-31.1331 mai 2026(Onboarding-2 Phase A — F1 : nudge invitation partenaire)
Un couple qui n'a pas (encore) invité son conjoint·e voit désormais une carte persistante sur le tableau de bord — « Invitez {prénom} pour organiser à deux » — au lieu que l'invitation différée disparaisse dans un trou noir.
- Version 2026-05-31.1231 mai 2026(Onboarding-2 Phase A — F3 : re-ancrage des tâches sur la date de mariage)
Quand un couple renseigne (ou modifie) sa date de mariage, toutes les échéances de ses tâches se recalculent automatiquement sur la vraie date — fini le planning figé à « +1 an » quand la date est posée après l'onboarding.
- Version 2026-05-31.1131 mai 2026(BUG-297 — `<html lang>` correct par locale (statique), portail toujours statique)
Les pages /es/_ et /nl/_ déclarent enfin
<html lang="es">/lang="nl"dès le HTML servi (avant : toujourslang="fr"). Meilleur SEO multilingue + lecteurs d'écran qui prononcent la bonne langue. - Version 2026-05-31.1031 mai 2026(BUG-298 — dashboard : prochaines étapes re-localisées ES/NL)
Les « 3 prochains pas » du tableau de bord s'affichent désormais dans la langue de la page (ES/NL) pour les tâches issues du catalogue, au lieu de rester en français.
- Version 2026-05-31.0931 mai 2026(BUG-292 — compteur notifications : plus de +1 après undo)
Sur Notifications, ignorer une notification puis « Annuler » ne gonfle plus le compteur de non-lues d'une unité : il revient exactement à sa valeur d'avant.
- Version 2026-05-31.0831 mai 2026(BUG-294 — paramètres : plus de tiret orphelin « Connecté·e depuis le — »)
Sur Paramètres, la carte « Compte partagé » n'affiche plus « Connecté·e depuis le — » (tiret seul) quand la date de liaison du partenaire est inconnue : le badge est simplement masqué.
- Version 2026-05-31.0731 mai 2026(BUG-300 — recherche invités : plus de frappes perdues)
La barre de recherche des invités ne perd plus de caractères quand on tape vite : tout ce qu'on tape reste affiché, et le filtrage se déclenche juste après.
- Version 2026-05-31.0631 mai 2026(BUG-303 — nom du partenaire : source unique portail ↔ lettre)
Le nom du partenaire est désormais identique partout : le portail public / faire-part affiche le même nom que la lettre scellée (le vrai nom du compte lié), au lieu d'un ancien nom de pré-inscription périmé.
- Version 2026-05-31.0531 mai 2026(Bugfix Sprint 3 — badge notif « 9+ » + barre sticky dashboard (décisions PO))
Le badge de la cloche affiche « 9+ » au lieu d'un « 200 » trompeur ; la barre récap du haut ne fait plus doublon avec le nouvel en-tête sur /dashboard (et affiche le bon budget cible ailleurs).
- Version 2026-05-31.0431 mai 2026(Bugfix Sprint 2 — a11y/i18n : `<h1>` dashboard + grammaire « Voir tout »)
Le tableau de bord a de nouveau un titre de page (pour les lecteurs d'écran), et les liens annuaire « Voir tout » ne cassent plus l'accord (« tous les salle de fête »).
- Version 2026-05-31.0331 mai 2026(Hotfix Sprint 1 — write-ops prod cassés : ajout invité + paiement budget restaurés)
Ajouter un invité (même sans téléphone) et enregistrer un paiement de budget fonctionnent à nouveau en production — ils échouaient en erreur 500 avec perte de la saisie.
- Version 2026-05-31.0231 mai 2026(Bugfix Sprint 1 — budget : montant négatif rejeté au lieu d'être coercé en +)
Saisir un montant de dépense négatif (« -500 ») est désormais signalé en rouge et refusé, au lieu d'être silencieusement transformé en +500 MAD.
- Version 2026-05-31.0131 mai 2026(Refonte dashboard couple — hiérarchie « guidage d'abord » + en-tête fusionné + KPI compacts)
Le tableau de bord s'ouvre désormais sur l'essentiel. Une ligne d'accueil sobre (« Bonjour Salma · J-84 · 17 % organisé · Casablanca, 22 août 2026 »), puis tout de suite « Votre parcours » et « Vos 3 prochains pas » — visibles sans scroller. Les chiffres clés (invités · budget · tables) passent en rangée compacte et cliquable. La longue liste « Mes héros » qui occupait le haut de page devient un simple résumé en bas (« Mes héros · 12 → Gérer »), la liste complète restant sur sa page dédiée. Et fini les doublons : le compteur J, le « Bonjour » et le « 17 % » n'apparaissent plus qu'une seule fois.
- Version 2026-05-30.1930 mai 2026(Bugfix Sprint 2.5 — i18n : bannière langue, blog ES/NL, terme « héros »)
Trois finitions multilingues, validées avec vous.
- Bannière de langue : sur une page ES/NL, l'invitation à changer de langue s'affiche désormais dans la langue de la page (« Lalla Kenza también está disponible en francés ») au lieu d'une phrase 100 % française ; le bouton, lui, reste dans la langue cible.
- Blog ES/NL : les articles écrits uniquement en français n'apparaissent plus sur /es/blog et /nl/blog (un message « bientôt » s'affiche). Dès que des articles ES/NL seront rédigés, ils apparaîtront automatiquement.
- « Héros » : sur le dashboard, le bandeau « Mis héroes » / « Mijn helden » devient « Mi equipo » / « Mijn team » (terme plus clair) en ES/NL ; le français garde « Mes héros ».
- Version 2026-05-30.1830 mai 2026(Bugfix Sprint 2.4 — prestataires : confirmation avant de retirer de la shortlist)
Plus de suppression accidentelle dans la shortlist. Sur « Mes prestataires », cliquer la corbeille retirait le prestataire en un seul clic. Désormais une confirmation s'affiche (en nommant le prestataire) avant de le retirer.
- Version 2026-05-30.1730 mai 2026(Bugfix Sprint 2.3 — annuaire : titre/description SEO traduits en ES/NL)
Le référencement de l'annuaire est enfin dans la bonne langue. Sur
/es/annuaireet/nl/annuaire, le titre de l'onglet et la description (ceux que Google affiche) restaient en français alors que la page, elle, était traduite. Désormais ils sont en espagnol et en néerlandais. - Version 2026-05-30.1630 mai 2026(Bugfix Sprint 2.2 — annuaire : le bouton « Contacter » remarche)
Le bouton « Contacter » d'une fiche prestataire remarche. Pour un couple connecté, cliquer « Contacter » ne faisait rien ; désormais la page défile jusqu'au formulaire de demande et place le curseur dans le premier champ. (Les visiteurs non connectés sont, comme avant, redirigés vers la connexion.)
- Version 2026-05-30.1530 mai 2026(Bugfix Sprint 2.1 — annuaire : le filtre par catégorie remarche)
Le filtre par catégorie de l'annuaire remarche. Cliquer « Traiteur », « Salle », « Photographe », « Orchestre », « Fleuriste »… affichait « Aucun prestataire » alors que des dizaines de fiches existaient — 10 catégories sur 14 étaient inutilisables. C'est réparé : chaque catégorie affiche bien ses prestataires. Bonus : la catégorie Coiffure (3 prestataires) est désormais accessible, et le filtre fantôme « Décoration » (vide) a été retiré.
- Version 2026-05-30.1430 mai 2026(Bugfix Sprint 1.3 — lettre scellée : brouillon persistant + date d'ouverture future)
La lettre scellée garde enfin ce qu'on écrit. On pouvait taper une lettre, cliquer « Enregistrer le brouillon », et tout perdre au rechargement. C'est réparé : le brouillon se recharge fidèlement, et chaque sauvegarde persiste.
Et la date de déverrouillage ne peut plus être dans le passé : le sélecteur bloque les dates écoulées, un message s'affiche si vous en choisissez une, et le bouton « Sceller » reste désactivé tant que la date n'est pas valide — pour qu'une lettre ne s'ouvre jamais le jour même par erreur.
- Version 2026-05-30.1330 mai 2026(Bugfix Sprint 1.2 — mon-blog : dépublier, supprimer en sécurité, URL publique)
Le journal de mariage est enfin contrôlable. Trois corrections côté « Mon blog » :
- Repasser un article en brouillon. Un post publié peut maintenant être retiré du journal public d'un clic (« Repasser en brouillon ») — avant, aucun bouton ne le permettait, et « Sauvegarder comme brouillon » le laissait publié.
- Suppression protégée. Supprimer un article demande désormais une confirmation, avec un avertissement renforcé quand l'article est publié (donc visible des invités). Fini la perte de contenu en un clic.
- L'adresse publique s'affiche. Le bandeau « Votre blog est visible sur : … » montre enfin l'URL réelle (
lallakenza.com/p/votre-mariage) et le bouton Copier/Partager fonctionne. Les couples qui n'ont pas encore publié leur portail voient un message clair plutôt qu'un lien vide.
- Version 2026-05-30.1230 mai 2026(Bugfix Sprint 1.1 — wishlist : éditer/supprimer un cadeau + liste à jour)
On peut enfin gérer ses cadeaux. Le bouton Modifier d'une carte cadeau/cagnotte ouvre maintenant un panneau d'édition pré-rempli (titre, description, objectif ou prix, quantité, lien, photo) — avant il ne faisait rien. Un bouton Supprimer (avec confirmation) a été ajouté. Et la liste se met à jour immédiatement après ajout / modification / masquage — plus besoin de recharger la page.
- Version 2026-05-30.1130 mai 2026(Onboarding-Guidance Sprint 4c-1 — digest hebdo enrichi de la prochaine action)
Le résumé du dimanche dit maintenant quoi faire ensuite. En plus de l'activité de la semaine, l'email digest hebdomadaire ajoute un encadré _« Et ensuite : <ta prochaine action> »_ — la seule action la plus pertinente, tirée du moteur Parcours. Le digest quotidien reste épuré (activité seule).
- Version 2026-05-30.1030 mai 2026(Onboarding-Guidance Sprint 5a — composant TipCallout + 1er conseil contextuel)
Des conseils au bon endroit, sans jamais encombrer. Nouveau composant de conseil contextuel : une carte douce (3 styles : info / critères / repère chiffré) qu'on peut masquer (elle se réduit à une petite pastille « Conseil » réaffichable — l'aide n'est jamais perdue). Premier conseil branché sur /budget : _« Combien prévoir ? Au Maroc, un mariage revient en moyenne à 1 000–1 500 MAD par invité… »_.
- Version 2026-05-30.0930 mai 2026(Onboarding-Guidance Sprint 4b — ruban Parcours + vos 3 prochains pas)
Le dashboard sait enfin guider. En haut de l'écran, un ruban en 5 étapes montre où le couple en est dans son parcours de mariage (étape courante surlignée, % global), et surtout « Vos 3 prochains pas » : les 3 actions les plus pertinentes _maintenant_, chacune cliquable vers la bonne page (ex. « Réserver la salle » → l'annuaire filtré sur les salles). Si un point bloque la suite (salle pas encore réservée → bloque le plan de table), un rappel calme l'indique. Voix bienveillante : « il reste », jamais « en retard ».
- Version 2026-05-30.0830 mai 2026(Onboarding-Guidance Sprint 4a — moteur Parcours (fonction pure))
(Aucun changement visible directement — c'est le moteur qui alimente le fil conducteur du dashboard. Le ruban « où j'en suis » + « vos 3 prochains pas » arrivent juste après, en 4b.)
- Version 2026-05-30.0730 mai 2026(Onboarding-Guidance Sprint 3-final — 54 titres de tâches traduits ×4)
Les tâches de mariage s'affichent enfin dans la langue du couple. Les 54 tâches pré-remplies (« Réserver la salle », « Réserver la Neggafa », « Signer l'acte de mariage »…) étaient codées en dur en français. Désormais un couple en anglais, espagnol ou néerlandais voit sa check-list dans sa langue dès la création de son espace.
- Version 2026-05-30.0630 mai 2026(Onboarding-Guidance Sprint 3-core — étape partenaire réparée + repère budget)
L'étape « inviter mon partenaire » fonctionne enfin. Dans la check-list d'onboarding du dashboard, cette étape ouvrait une boîte de dialogue vide et absurde (elle pointait sur une date technique). Désormais : un mini-formulaire email qui envoie une vraie invitation, et un lien « Je le ferai plus tard » pour ne pas rester bloqué.
Repère budget pendant l'onboarding. Sous le champ budget, quand le nombre d'invités est renseigné : _« Un mariage marocain coûte ~1 000–1 500 MAD par invité. Pour ~120 invités, compte environ 120 000 – 180 000 MAD. »_ + un bouton « Utiliser 150 000 MAD » (estimation médiane). Le budget reste optionnel.
- Version 2026-05-30.0530 mai 2026(Onboarding-Guidance Sprint 2C — ignorer une notification + annuler)
On peut enfin ranger une notification. Chaque carte de
/notificationsa un bouton ✕ : un clic la fait disparaître (du fil et du compteur de la cloche, pour les deux conjoints), avec un toast _« Notification ignorée · Annuler »_ — 6 secondes pour revenir en arrière. Plus de fil qui s'accumule sans moyen de faire le ménage. - Version 2026-05-30.0430 mai 2026(Onboarding-Guidance Sprint 2B — batching RSVP : 150 réponses → 1 carte)
Fini le mur de notifications RSVP. Avant, si 150 invités répondaient le même jour, le couple recevait 150 cartes dans son fil. Maintenant : une seule carte par jour — _« 12 invités ont répondu aujourd'hui · 9 confirmés · 3 déclinés »_. Le décompte reste juste même si un invité change d'avis (il est compté une fois, dans son dernier statut).
- Version 2026-05-30.0330 mai 2026(Onboarding-Guidance Sprint 2A — digest job : livraison des notifications calmes)
Les notifications calmes sont enfin livrées. Le Sprint 1B laissait les couples en mode Essentiel ou Équilibré mettre leurs notifications non-urgentes « en attente » — mais rien ne les délivrait. Désormais un résumé arrive : un récap quotidien (lun–sam, 18h) et le dimanche soir, un _« Ta semaine de mariage en 30 secondes »_ — une seule carte + un email calme qui regroupe tout ce qui a avancé (réponses d'invités, tâches, budget, prestataires), au lieu d'une notification par événement. Les messages critiques continuent de passer immédiatement.
- Version 2026-05-30.0230 mai 2026(Onboarding-Guidance Sprint 1B — shouldNotify gate + 3 notif modes)
Les couples contrôlent enfin leurs notifications. Les 3 cases à cocher de
/parametres(qui ne faisaient rien — écrites mais jamais lues, BUG-271) sont remplacées par 3 modes clairs : Essentiel / Équilibré (défaut) / Tout, avec une estimation vivante « ~X messages / semaine ». Le mode choisi est désormais réellement respecté : en Essentiel ou Équilibré, les notifications non-urgentes ne font plus sonner le badge — elles attendent le résumé. Les messages critiques (paiement, dépassement budget) passent toujours immédiatement. - Version 2026-05-30.0130 mai 2026(Onboarding-Guidance Sprint 1A — funnel instrumentation)
Aucun changement visible côté couple — ce ship pose la mesure. On instrumente le tunnel d'activation (onboarding, partenaire, budget, 1er prestataire, 1ère tâche, notifications) pour voir où les mariés décrochent, avant de redessiner le guidage. Aucune donnée personnelle envoyée.
- Version 2026-05-28.0428 mai 2026(Sprint vendor-Eta Phase B — V040 avatar SSoT)
Le prestataire voit maintenant le nom de son entreprise (et non son nom personnel) dans le menu compte du Navbar. Avant : "Yasmine Bensaid" partout, alors que le couple voit "Dar El Ghalia" dans l'annuaire — incohérence d'identité qui semait le doute ("qui suis-je sur cette plateforme ?"). Désormais : le menu compte affiche "Dar El Ghalia" en gras (identité business) avec "Yasmine Bensaid" en sous-titre discret (identité contact personne). Cohérent avec la fiche annuaire publique et le dashboard /vendor.
- Version 2026-05-28.0328 mai 2026(Sprint MM-HOTFIX-2 Sub-B — /admin/users ban/unban)
Nouvelle surface
/admin/userspour gérer les utilisateurs sans passer par Supabase Studio. Le modérateur et l'admin disposent d'une table paginée + filtrable (recherche email/nom, filtre par rôle, filtre actif/banni) avec un détail par utilisateur. Sur le détail : infos du profil, comptes liés (couples possédés + prestataires possédés), et deux actions de modération — Bannir (couleur rouge, raison obligatoire ≥10 chars) et Réactiver. Garde-fous : impossibilité de se bannir soi-même, modérateur ne peut pas bannir un admin, idempotence (déjà banni / pas banni). - Version 2026-05-28.0228 mai 2026(Sprint MM-HOTFIX-2 Sub-A — /admin/reports workflow signalements)
Nouveau workflow signalements complet :
/admin/reports. Les modérateurs et admins disposent désormais d'une queue paginée + filtrable (par statut et catégorie) pour traiter les signalements de contenu. Le détail d'un signalement montre l'émetteur, le contenu signalé (avec lien direct), la catégorie + description, et deux actions claires : Résoudre (action prise) ou Rejeter (rien à faire). Les deux exigent une note de résolution archivée dans le journal d'audit. Un nouveau composant<ReportContentModal>est disponible côté public pour wirer un bouton "Signaler" sur n'importe quelle surface (livre d'or, inbox, fiche prestataire, avis, article blog) — les 4 boutons concrets seront wirés dans un ship suivant. - Version 2026-05-28.0128 mai 2026(Sprint MM-HOTFIX-1 hotfix — Anonymize guest router.refresh — BUG-266 F-204b RGPD blocker)
Le modérateur peut maintenant anonymiser un invité depuis
/admin/couples/<id>et voir immédiatement le changement dans la liste. Auparavant, après confirmation de la modale RGPD, la cellule "Nom" continuait d'afficher le nom original — il fallait hard-refresh manuellement. Désormais la table se met à jour automatiquement. Même fix appliqué pour les actions "Supprimer événement" et "Archiver ligne budget" qui souffraient du même bug. Sans cette correction, l'application opérationnelle du droit à l'oubli RGPD article 17 depuis l'UI était impossible. - Version 2026-05-27.2827 mai 2026(Sprint Moderator-2.6 — Opérations bulk multi-select sur /admin/vendors)
Multi-select sur l'admin prestataires : un mode "sélection" permet maintenant de cocher plusieurs prestataires et de tous les suspendre / publier / archiver en une fois. Un toolbar flottant en bas-droite apparaît dès qu'une sélection existe, avec 3 boutons d'action (couleur par action : vert publier, ambre suspendre, rouge archiver) + un bouton Effacer. Pour suspend/archive en lot, une seule modale demande la raison qui sera appliquée à tous les prestataires sélectionnés (avec préfixe
[bulk]dans l'audit log). Plafonné à 100 prestataires par opération. - Version 2026-05-27.2727 mai 2026(Sprint Moderator-2.5 — Confirmation modal brand-styled (remplace window.prompt))
Les actions destructives sur l'admin ont maintenant une modale propre. Plus de
window.prompt()du navigateur (illisible sur mobile, pas de focus trap, single-line) — désormais une modale Lalla Kenza avec textarea multi-ligne, ESC pour fermer, clic-extérieur pour annuler, et un bouton confirm rouge clairement dégagé pour suspend/archive/anonymize/delete. Touche : la modale affiche aussi un message d'erreur inline si le server action échoue, sans perdre la raison déjà saisie. - Version 2026-05-27.2627 mai 2026(Sprint Moderator-2.4 — Export CSV admin (couples + vendors) avec audit row)
Bouton "Exporter CSV" ajouté sur
/admin/coupleset/admin/vendors. Le modo / admin peut télécharger un dump CSV de toutes les rows accessibles (full dataset, pas le filtre actif). Chaque export insère une row dansadmin_actions(actioncouple.csv.exportouvendor.csv.export) avec le count + l'identité — accountability RGPD pour qui a exporté quoi quand. - Version 2026-05-27.2527 mai 2026(Sprint Moderator-2.3 — admin moderation history timeline sur `/admin/vendors/[vendorId]/activity`)
Audit log moderator visible côté vendor. L'admin/modérateur peut désormais voir l'historique complet des actions modération prises sur un vendor (approve / reject / status change / edit / delete) directement depuis la page
/admin/vendors/<id>/activity. Nouvelle section "Historique modération" ajoutée entre le<BucketFilter>activity feed et laRevisionsSectionfield-level changes — chaque row affiche : timestamp, action slug, role + email acteur, raison fournie, diff before→after (jusqu'à 3 keys changées). - Version 2026-05-27.2427 mai 2026(Sprint Moderator-2.2 — migration `vendor-onboarding/actions.ts` inline `logAdminAction` → centralised helper)
Aucun changement utilisateur perceptible. Refactor cleanup — élimine la duplication du helper audit log entre
vendor-onboarding/actions.ts(legacy inline) etsrc/lib/auth/log-admin-action.ts(centralised). Tous les call sites convergent vers l'helper centralisé qui capture aussiip_address+user_agent(forensics). - Version 2026-05-27.2327 mai 2026(Sprint Moderator-2.1 — status filter dans `/admin/vendors` filter bar + i18n × 4 locales)
Filter status ajouté au filter bar
/admin/vendors. Le modo peut désormais filtrer rapidement par lifecycle state (Brouillon / Publié / Suspendu / Archivé) en complément des filtres search + catégorie + ville déjà existants. - Version 2026-05-27.2227 mai 2026(Sprint Moderator-1 M1.4 UI — status badge + dropdown sur admin vendor cards + i18n × 4 locales)
UI vendor status enfin câblée côté admin. Les modérateurs peuvent désormais changer le status d'un prestataire (
draft/published/suspended/archived) directement depuis la card admin via un select dropdown coloré (gris/vert/orange/rouge). Pour les transitions destructives (suspend / archive), un prompt demande la raison obligatoire (RGPD-accountability). Disponible dans les 4 locales fr/en/es/nl. - Version 2026-05-27.2127 mai 2026(Sprint Moderator-1 M1.4 — vendor_status enum + RLS tighten + updateVendorStatus action (backend-only ; UI follow-up Sprint Moderator-2))
Backend-only — UX change deferred au follow-up UI. Nouvelle colonne
public_vendors.statusenum (draft/published/suspended/archived) + action serverupdateVendorStatusqui permettra à un modo de suspendre temporairement un prestataire (e.g. TOS violation, complaint pending) sans suppression définitive. La policy RLSpublic_vendorsest tightened : seuls lesstatus='published'sont visibles côté anon. Le modo peut déclencher la transition via SQL en attendant l'UI (Sprint Moderator-2). - Version 2026-05-27.2027 mai 2026(Sprint V042 — root `not-found.tsx` locale detection (cookies + accept-language) — FR hardcoded leak sur EN/ES/NL fixed)
Page 404 enfin localisée dans les 4 langues. Pré-fix : un visiteur EN/ES/NL tapant une URL inexistante (typo, lien obsolète) tombait sur une page 404 entièrement en français — UX confusion + non-compliance i18n. Post-fix : la 404 s'affiche dans la langue du visiteur (détectée via cookie
lk_localepuis Accept-Language header, avec fallback FR par défaut). Titre, sous-titre, kicker badge, 3 cartes d'orientation et CTA retour : tout traduit. - Version 2026-05-27.1927 mai 2026(Sprint Moderator-1 M1.2 — `/admin/couples` listing + 6-tab detail UI (Events/Guests/Budget/Tasks/Audit fonctionnels))
Nouvelle interface admin pour gérer les données mariage des couples. Les modérateurs peuvent désormais :
- Voir la liste paginée de tous les couples (recherche, filtres par ville + statut conjoint·e, pagination 50/page)
- Ouvrir le détail d'un couple : 6 onglets (Vue d'ensemble / Événements / Invités / Budget / Tâches / Audit)
- Modifier ou supprimer un événement mariage (raison obligatoire pour la suppression)
- Anonymiser un invité (RGPD : nom remplacé par "Invité anonymisé", raison obligatoire)
- Archiver une ligne budget
- Changer le statut d'une tâche (todo/in_progress/done/cancelled)
- Consulter l'audit log complet des actions modo sur ce couple
Toutes les actions modo passent par
requireAdminOrModerator+ audit log immuable (admin_actions table). Disponible dans les 4 locales fr/en/es/nl. - Version 2026-05-27.1827 mai 2026(Sprint Moderator-1 M1.3 — admin_actions audit log infrastructure : centralised helper + immutability gate (28 pre-push gates))
Aucun changement utilisateur perceptible. Infrastructure pour le Sprint Moderator-1 M1.2 (à venir
.19) qui exposera une UI admin/admin/couplespermettant aux modérateurs de gérer les données mariage. Toutes les actions modo seront tracées dans une table d'audit log immuable. - Version 2026-05-27.1627 mai 2026(Sprint EE-HOTFIX-3 — root `src/app/not-found.tsx` `<Logo>` removed → VRAI fix BUG-189/265 hydration mismatch (4ème tour, capturé via npm run dev))
404 branded médina enfin visible dans Chrome (et plus seulement en curl). Pré-fix : taper une URL qui n'existe pas → overlay rouge anglais "This page couldn't load. Reload to try again, or go back." pendant ~1s avant un re-render. Post-fix : la page branded "Cette page s'est égarée dans la médina" + 3 cartes annuaire / blog / outils s'affiche immédiatement, sans flicker, sur tous les paths (root et locale-prefixed).
- Version 2026-05-27.1527 mai 2026(Sprint S-NEXT.1 — SEC-P1-002 defense-in-depth restored via `sanitize-html` (BUG-264 follow-up Option B))
Sécurité blog renforcée sans régression. Les articles
/blog/<slug>continuent à s'afficher normalement (HTTP 200) ET la lecture passe désormais par un sanitiseur defense-in-depth — protection accrue contre une éventuelle XSS stockée (rare, mais possible si une row est éditée directement via Supabase Studio en bypassant l'action serveur). Aucun changement perceptible côté lecteur. - Version 2026-05-27.1427 mai 2026(Sprint Brand-Tagline — adoption tagline primaire "Pour un mariage marocain à votre image")
Nouvelle tagline primaire de la marque déployée sur les surfaces de positionnement SEO et le hero landing : « Pour un mariage marocain à votre image » (FR), traduite et adoptée en EN/ES/NL. La tagline émotionnelle existante « Votre mariage, notre passion » reste affichée dans le Navbar logo, le footer et les signatures email — rôle "voice" de marque, complémentaire au positionnement explicite.
- Version 2026-05-27.1327 mai 2026(Sprint EE-HOTFIX-2-FINAL — `[locale]/not-found.tsx` refactor (remove next-intl client deps) — hypothèse INCORRECTE, hydration toujours cassée ⚠️)
404 branded médina visible dans Chrome (et pas seulement en curl). Pré-fix : taper une URL inexistante (
/anything-fake) → overlay rouge anglais "This page couldn't load. Reload to try again, or go back.". Post-fix : la page branded "Cette page s'est égarée dans la médina" + 3 cartes d'orientation (annuaire / blog / outils) s'affiche partout sans flicker, sur les 4 locales. - Version 2026-05-27.1227 mai 2026(Sprint vendor-Zeta Phase 2 — V041 Contact UX Option A : login-required redirect)
Prestataires — bouton "Contacter" enfin fonctionnel pour les visiteurs anonymes. Pré-fix : clic "Contacter" sur une fiche prestataire (
/annuaire/<slug>) en navigation anonyme ne faisait rien (no-op silencieux — la section formulaire d'inquiry est gated couples-only). Post-fix : redirection vers/login?hint=vendor_contactavec un encart explicatif "Connectez-vous ou créez un compte gratuit (30s) pour contacter ce prestataire". Aligns avec le flow Choose-this-vendor (déjà login-required). - Version 2026-05-27.1127 mai 2026(Sprint EE-HOTFIX-1c — `/blog/[slug]` 500 PERMANENT FIX : drop SSR DOMPurify, trust write-time sanitiser (BUG-264 closed))
Blog complètement réparé (verified post-
.10curl prod : HTTP/2 200 sur 2 slugs distincts). Lecteurs peuvent à nouveau lire les articles. - Version 2026-05-27.1027 mai 2026(Sprint EE-HOTFIX-1b — DIAGNOSTIC : remove DOMPurify from blog page to isolate 500 root cause)
Aucun changement utilisateur. Diagnostic interne pour isoler la cause du 500 blog persistant après
.08. - Version 2026-05-27.0927 mai 2026(Sprint EE-HOTFIX-2 — `[locale]/not-found.tsx` extension : remove `<NotFoundTracker />` (BUG-263 fully fixed))
Page 404 branded restaurée pour de bon. Le ship
.02annonçait corriger l'erreur "This page couldn't load" sur les URLs inexistantes — mais elle persistait sur 80%+ des chemins (toutes les URLs prefixées par un locale/fr/,/en/, etc.). Corrigé. - Version 2026-05-27.0827 mai 2026(Sprint EE-HOTFIX-1 — `/blog/[slug]` REAL root cause : isomorphic-dompurify externalize (BUG-264))
Articles du blog enfin lisibles. La page de détail d'un article (
/blog/<slug>) retournait une erreur 500 depuis plusieurs jours, malgré le « fix » annoncé en.01. Cause réelle découverte et fixée : un problème de bundling Node interne (jsdompackagé incorrectement). Aucune action utilisateur requise — la page se charge à nouveau. - Version 2026-05-27.0727 mai 2026(Sprint vendor-Zeta Phase 1 — RelativeTime locale-aware primitive (V039) + VerifiedBadge i18n (V039-ext))
Prestataires — i18n parité 4 locales restaurée sur 2 surfaces vendor.
1.
/vendor/activity: les timestamps relatifs ("il y a 15 jours") s'affichent maintenant dans la langue de l'utilisateur. Avant : tout en français même sur/en/. Maintenant : "15 days ago" (EN), "il y a 15 jours" (FR), "hace 15 días" (ES), "15 dagen geleden" (NL).2.
/annuairecards : le badge "Vérifié" est traduit. EN → "Verified", ES → "Verificado", NL → "Geverifieerd", FR → "Vérifié". - Version 2026-05-27.0627 mai 2026(Sprint FF.3 — R-205 docs : `src/lib/auth/CLAUDE.md` decision tree (gate deferred))
Aucun changement utilisateur. Pure documentation interne pour les futures contributions code.
- Version 2026-05-27.0527 mai 2026(Sprint FF.1 — R-202 close : legacy `/rsvp/[token]` → 308 redirect, `submitPublicRsvp` deleted)
Anciens liens RSVP : les emails / invitations imprimées contenant
/rsvp/<token>continuent de fonctionner — la page redirige automatiquement (HTTP 308 permanent) vers le portail invité unifié/g/<publicId>?inv=<token>introduit Sprint AA. Aucune action requise côté invité, le flow est transparent. - Version 2026-05-27.0427 mai 2026(Sprint EE.4 — sealed letter Casa-tz helper extraction + cross-tz Vitest (BUG-232 verified-live))
Aucun changement utilisateur. La logique de calcul de l'heure de déverrouillage (23:59 heure marocaine, peu importe le fuseau du navigateur) reste identique côté UI.
- Version 2026-05-27.0227 mai 2026(Sprint EE.2 — root /not-found hydration fix : remove client tracker (BUG-263))
Page 404 branded restaurée. Quand on tapait une URL inexistante (ex:
https://mvp-mlk1.vercel.app/random-page), Chrome affichait un message générique "This page couldn't load. Reload to try again." au lieu du beau template branded "Cette page s'est égarée dans la médina". Le SSR rendait pourtant correctement (curlle prouvait) — c'était un problème d'hydration côté client. Corrigé. - Version 2026-05-27.0127 mai 2026(Sprint EE.1 — `/blog/[slug]` 500 root-cause fix + R-155 re-migration (BUG-262))
Le blog refonctionne. Les pages d'articles (
/blog/<slug>) retournaient une erreur 500 depuis quelques jours. Cause identifiée et corrigée : un appel admin Supabase mal géré qui plantait au lieu de retourner proprement un 404. Les articles s'affichent à nouveau correctement. - Version 2026-05-26.6326 mai 2026(Sprint DD Phase 5 — R-198 post-mortem + UX bounce magic-link cohérence)
UX wishlist — cohérence magic-link. Quand un invité arrive sur
/p/<slug>/cadeauxsans son lien personnel et clique « Je l'offre », au lieu d'un message d'erreur sec après soumission, il voit directement un encart explicatif (icône cadenas + « Votre lien personnel ») avec un formulaire email pour recevoir son lien. Même UX cohérente avec celle déjà en place sur/g/<publicId>sans token (Sprint AA). - Version 2026-05-26.6226 mai 2026(Sprint DD Phase 4 — R-202 RSVP triple-path partial cleanup; R-204/R-205 deferred)
Aucun changement utilisateur. Suppression de code mort côté serveur.
- Version 2026-05-26.6126 mai 2026(Sprint DD Phase 3 — catalog automation (R-206) : duplicate-signatures.md generator)
Aucun changement utilisateur. Cette livraison ajoute un artefact auto-généré qui détecte les doublons de schemas Zod automatiquement — outil interne pour les futurs audits sans grep manuel.
- Version 2026-05-26.6026 mai 2026(Sprint DD Phase 2 — audit historical claimGift + RSVP for exploit traces)
Aucun changement utilisateur. Cette livraison est un audit forensique des écritures historiques en production pour vérifier que les vulnérabilités BUG-CRITICAL (RSVP) et BUG-CRITICAL-2 (claimGift), corrigées en
.55/.56, n'ont pas été exploitées en silence avant les hotfixes. - Version 2026-05-26.5926 mai 2026(Sprint DD Phase 1 — preventive lock for token-bypass class (R-203 + R-198))
Sécurité applicative — verrou architectural anti-classe. Les corrections P0 livrées en
.55(RSVP) et.56(claimGift) fermaient deux instances de la même classe de vulnérabilité (« anonymous server action qui MODIFIE un record existant attribué à une entité nommée SANS preuve d'ownership »). Cette livraison empêche définitivement la réapparition de cette classe : tout nouveau code anonyme qui tenterait de modifier un record existant sans token de vérification déclenche une erreur de pré-push (audit-public-write-token). Côté invités : aucune différence visible. - Version 2026-05-26.5826 mai 2026(Sprint Refactor-A FOLLOWUP — revert R-155 on /blog/[slug] only (500 in prod, root cause TBD))
Correction urgente : la page de détail d'un article de blog renvoyait une erreur 500 en production après le déploiement
.57. Les autres surfaces refactorisées (annuaire prestataire, guide contrat, page « notre histoire ») restent fonctionnelles. Cette livraison restaure le code d'origine sur les articles de blog uniquement, le temps d'investiguer la cause racine. - Version 2026-05-26.5726 mai 2026(Sprint Refactor-A — R-145 sr-only h1 (a11y) + R-155 canonical URL sweep + R-167 partial env helpers adoption)
Accessibilité — pages /invites et /budget passent WCAG 2.4.6 AA. Les deux pages dashboard chip-wall / gauge n'avaient pas de titre de page accessible (les éléments visuels servent de « headline »). Un titre lisible uniquement par les lecteurs d'écran a été ajouté en tête de page (« Mes invités » / « Mon budget ») — aucune modification visuelle, les utilisateurs voyants ne remarquent rien. Les lecteurs d'écran (NVDA, VoiceOver, JAWS) annoncent maintenant le titre de la page à l'ouverture.
- Version 2026-05-26.5626 mai 2026(Sprint BB Phase 1 — HOTFIX P0 claimGift token bypass (BUG-CRITICAL-2, sister to RSVP .55))
Sécurité — protection cadeaux renforcée. Le formulaire « Je l'offre » sur
/p/<slug>/cadeauxexige désormais le lien personnel complet (avec token). Pré-fix, n'importe quel anonyme pouvait « réserver » un cadeau d'un couple en tapant n'importe quel nom — vraie sabotage potentielle d'une wishlist (un attaquant + 30 requêtes = tous les cadeaux d'un mariage faussement réservés). Désormais : sans token valide, le bouton « Je l'offre » affiche un message « Ouvrez votre lien personnel ». Les invités légitimes qui ouvrent leur lien voient le formulaire comme avant. - Version 2026-05-26.5526 mai 2026(Sprint AA Phase 1 — HOTFIX P0 RSVP bypass via /g/<publicId> sans token (BUG-CRITICAL))
Sécurité — protection RSVP renforcée. Le portail invité
/g/<publicId>exige désormais le lien personnel complet (avec token). Sans token valide, l'invité voit un écran « Votre lien personnel » avec un formulaire pour recevoir un nouveau lien par email plutôt que le formulaire RSVP. La recherche par nom (/p/<slug>) ne redirige plus directement vers le portail invité — elle déclenche le même flow magic-link par email. Aucun invité légitime n'est affecté : ceux qui ont leur lien complet voient leur RSVP comme avant. - Version 2026-05-26.5426 mai 2026(Sprint vendor-Epsilon Phase 3 — fix(vendor): V017 deals empty CTA + V038 redirect verified + R-V008/R-V010 deferred)
Page
/vendor/dealsempty state affiche désormais un bouton « Voir mes demandes » →/vendor/inquiriesquand aucun deal n'existe encore. Le prestataire a un next-step actionnable au lieu d'un cul-de-sac UX. - Version 2026-05-26.5326 mai 2026(Sprint vendor-Epsilon Phase 2 — fix(vendor): V006/V032 NL overflow + V030 partial semantic time)
Deux améliorations qualité :
- Formulaire d'inscription prestataire : titre et sous-titre s'équilibrent désormais correctement sur les petits écrans dans toutes les langues (FR/EN/ES/NL) — fini les débordements horizontaux sur les versions néerlandaises où les mots composites sont 30-50% plus longs qu'en français.
- Boîte de réception prestataire : les horodatages sont maintenant marqués sémantiquement (
<time datetime>) — meilleur support des lecteurs d'écran + extraction microformat.
- Version 2026-05-26.5226 mai 2026(Sprint vendor-Epsilon Phase 1 — fix(vendor): V024 + V035 a11y/test stability + V026/V027/V036 SSR verdict)
Aucun changement UI visible. Améliorations a11y et test-stability sur 2 surfaces vendor + clarification documentaire sur les audits SSR.
- Version 2026-05-26.5126 mai 2026(Sprint vendor-Delta — fix(vendor): V011 signup CTA + V018/V019 observability + V015 closed-as-NOT-A-BUG)
Trois améliorations vendor :
- Page d'inscription prestataire affiche maintenant un lien « Vous avez déjà un compte ? Connectez-vous » dès l'en-tête du formulaire — plus de risque de remplir 12 champs avant de découvrir qu'il faut d'abord se connecter.
- Pages
/vendor/reviewset/vendor/activityrendent désormais un état vide cohérent (au lieu de « Chargement… » bloqué) si le serveur a un problème transient — chaque incident est aussi tracé via Sentry breadcrumb pour diagnostic.
- Version 2026-05-26.5026 mai 2026(Sprint vendor-Gamma — fix(vendor): V025/R-V006 + V028 + V031 — vendor identity helper + health endpoint + TZ formatter)
Aucun changement UI visible — fondations infrastructure pour Sprint Delta. Les helpers créés seront adoptés en
.51sur ~5 surfaces avec impact UI direct. - Version 2026-05-26.4926 mai 2026(Sprint vendor-Beta — fix(vendor): V033/V034 role-aware redirects + V008 footer visibility)
Trois améliorations côté navigation et footer :
- Prestataires connectés ne se perdent plus sur le portail couple — quand un prestataire tente d'accéder à
/admin(V033) ou à des routes couple comme/dashboard//budget//invites(V034), il est désormais redirigé vers/vendor(son tableau de bord) au lieu du portail de mariage couple. Plus de confusion ni de fuite d'identité couple-side. - Lien "Espace prestataire" du footer plus visible — le groupe "Pour les pros" (lien onboarding + connexion) est désormais mis en avant : titre en gold plus clair, lien d'inscription en gras avec flèche
→(pop visuel sans surcharger).
- Prestataires connectés ne se perdent plus sur le portail couple — quand un prestataire tente d'accéder à
- Version 2026-05-26.4826 mai 2026(Sprint vendor-Alpha Phase 5 — fix(vendor): V020 H1 responsive + R-V005 PageHeader sweep 3 pages)
Deux améliorations cosmétiques/structurelles côté espace prestataire :
- Titre dashboard prestataire ne déborde plus sur mobile — la phrase narrative composée du nom + rating + nombre d'avis ("Excellence — Dar El Ghalia · 4,8 ★ · 14 avis", ~75 caractères) s'équilibre désormais correctement sur les petits écrans grâce au
text-balanceCSS + safety netbreak-wordspour les composites longs (e.g. noms de marques étendus). - 3 pages prestataires (Promotions, Calendrier, Packages) adoptent le composant
<VendorPageHeader>introduit en.45. Pixel-identique en théorie, valeur = cohérence + dé-duplication LOC pour les évolutions futures.
- Titre dashboard prestataire ne déborde plus sur mobile — la phrase narrative composée du nom + rating + nombre d'avis ("Excellence — Dar El Ghalia · 4,8 ★ · 14 avis", ~75 caractères) s'équilibre désormais correctement sur les petits écrans grâce au
- Version 2026-05-26.4726 mai 2026(Sprint vendor-Alpha Phase 3c — fix(vendor): [GDPR] V021 cascade inquiry anonymization (Wave 3 blocker))
Conformité RGPD : lorsqu'un couple supprime son compte Lalla Kenza, ses pièces jointes d'inquiry chez les prestataires sont désormais automatiquement anonymisées. L'email du couple est wipé, le nom est remplacé par "[Couple supprimé]" affiché en italique grisé, et le bouton "Contacter par email" disparaît. Le prestataire conserve l'historique des messages pour ses besoins business (traçabilité, contrats, fiscalité) mais sans aucune donnée personnelle identifiante.
- Version 2026-05-26.4626 mai 2026(Sprint vendor-Alpha Phase 4 — fix(vendor): V007 textarea label + V014 placeholder + V004 verified + 3 deferred)
Deux ajustements polish côté formulaire d'onboarding prestataire :
- Champ « Comment pouvons-nous vérifier votre identité ? » : le label est maintenant correctement associé au textarea pour que cliquer dessus place le curseur dans le champ, et que les lecteurs d'écran annoncent correctement le champ comme requis.
- Placeholder du slug :
studio-lumiere-casablanca(placeholder leftover de l'ancien seed) →votre-marque-casablanca(générique, applicable à n'importe quel prestataire).
- Version 2026-05-26.4526 mai 2026(Sprint vendor-Alpha Phase 3b — refactor(vendor): V023 + R-V005 `<VendorPageHeader>` primitive + 3 adoptions)
Aucun changement UI visible attendu — refactoring qui consolide la pré-existante structure des en-têtes de pages vendor (back-to-dashboard + icône + titre + sous-titre + bouton Aperçu public) dans un seul composant. Le pixel-exact match doit être identique post-déploiement (sinon régression).
- Version 2026-05-26.4426 mai 2026(Sprint vendor-Alpha Phase 3a — fix(vendor): V002 form validation + R-V003 vendor route protection audit gate)
Deux durcissements côté prestataire :
- Formulaire d'onboarding : les deux sélecteurs Catégorie + Ville sont maintenant explicitement marqués obligatoires (HTML
required+ ARIA), améliorant l'expérience screen-readers + déclenchant la validation navigateur si l'utilisateur les vide manuellement. - Garde-fou interne : un nouveau check pre-push vérifie que chaque page de l'espace prestataire authentifié
/vendor/*enforce bien le rôle vendor (ou délègue au middleware). Évite la régression BUG-037 (page anon sans gate) en bloquant le push.
- Formulaire d'onboarding : les deux sélecteurs Catégorie + Ville sont maintenant explicitement marqués obligatoires (HTML
- Version 2026-05-26.4326 mai 2026(Sprint vendor-Alpha Phase 2 — fix(vendor): V005 i18n title + V010 hreflang + V016 seed alignment)
Trois améliorations côté vendor + annuaire :
- Titre de page
/vendor/onboardingtraduit — était bloqué en français sur les versions /en/, /es/ et /nl/ de l'URL. Désormais chaque locale affiche son propre titre dans la barre d'onglet ("Become a vendor", "Convertirse en proveedor", "Aanbieder worden"). - Fiches prestataires
/annuaire/<slug>annoncent leurs 4 langues — Google découvre maintenant les versions FR/EN/ES/NL via les balises<link rel="alternate" hreflang>. Bénéfice SEO : meilleur ciblage geo-linguistique des SERPs. - Seed de test cohérent —
scripts/seed-test-data.mjsne crée plus le profil orphelin "Studio Lumière (test)" qui apparaissait dans l'annuaire ; le compte test-vendor@ reste lié à la vraie fiche Dar El Ghalia (14 avis, ~15 photos).
- Titre de page
- Version 2026-05-26.4226 mai 2026(Sprint vendor-Alpha Phase 1 — fix(vendor): V012 crash + V013 PhotoCard a11y + V001 onboarding name attrs)
Trois améliorations côté espace prestataire :
- Plus de "Application error" sur
/vendor/profile/photos— l'URL ne menait à aucune page (la galerie photos vit à/vendor/photos). Désormais elle redirige proprement vers l'éditeur photos dédié. - Photos prestataire accessibles aux lecteurs d'écran — chaque carte photo a maintenant 3 attributs
aria-label(légende, bouton « définir comme couverture », bouton « supprimer ») parametrés par numéro de photo. Sur un profil avec 13 photos = 39 attributs renseignés. - Formulaire d'onboarding plus robuste — les 11 champs (nom, slug, catégorie, ville, description, téléphone, WhatsApp, email, Instagram, site web, vérification) ont maintenant un
nameHTML, ce qui débloque l'auto-fill navigateur + 1Password / gestionnaires de mots de passe.
- Plus de "Application error" sur
- Version 2026-05-26.4126 mai 2026(Sprint S-FINAL Phase 2.1 bis — [SECURITY] magic-bytes 7/7 coverage + portal-photos bucket registry hotfix)
Aucun changement UI visible. Validation magic-bytes maintenant à 100% (7/7 surfaces) — couvre désormais les pièces jointes aux demandes prestataires, les pièces jointes aux messages privés, et les couvertures de posts du journal. Hotfix critique : aligne le registre
STORAGE_BUCKETSau bucket réellement utilisé en production (portal-photosau lieu deportal-gallery), sinon les wire-ins de la photo galerie portail dans.39et.40rejetaient toute photo légitime avec « Lecture du fichier impossible ». - Version 2026-05-26.4026 mai 2026(Sprint S-FINAL Phase 2.1 follow-up — [SECURITY] magic-bytes wire-ins on 3 clean confirm surfaces)
Aucun changement UI visible. La validation magic-bytes (introduite en
.39pour le guest upload du QR-code) couvre maintenant 3 surfaces supplémentaires : ajout de photo prestataire (/vendor/photos), ajout de photo couple sur le portail (/p/<slug>/photos), changement d'avatar (/profil). Toute tentative de smuggling de fichier dont le contenu réel ne correspond pas au type déclaré est rejetée avec un message clair + nettoyage automatique du fichier orphelin. - Version 2026-05-26.3926 mai 2026(Sprint S-FINAL Phase 2.1 — [SECURITY] magic-bytes validation helper + first wire-in (submitGuestPhoto))
Aucun changement UI visible. Une photo uploadée par un invité via le QR-code du jour J est maintenant validée par son contenu réel (pas juste son Content-Type déclaré) avant d'apparaître dans la file de modération. Une tentative de smuggling SVG-avec-JS sous l'extension
.jpgest rejetée avec « Format de fichier non valide. JPEG, PNG, WebP ou HEIC uniquement. » — le fichier orphelin est nettoyé automatiquement du storage. - Version 2026-05-26.3826 mai 2026(Sprint S-FINAL Phase 1.1 — [SECURITY] npm audit fix : Next.js 16.1.6 → 16.2.6 + next-intl 4.9.1 → 4.12.0 + 9 transitives)
Aucun changement UI visible. Mise à jour de sécurité des dépendances — 18+ CVEs Next.js fermés (HTTP request smuggling, CSRF bypass, XSS, DoS, cache poisoning, middleware bypass) sans changement comportemental observable.
- Version 2026-05-26.3726 mai 2026(Sprint S-FINAL Phase 1+3 batch — [SECURITY] DOMPurify blog + gitleaks pre-commit + service_role audit gate)
Aucun changement UI visible. Renforcement défensif côté sécurité — un éventuel article de blog malicieusement écrit (post pré-sanitiseur 0.83.12 ou édité hors-app via Supabase Studio) ne peut plus exécuter de JavaScript dans le navigateur des lecteurs.
- Version 2026-05-26.3626 mai 2026(Sprint Z — Trilogy X/Y/Z close + session bilan)
Aucun changement UI visible. Sprint Z = clôture documentaire du trilogy cleanup Sprint X/Y/Z.
- Version 2026-05-26.3526 mai 2026(Sprint Y — HLP-02 requireUserId canonical helper + 3 sites migrated)
Aucun changement UI visible. Helper canonical pour
requireUserId()créé + 3 actions files migrés. ~18 LOC dedup + alignement message d'erreur ("Non authentifié" français partout vs un site anglais "Unauthenticated"). - Version 2026-05-26.3426 mai 2026(Sprint X — Dead code purge DC-03 + DC-04 + DC-05)
Aucun changement UI visible. ~540 LOC + 1 DB table droppés — pure dead code cleanup.
- Version 2026-05-26.3326 mai 2026(Sprint W Phase 2+3+close — budget + server pages adoption + summary)
Aucun changement UI visible. 7 sites instrumentés Sentry breadcrumb supplémentaires (4 budget + 3 server-page reads).
- Version 2026-05-26.3226 mai 2026(Sprint W Phase 1 — failWithObservability adoption in RSVP critical path)
Aucun changement UI visible. Observability ajoutée sur les 4 throw sites du chemin critique RSVP guest. Pré-fix : échec DB sur
submitPublicRsvp→ throw avec message brut + 500 UI, pas de breadcrumb Sentry. Maintenant : breadcrumb Sentry structured + console.error + throw propage normalement. - Version 2026-05-26.3126 mai 2026(Sprint V Phase 3 + close — failWithObservability helper + Sprint V summary)
Aucun changement UI visible. Infrastructure observability ajoutée + Sprint V clôturé.
- Version 2026-05-26.3026 mai 2026(Sprint V Phase 2 — DEF-01 + DEF-02 defense-in-depth couple_id filters)
Aucun changement UI visible. 2 défects defense-in-depth résolus :
- DEF-01 : 4 SELECTs sur tables couple-scoped dans
seating/actions.ts(auto-suggest seating) gagnent un.eq("couple_id", coupleId)explicite en plus de RLS. Si RLS régresse, pas de cross-tenant read possible. - DEF-02 : 6 SELECTs parallel dans
alerts/queries.ts(dashboard alerts snapshot) gagnent le même filter explicite. - OBS-03 bonus :
partnershipsRes.errorétait oublié duPromise.allerror check — ajouté.
- DEF-01 : 4 SELECTs sur tables couple-scoped dans
- Version 2026-05-26.2926 mai 2026(Sprint V Phase 1 — SEC-04 + SEC-05 + TOC-07 pre-launch security close)
Aucun changement UI visible. 3 défects pre-launch security résolus :
- SEC-04 :
updatePaymentLink/deletePaymentLinkgated parrequireRowOwnershipen plus de RLS. Defense-in-depth. - SEC-05 :
/api/portal/[slug]/guest-lookuprate-limited 20/5min/IP. Empêche scraping d'énumération des listes invités. - TOC-07 : RSVP guest multi-événements → batch upsert atomique (single transaction). Plus de mixed state si event #2 fail après event #1 commit.
- SEC-04 :
- Version 2026-05-26.2826 mai 2026(Sprint U Phase 3 — TOC-03 + TOC-05 + TOC-06 batch concurrency fixes)
Aucun changement UI visible. 3 bugs concurrence résolus en batch :
- TOC-03 : analytics vendor sur-comptaient quand un visiteur double-firait
recordVendorEvent()(SPA hydrate + visibility change → 2 inserts dans la même seconde) - TOC-05 : 2 sondages couple OU 2 infos pratiques créées simultanément attéraient au même
sort_order→ ordre de rendu indéterministe - TOC-06 : 2 photos uploadées simultanément attéraient à la même
positiondans la galerie → ordre de rendu indéterministe
- TOC-03 : analytics vendor sur-comptaient quand un visiteur double-firait
- Version 2026-05-26.2726 mai 2026(Sprint U Phase 2 — TOC-04 budget payment cap race trigger)
Aucun changement UI visible quand le système est utilisé normalement. Vrai bug financier résolu : pré-fix, 2 acomptes saisis simultanément sur le même poste budgétaire (e.g. les 2 mariés saisissent en parallèle, ou retry post-erreur) pouvaient dépasser le cap forecast — l'estimated_amount était bypass car les 2 checks app-side voyaient le même
paid_so_faravant le premier commit. Audit architecture 2026-05-24 — TOC-04. - Version 2026-05-26.2626 mai 2026(Sprint U Phase 1.b — TOC-02 notifications dedupe race-loss recovery)
Aucun changement UI visible. Bug invisible mais réel résolu : pré-fix, deux server actions qui faisaient
notify()simultanément avec le mêmededupeKey(e.g. 2 RSVP submissions dans la même seconde, ou un retry post-erreur) pouvaient retourner{ ok: false, error: "Insert: duplicate key..." }au caller alors que la notification a en fait été créée par l'autre request. Le caller voyait ça comme une vraie failure et roll-back la mutation parente. - Version 2026-05-26.2526 mai 2026(Sprint U Phase 1 — TOC-01 wishlist envelope race-tolerant UPSERT)
Aucun changement UI visible. Bug invisible mais réel résolu : pré-fix, un double-click sur "Ajouter une enveloppe" pouvait créer 2 lignes "Enveloppes générales" doublons dans la cagnotte (race condition find-or-create). Les contributions suivantes s'attachaient à une random des 2 rows. Caught en audit architecture 2026-05-24 comme TOC-01.
- Version 2026-05-26.2426 mai 2026(Sprint T close — registry sync + summary + Wave 2 SEO 100%)
Aucun changement code-side. Documente la clôture du Sprint T : Wave 2 SEO complète à 100% (6 défects fixés sur 6), 3 R-NNN closés ce sprint (R-201, R-191, R-193), Sprint U proposé pour les TOC + adoption sweeps déférés.
- Version 2026-05-26.2326 mai 2026(Sprint T Phase 2 — R-191 getValidatedLocale helper + R-193 i18n-call-resolves gate)
Aucun changement visible. Deux ajouts d'infrastructure pour réduire la dette technique + prévenir une classe entière de bugs en production.
- Version 2026-05-26.2226 mai 2026(Sprint T Phase 1 — R-201 D026 close, dynamicParams false + Vercel rebuild hook)
Wave 2 SEO complète.
/p/<slug-faux>retourne maintenant un vrai HTTP 404 natif (au lieu du 200 trompeur précédemment). Google, WhatsApp, iMessage, Bing arrêtent enfin d'indexer / prévisualiser des pages fantômes du portail.Pour les couples qui publient leur portail : ~2 minutes de délai entre le clic "Publier" et la visibilité online (le temps que Vercel rebuild le site avec le nouveau slug dans le set statique).
- Version 2026-05-26.2126 mai 2026(Sprint S Phase 1 retest fix — D033 stub headers + R-201 logged + retest report 10)
Aucun changement visible. Retest live de Sprint S Phase 1 a montré que les headers
RateLimit-*ne s'émettent pas en production parce qu'Upstash Redis n'est pas configuré côté Vercel — le limiter degrade àALLOWqui retourneremaining: Infinity, reset: 0, et le helper retournait{}dans ce cas. Fix : emit des STUB headers (60/min refreshing in 60s) même en no-Upstash case. Le contrat d'API est maintenant cohérent quelle que soit la config backend. - Version 2026-05-26.2026 mai 2026(Sprint S Phase 1 follow-up + Phase 3 start : D033 401 headers + BUG-NEW2 /cadeaux redirect)
Deux ajustements suite à la vérification live de Sprint S Phase 1 + un premier item Phase 3 :
/api/my-coupleretourne maintenant les 4 headersRateLimit-*MÊME sur le 401 unauthentified, pas uniquement sur les 200. L'auditcurl -sI '/api/my-couple' | grep ratelimitvoit enfin ses 4 lignes./cadeaux(sans préfixe slug portail) redirige vers/wishlistau lieu de tomber sur le 404 branded. Les couples qui tapent l'URL à la main ou suivent un lien stale arrivent direct sur leur éditeur de wishlist.
Note D026 : le fix Sprint S Phase 1 a installé le not-found contextuel ("Ce mariage n'existe pas") MAIS le statut HTTP reste 200 sur
/p/<slug-faux>. Limitation Next.js 16 confirmée — la metadata stream commit avant que notFound() ne propage. Tracking comme R-201 pour Sprint T (probable solution :dynamicParams: false+ webhook Vercel deploy on publish). - Version 2026-05-26.1926 mai 2026(Sprint S Phase 1 — Wave 2 SEO trilogy : D026 + D031 + D033)
Wave 2 SEO complète. Trois bouchons SEO/auditabilité fermés en une ship :
- Les liens de portail mariage cassés (
/p/<slug-faux>) retournent maintenant un vrai HTTP 404 au lieu d'un 200 trompeur — Google, WhatsApp, iMessage savent enfin que la page n'existe pas et arrêtent de l'indexer / d'en prévisualiser un titre fantôme. - Le contenu textuel du 404 portail devient contextuel (« Ce mariage n'existe pas (ou plus) ») plutôt que le générique « Cette page s'est égarée dans la médina » qui s'affichait avant.
- Hreflang généré sur 5 pages publiques majeures (home, /annuaire, /blog, /a-propos, /p/[slug]) — chaque page expose ses 4 variantes linguistiques + un x-default. Google peut router le visiteur français vers
/, l'anglais vers/en, etc., sans hack URL.
Aucun changement visible côté authent : l'endpoint
/api/my-couple(qui alimente le widget « Compte partagé ») expose maintenant les headers RateLimit standards (60/min/user) pour qu'un client polling puisse se modérer tout seul plutôt que de se faire 429 sec. - Les liens de portail mariage cassés (
- Version 2026-05-26.1826 mai 2026(Sprint R — R-189 regression guards + housekeeping)
Aucun changement visible. Renforcement de l'infrastructure post-R-189 : 3 garde-fous + 2 nettoyages pour empêcher la régression du portail
●Static qu'on vient de débloquer après 7 sprints d'investigation. - Version 2026-05-26.1726 mai 2026(Sprint Q+ — R-189 FINAL FIX, portal ● Static)
Wave 2 SEO débloquée. Le portail public
/p/<slug>rend désormais en STATIQUE au build (Googlebot / WhatsApp / iMessage récupèrent le HTML couple complet inline plutôt qu'un skeleton Suspense). Pre-rendu confirmé pour les 2 slugs publiés actuels (/fr/p/fatima-karim-2026+/en/p/fatima-karim-2026). Le portail bascule officiellement deƒDynamic →●Static dans le build report Next.js. 7 sprints d'investigation closés. - Version 2026-05-26.1626 mai 2026(Sprint N.3 — ship SEC-03 safeUrl XSS guard on 8 public-page schemas)
Aucun changement visible. Renforcement défensif silencieux : les URL saisies par les couples (liens de paiement, sites de prestataires, hôtels, blog, etc.) ne peuvent plus accepter de schémas dangereux (
javascript:,data:,vbscript:,file:,blob:). Si une URL hostile est saisie, l'erreur "Lien non supporté (http/https uniquement)" remonte au moment de la sauvegarde au lieu d'aboutir au stockage. - Version 2026-05-26.1526 mai 2026(Sprint Q — R-189 substantial cleanup, 13 portal sub-pages migrated)
Aucun changement visible immédiat. Nettoyage architectural majeur des 13 sous-pages portail (
/p/[slug]/<section>) pour les rapprocher du rendu statique SEO Wave 2. Le portail reste enƒdynamic à cause d'un dernier résidu identifié dans next-intl 4.9 (hunt à finir avec un patch local node_modules). - Version 2026-05-26.1426 mai 2026(Sprint N.2 — SEC-01 + SEC-02 auth rate-limiter ship)
Aucun changement visible. Côté sécurité, le brute-force login et le spam-signup étaient possibles avant ce ship (les forms court-circuitaient les server actions qui contiennent le rate-limiter) et ne le sont plus.
- Version 2026-05-26.1326 mai 2026(IG cooldown — +24h safety margin, Phase 3 test deferred to mercredi 27)
Le compte à rebours Cooldown IG sur
/admin/ig-graphrepasse à mercredi 27 mai 12h (96h post-incident au lieu du strict 72h) pour ajouter 24h de marge de sécurité avant le test de reprise. - Version 2026-05-26.1226 mai 2026(Sprint N.1 — R-189 root layout collapse, partial)
Aucun changement visible. Travail architectural pour rapprocher le portail public
/p/<slug>du rendu statique (SEO Wave 2). Partiel : la collapse root layout est shippée et propre, mais une fuiteheaders()résiduelle (probablement next-intl 4.9 RequestLocale interne ou Suspense parent / Next 16 + React 19 RSC) empêche encore le portail de basculer en●Static. Hunt prévue en follow-up dédié. - Version 2026-05-26.1126 mai 2026(IG cooldown — runbook + IG_COOLDOWN_UNTIL aligned on samedi 23 J0)
Cosmétique sur le bandeau Ops de
/admin/ig-graph: le compte à rebours Cooldown IG affiche désormais la bonne date d'expiration (mardi 26 mai 12h UTC, et non plus 27 mai). Idem sur le runbook ops. - Version 2026-05-26.1026 mai 2026(Sprint M.6 — R-143 form-input-name tighten + burn-down)
Aucun changement visible. Renforcement du filet pre-push pour empêcher la classe BUG-229/236/243/248 (form fields qui défaillent l'autofill du gestionnaire de mots de passe) de revenir via un nouveau pattern de contournement.
- Version 2026-05-26.0926 mai 2026(Sprint M.5 — R-169 SupabaseImage primitive)
Aucun changement visible. Travail de fond pour rendre l'intention "ne pas optimiser via Next car Supabase fait déjà la transformation WebP" explicite au niveau du type plutôt qu'au niveau du commentaire éparpillé.
- Version 2026-05-26.0826 mai 2026(Sprint M.4 — R-142 SlideOverSheet primitive)
Aucun changement visible immédiat. Les 4 sheets côté cadeaux (AddItemSheet, OfflineEnvelopeSheet, ThankYouModal côté couple + ContributionSheet côté invité) gardent leur comportement à l'identique. Future-proofing : tout fix futur sur la classe BUG-223 (Framer Motion stuck) ou sur l'ergonomie a11y des sheets ne touche plus qu'UN fichier.
- Version 2026-05-26.0726 mai 2026(Sprint M.3 — R-150 + R-173 + R-181 audit-gate housekeeping)
Aucun changement visible. Travail sur les filets de sécurité du pre-push pour empêcher la reproduction de 2 classes de bug (BUG-218 Fragment-in-AnimatePresence + RLS-only mutation par id).
- Version 2026-05-26.0626 mai 2026(Sprint M.2 — R-184 `withAdmin` HOF mechanical sweep)
Aucun changement visible. Refactor mécanique de l'observabilité Supabase admin-client : chaque appel passe désormais par le wrapper
withAdminshipped en Sprint L.2 (R-171), qui log viaconsole.errorquand le service-role key est absent ou quand la callback throw. Vercel logs gagnent en visibilité sur les deux modes d'échec invisibles avant. - Version 2026-05-26.0526 mai 2026(Sprint M.1 — R-186 portail Link migration + queries-public split)
Aucun changement visible immédiat. Travail de fond sur l'architecture du portail public
/p/<slug>pour rapprocher la page du rendu statique (SEO Wave 2). Reste un blocker structurel résiduel (R-189) avant que la page bascule en●Static dans le build report. - Version 2026-05-26.0426 mai 2026(Sprint L.4+L.5+L.6 — perf + primitives + defense gates)
UX cold-start /parametres "Compte partagé" : la card hydrate déjà-chargée (le snapshot couple est pré-fetché côté serveur). Plus de "Chargement compte couple…" perception, plus de timeout 5s, plus de soft-hint.
- Version 2026-05-26.0326 mai 2026(Sprint L.1+L.2+L.3 — foundation cleanup avant Wave 2)
Aucun changement utilisateur direct. Foundation hardening avant Wave 2.
- Version 2026-05-26.0226 mai 2026(Sprint K — 3 audit gates + withAdmin HOF + D038 fix + R-162 diagnostic)
3 fixes utilisateur :
- Livre d'or public : 2 inputs ont enfin
name=(autofill + a11y). - Sécurité a11y/SEO : 3 nouvelles audit gates pre-push qui ferment les classes de bugs Sprint H/I/J (préviennent les futures régressions de D018, D002-D038, D026/D027).
- Investigation portail SEO : root cause D027/BUG-245 enfin identifiée (le
headers()dans[locale]/layout.tsxcascade dynamic-render à toute la chaîne). Documenté pour fix structurel sprint suivant.
- Livre d'or public : 2 inputs ont enfin
- Version 2026-05-26.0126 mai 2026(docs: refactoring registry audit — 21 new R-162→R-182 entries)
Aucun changement utilisateur (ship docs-only).
- Version 2026-05-25.3825 mai 2026(hotfix Sprint J — setRequestLocale on portal page for static-pre-render attempt)
Aucun changement utilisateur. Tentative complémentaire pour faire passer le portail public en pré-rendering statique (suite à la validation prod
.37qui montre quegenerateStaticParamsseul n'a pas suffi). - Version 2026-05-25.3725 mai 2026(Sprint J Phase 3 — P2 batch BUG-250→256)
7 améliorations PWA / SEO / UX / a11y :
- App installable sur iOS / Android (Add to Home Screen). Splash écran et identité brand respectées.
- Portail public envoie maintenant des données structurées Schema.org Event → previews riches dans WhatsApp / iMessage / LinkedIn.
- Lettre scellée : le brouillon est sauvegardé en local debounce 1s → plus de perte de contenu si la fenêtre se ferme accidentellement.
/nl/budget: les longues étiquettes néerlandaises wrap correctement au lieu d'être tronquées.
- Version 2026-05-25.3625 mai 2026(Sprint J Phase 2 — P1 fonctionnel BUG-248/249)
2 fixes UX :
/budgetrecherche : le champ de recherche annonce maintenant son rôle aux lecteurs d'écran ("Rechercher une dépense par libellé") et utilise le typesearchnatif pour bénéficier du bouton "clear" du navigateur./parametresCompte partagé : la card affiche désormais un hint "Connexion à votre compte couple…" à T+2s (au lieu de T+3s) et bascule en vue dégradée à T+5s (au lieu de T+6s). La perception de blocage par le cookie banner disparaît.
- Version 2026-05-25.3525 mai 2026(Sprint J Phase 1 — SEO portail BUG-245/246/247 bloqueurs Wave 2)
3 fixes SEO critique :
- Portail public
/p/<slug>SEO : le contenu réel (noms du couple, Save the date, programme) est désormais dans le HTML SSR initial pour tous les portails publiés. Plus de skeleton servi aux crawlers Google / WhatsApp / iMessage / Open Graph. /p/<slug-typo>retourne HTTP 404 au lieu de 200. Google ne pollue plus son index avec des URLs erronées.- Sitemap + canonical URLs cohérents avec le hostname servi. Le mvp-mlk1.vercel.app emet désormais
Disallow: /pour empêcher la double-indexation, et le sitemap pointe vers le canonical host correct du deployment.
- Portail public
- Version 2026-05-25.3425 mai 2026(hotfix Sprint I — remove `dynamic = "force-dynamic"` from /p/[slug])
Suite du fix BUG-237/238 du ship
.33: suppression de la directivedynamic = "force-dynamic"du portail public. La validation live après.33a montré que leloading.tsx nullet lenot-found.tsxco-localisés ne suffisaient pas — la directiveforce-dynamicinteragissait avec le Suspense streaming ET empêchait le propagation du status 404. - Version 2026-05-25.3325 mai 2026(Sprint I — post-Retest 7 fix batch BUG-237→244 : SEO + a11y systemic)
8 corrections cumulées suite au rapport indépendant Retest 7 :
- Portail public
/p/<slug>indexable : le contenu réel (noms du couple, Save the date, programme) apparaît maintenant dans le HTML SSR initial. Auparavant, Google et les crawlers WhatsApp/iMessage ne voyaient qu'un skeleton "Lalla Kenza • Chargement…" — le portail public était invisible aux moteurs de recherche. - Portail introuvable retourne HTTP 404 :
/p/<slug-typo>retourne désormais le code 404 correct (avant : 200), donc Google n'indexe plus les URLs erronées. - Dashboard tâches : les 5 checkboxes circulaires de "Prochaines tâches" annoncent maintenant le titre de la tâche aux lecteurs d'écran.
- Budget a11y : les 15 boutons icon-only (Ajouter paiement / Modifier / Supprimer × 5 lignes) + le chevron expand/collapse annoncent maintenant l'action ET le libellé de la dépense ("Modifier Traiteur" au lieu de "button button button").
- Login
?next=respecté :/login?next=/budgetredirige bien vers/budgetaprès connexion (race condition cookie résolue). - Profil "Nom du partenaire" verrouillé si lié : quand un compte partenaire est lié, le champ devient read-only avec hint explicatif. Plus de divergence possible avec le nom du compte lié.
- Review form prestataire : les 4 champs ont enfin
name=(autofill Bitwarden/1Password marche). - Badge rôle : truncate + tooltip pour les rôles longs.
- Portail public
- Version 2026-05-25.3225 mai 2026(Sprint H FINAL retest report — RETEST 6 live prod validation `.31`)
Aucun changement utilisateur (ship docs-only).
- Version 2026-05-25.3125 mai 2026(Sprint H Phase 3 FINAL — P3 polish BUG-235/236 + cumulative bilan)
2 polish fixes Cycle 2 P3 :
- "Contacter" sur
/annuaire/<vendor>scroll vers form ET focus le premier input → le couple peut taper immédiatement. - Register form 4 inputs ont maintenant
name=…→ autofill Bitwarden/1Password/Chrome marche.
- "Contacter" sur
- Version 2026-05-25.3025 mai 2026(Sprint H Phase 2 — P2 batch BUG-232/233/234 + 10 R-NNN refactor opportunities)
3 fixes Cycle 2 P2 batch + 10 nouvelles opportunités de refactoring loggées :
/parametres/lettre-scellee: la date de déverrouillage par défaut est maintenant toujours 23h59 Africa/Casablanca, quel que soit le fuseau du navigateur. Le hint "23h59" est honoré peu importe où le couple se connecte./annuaire/<vendor>: le formulaire "Demander un devis" est maintenant pré-rempli avec le nom + email du couple connecté. Plus de friction pour les inquiries multiples./vendor: les couples qui cliquent par erreur sur un lien vendor sont redirigés/dashboard?from=vendor(était silent redirect). Phase 3 ajoutera un toast contextuel.
- Version 2026-05-25.2925 mai 2026(Sprint H Phase 1.5 — complete batch BUG-225v2/227/228/229/230/231)
Batch de 6 fixes Cycle 2 (P1 + P2 + P3 mixés selon impact systémique) :
/parametres/lettre-scelleeplaceholder canonical : maintenant utilise le nom du partenaire LIÉ (Yassine Tazi) avec sa casse originale, plus jamais "yassir idrissi" en minuscule. Fixes BUG-225 v2 + BUG-231 en cascade.- Navbar cloche notifications : aria-label clair ("Notifications (5 non lues)") au lieu de "link" muet pour screen readers.
- Sécurité headers :
X-Powered-By: Next.jsretiré (info-disclosure leak),X-XSS-Protection: 0explicit (modern recommended value). - Login form : inputs email + password ont
name="email"/name="password"→ Bitwarden/1Password/Chrome autofill marchent maintenant. - Dropdown ville
/profil: Marrakech + Tanger listés disabled "— bientôt" pour montrer le roadmap.
- Version 2026-05-25.2825 mai 2026(Sprint H Phase 1 retest report — RETEST 5)
(Aucun changement visible — documentation interne du retest live des fixes shippés
.27.) - Version 2026-05-25.2725 mai 2026(Sprint H Phase 1 — Cycle 2 P1 batch BUG-224/225/226)
3 fixes systémiques sur les surfaces couple-side post-Cycle-2 audit :
- A11y systémique : les pages cockpit dashboard (
/dashboard,/planning,/seating,/preview) ont maintenant un<h1>valide (au lieu de zéro). WCAG 2.4.6 Headings and Labels Level AA respecté. Screen readers retrouvent le contexte de page, SEO indexe correctement. - Partner identité unifiée : sur
/parametres/lettre-scellee, le placeholder utilise maintenant le nom du partenaire LIÉ ("Yassine Tazi" depuis l'account de Yassine) plutôt que le champ texte pre-link ("Yassir Idrissi" tapé par Salma avant l'invite). Cohérence cross-surface restaurée. - Portail public SEO :
/p/<fake-slug>retourne maintenant HTTP 404 (vs 200 avant) → Google indexe correctement, plus de "soft 404" dilution. Aussi :/p/<real-slug>SSR initial response contient maintenant le vrai contenu (vs markup "égarée" mixé) → Open Graph preview WhatsApp/Twitter correctement.
- A11y systémique : les pages cockpit dashboard (
- Version 2026-05-25.2625 mai 2026(Mission F FINAL — Wave 1 GO LIMITÉ recommandé : 3/3 P0 fermés en prod)
(Aucun changement visible — documentation interne du GO LIMITÉ Wave 1.)
- Version 2026-05-25.2525 mai 2026(Mission F Phase 2 — ESC sheets V2 CSS transitions BUG-223 + cascade fix BUG-41)
Les 4 sheets V2 (AddItem, OfflineEnvelope, ThankYou, Contribution) se ferment maintenant correctement quand le couple presse ESC ou clique le backdrop. Avant : le sheet restait visuellement à l'écran (Framer Motion enter spring stuck mid-animation, exit never fired). Maintenant : disparition propre en 200ms via transition CSS native.
Validation live prod par cascade : BUG-41 (/parametres stuck) est aussi résolu — la carte "Compte partagé" charge en ~10s sur prod
.24(vs J0 stuck forever). Le fix BUG-222 Supabase Lock (.24) a éliminé la latence Lock contention qui causait le timeout. - Version 2026-05-25.2425 mai 2026(Mission F Phase 1 — Supabase Lock REAL root cause: processLock fix BUG-222)
Le warning console répété au load de chaque page dashboard (
LockManager lock auth-token timed out waiting 10000ms) est éliminé. Les couples ne le voient pas directement (DevTools-only) mais cela résoud :- 18+ exceptions console par 5 min de navigation
- 10s de latence perçue sur des opérations qui touchent la session (token refresh)
- (Probable cascade) déblocage des bugs BUG-19 ESC sheet + BUG-41 /parametres stuck si la latence Supabase causait leur timeout
- Version 2026-05-25.2325 mai 2026(Sprint E retest live report — 3 P0 status post-Sprint plan)
(Aucun changement visible — documentation interne du retest live des fixes shippés
.18 → .22.) - Version 2026-05-25.2225 mai 2026(Sprint QA post-retest C+D FINAL — Backdrop derived fix BUG-220 + listener re-confirm BUG-221 + bilan)
(Aucun changement visible — documentation interne. Le backdrop visuel a été restauré par le BUG-218 ship
.20; ce commit ne fait que tracer le dossier dérivé.) - Version 2026-05-25.2125 mai 2026(Sprint QA post-retest A3 — /parametres loading UX BUG-219)
Sur
/parametres, la card "Chargement du compte couple…" ne reste plus muette pendant 10 secondes :- À T+3s, une ligne italique grise apparaît : « C'est plus long que d'habitude — encore quelques instants… ». Le couple sait que la page n'a pas freezé.
- À T+6s (au lieu de T+10s avant), si l'API n'a pas répondu, la degraded view ("Impossible de charger… Réessayer ?") fire automatiquement. Plus d'attente patiente de 10 sec.
Le fix racine (BUG-217 Supabase singleton,
.19) avait déjà réduit la latence API typique à < 1s en éliminant la lock contention. Ce commit est défense-en-profondeur côté UX. - Version 2026-05-25.2025 mai 2026(Sprint QA post-retest A2 — ESC sheets V2 Fragment wrapper BUG-218)
Les 4 sheets V2 (AddItemSheet, OfflineEnvelopeSheet, ThankYouModal, ContributionSheet) se ferment maintenant correctement quand le couple presse ESC ou clique le backdrop. Avant le fix, le DOM restait monté visuellement même après le déclenchement du onClose (cassé visuellement, body scroll lock se libérait quand même mais le sheet "ghostait" sur l'écran).
- Version 2026-05-25.1925 mai 2026(Sprint QA post-retest A1 — Supabase Lock singleton bypass BUG-217)
Suppression du warning console répété au load de
/seating(et autres surfaces dashboard) :```
LockManager lock "lock:sb-<ref>-auth-token" timed out waiting 10000ms × 5
```
Avant le fix, ce warning fire 5× au load — pas de panne user-facing visible (l'auth refresh-token finissait par passer après ~10s par instance), mais friction perçue + observability polluée. Maintenant : 0 occurrence attendue.
- Version 2026-05-25.1825 mai 2026(Sprint QA post-retest B — i18n MISSING_MESSAGE taskCategories hotfix BUG-216)
Silence des 4 warnings console
MISSING_MESSAGE: taskCategories.{Salle & Traiteur, Neggafa, Photo & Vidéo, Animation}qui salissaient la console DevTools au load/dashboard. L'UI affichait déjà le bon libellé viasafeTfallback (donc aucun changement visible côté couple), mais la console est maintenant propre — utile pour observability et pour repérer les vrais bugs au milieu du bruit. - Version 2026-05-25.1725 mai 2026(Sprint QA polish P3 3/3 FINAL — Wontfix dossiers BUG-214/215 + Sprint 5 bilan)
(Aucun changement visible — documentation interne.)
- Version 2026-05-25.1625 mai 2026(Sprint QA polish P3 2/3 — Affordance + signage BUG-211/212/213)
Trois micro-frictions qui rendaient les surfaces
/inviteset/eventsmuettes deviennent self-documenting :- Sur
/invites, les petites icônes à droite de chaque chip invité (Confirmé ✓, Héros ✨, Restrictions 🍴, International ✈, Doublon ⚠) ont maintenant un tooltip au hover. Le couple n'a plus à deviner la symbolique. - Sur
/events, le toggle "Grand Mariage" OBLIGATOIRE est désormais clairement verrouillé : icône cadenas centrée, fond neutre gris, plus le visuel gold-actif trompeur de l'ancien toggle disabled. - Sur
/eventsSbouhi (et toute cérémonie sans dress code), une ligne italique grise "Aucun dress code · cliquez sur Modifier pour en ajouter un" remplace le blanc silencieux. Le couple sait où cliquer pour combler le manque.
- Sur
- Version 2026-05-25.1525 mai 2026(Sprint QA polish P3 1/3 — Glyph clarification BUG-209/210)
Deux décorations longtemps muettes deviennent self-explanatory au hover :
- Sur le bandeau sticky des cockpits (
/dashboard,/budget,/seating...), la ligne de petits points à côté de "13/13 tables remplies" a maintenant un tooltip qui explique : "Pictogramme : 13 tables remplies sur 21 — chaque point représente une table." Plus de bullets cryptiques. - Sur les frises décoratives zellige en haut de chaque page cockpit, le hover fait apparaître "Ornement zellige — décoration inspirée du zellige marocain." Le couple comprend maintenant que ce n'est pas un indicateur de progression mais un ornement.
- Sur le bandeau sticky des cockpits (
- Version 2026-05-25.1425 mai 2026(Sprint QA cluster UX clarté 3/4 FINAL — Cosmetic bouquet + wontfix BUG-206/207/208)
Polish bouquet sur 2 surfaces dashboard + investigation d'une fausse alerte d'audit :
- Sur
/dashboardsection "Mes héros" : chaque héros qui n'a pas encore de tâche assignée affiche maintenant "Aucune tâche assignée" au lieu du monotone "0 / 0 tâches accomplies". Copie invitationnelle plutôt que failure-flavoured. - Sur
/parametres/portal: le bouton "Enregistrer" greyed a maintenant untitlequi surface sur hover ("Aucune modification à enregistrer" ou "Enregistrement en cours…"). Le couple comprend pourquoi le bouton est inactif au lieu de croire qu'il est cassé.
- Sur
- Version 2026-05-25.1325 mai 2026(Sprint QA cluster UX clarté 2/4 — Filter rail count when zero BUG-205)
Sur
/invites,/seating,/budget, les chips de filtre dont le count est zéro affichent maintenant le 0 explicitement (avant : "Peut-être" ou "Soldé" sans count → l'utilisateur croit que le filtre est cassé). Le 0 est dimmed (text-ink-300) pour rester discret sans disparaître. - Version 2026-05-25.1225 mai 2026(Sprint QA cluster UX clarté 1/4 — 3 P1 résiduels BUG-202/203/204)
3 confusions UX visibles côté couple sont fixées en un seul commit :
- Plus de chips dupliquées sur
/dashboard"Mes héros" — un rôle ne peut plus apparaître 2 fois pour un même héro (avant : "Coordinateur·rice Communication" + "Coordinateur·rice Communication" côte à côte pour Dounia). - Le KPI budget gauge a maintenant un label de scope clair — le pourcentage du
/budgetindique explicitement "Planifié vs cible — pas le montant déjà payé" (avant : "59%" sans contexte → l'utilisateur le lit comme "% payé" alors que c'est "% planifié"). - Le badge navbar "9+" n'est plus stale quand
/notificationsest vide — si le compte serveur dit "9 non-lues" mais la liste affichée est vide ET pas tronquée (< 50 items), le badge se masque (avant : badge "9+" persistant alors que la page disait "Aucune notification").
- Plus de chips dupliquées sur
- Version 2026-05-25.1125 mai 2026(Sprint QA cluster UI cohérence 4/4 FINAL — Faire-part skeleton BUG-201)
L'aperçu du faire-part sur
/invitationsn'affiche plus un rectangle noir pendant le chargement du template. À la place : un skeleton paper-cream avec border zellige-gold, animation shimmer subtile, et texte d'attente "Aperçu en cours…". L'utilisateur comprend immédiatement que ça charge au lieu de penser que c'est cassé. - Version 2026-05-25.1025 mai 2026(Sprint QA cluster UI cohérence 3/4 — Sheet hygiene BUG-200)
Quand le couple ouvre n'importe quel slide-over V2 (AddItem, Enveloppe, Contribution guest, ThankYou) :
- Backdrop visiblement plus opaque : le fond derrière la sheet est nettement assombri + blur (avant :
bg-accent-900/30 backdrop-blur-smà peine visible →bg-accent-900/55 backdrop-blur-md). - Plus de collision sheet vs navbar : la sheet glisse maintenant AU-DESSUS de la navbar sur desktop (avant : header de la sheet caché sous l'avatar dropdown du navbar).
- Le bandeau KPI fade out quand une sheet est ouverte, ne reste plus visible en surimpression chaotique.
- Backdrop visiblement plus opaque : le fond derrière la sheet est nettement assombri + blur (avant :
- Version 2026-05-25.0925 mai 2026(Sprint QA cluster UI cohérence 2/4 — Navbar tagline cohérence BUG-199)
Tous les écrans du tableau de bord couple-side (
/wishlist,/planning,/events,/messages,/parametres,/notifications,/invitations,/mon-blog,/notre-histoire,/quiz-couple,/temoins-honneur,/family,/portail,/prestataires,/livre-dor,/photos-moderation,/faq-mariage,/infos-pratiques) utilisent maintenant le logo Navbar compact (sans tagline "VOTRE MARIAGE, NOTRE PASSION"), comme/dashboard,/budget,/invites,/seating. La chrome du produit est cohérente d'une page à l'autre. Le tagline reste sur les surfaces publiques/marketing (/,/blog,/annuaire/*,/a-propos,/contact,/outils, etc.). - Version 2026-05-25.0825 mai 2026(Sprint QA cluster UI cohérence 1/4 — Dashboard sticky overlap + KPI loader stuck)
Sur
/dashboard:- Scroll plus jamais sous le bandeau sticky : le contenu de la page laisse maintenant de la place automatiquement pour que la KPI bar + navbar ne tronquent pas le mot du haut (avant : "Trésorier·ière" coupé en "résorier·ière" au scroll vers le bas).
- Loader spinner du KPI Budget disparaît proprement : si l'API
/api/couple-summarystalle plus de 10 secondes (cold-start Supabase, réseau lent), la bar se cache gracieusement au lieu de spinner indéfiniment (avant : spinner stuck à droite de "45,5 k MAD / 265 k MAD" alors que la data était visiblement chargée).
- Version 2026-05-25.0725 mai 2026(Sprint QA cluster SSoT 4/4 FINAL — Guest stats canonical helper BUG-196)
Le KPI "X confirmés / Y total" du
/dashboardest désormais calculé via le même helper canonique qui sera adopté par/inviteset/seatingdans les prochains sprints. Aucun changement visible aujourd'hui (les chiffres sont les mêmes), mais à partir de l'adoption complète, les 3 pages afficheront cohéremment les mêmes nombres pour les mêmes questions. - Version 2026-05-25.0625 mai 2026(Sprint QA cluster SSoT 3/4 — Conversation brand label BUG-195)
Sur
/messages, quand le couple ouvre une conversation avec un prestataire (ex: "Dar El Ghalia"), chaque message du prestataire montre désormais clairement le nom de la marque à côté du nom de la personne qui répond. Avant : sidebar affichait "Dar El Ghalia" mais messages signés "Studio Lumière (test)" — confusion garantie. Maintenant : "Yassine · Dar El Ghalia" (nom personnel en gras, marque en sous-titre). - Version 2026-05-25.0525 mai 2026(Sprint QA cluster SSoT 2/4 — Wedding date snapshot write-through BUG-194)
Quand un couple change sa date de mariage (
/profil/date-mariage→ setWeddingDate), la date affichée sur leur faire-part/invitationsse met automatiquement à jour pour matcher la nouvelle valeur — à condition que la date du faire-part n'ait pas été customisée intentionnellement par le couple. Avant :/invitationsmontrait l'ancienne date snapshot pour toujours alors que toutes les autres surfaces (countdown, portail, dashboard) montraient la nouvelle. Confusion garantie. - Version 2026-05-25.0425 mai 2026(Sprint QA cluster SSoT 1/4 — Helper canonical couple-display + 9 callers migrés)
Aucun changement utilisateur direct. Sous le capot, les 9 surfaces publiques
/p/<slug>/*(home, cadeaux, livre d'or, blog, FAQ, témoins, notre histoire, photos, photos/upload) lisent maintenant le nom du couple via un seul helper canonical. Garantit qu'un futur changement de règle ("Salma & Yassir" → "Salma et Yassir", ou trim whitespace, ou fallback locale-aware) se fait en un endroit unique au lieu de 8. - Version 2026-05-25.0325 mai 2026(Sprint QA — BUG-45 hydration mismatch /seating fixé)
Le dernier P0 de l'audit 2026-05-24 est clos. Les couples qui ouvraient
/seating(vue Liste) voyaient 2 erreurs React#418dans la console à chaque visite. Côté UX : la page mettait ~30-80ms à finir de s'afficher correctement parce que React devait re-rendre tout le sous-arbre après la divergence SSR/CSR. Côté Sentry : chaque visite polluait le stream d'erreurs.À partir de cette release, plus aucune erreur d'hydratation sur
/seatingni sur/seating#plan2d. - Version 2026-05-25.0225 mai 2026(Sprint QA J1-J10 — 4 P0 hotfix + 44 tests + audit + plan 30j)
4 P0 critiques détectés à l'audit prod 2026-05-24 sont fixés :
- Hero
/wishlistV2 maintenant visible dès le mount (BUG-14) — le bandeau "NOTRE NEGGARA / Liste de cadeaux / Stats / boutons Ajouter+Enveloppe" restait à opacity 0.12 en prod. - ESC ferme les slide-overs (BUG-19) sur les 4 sheets V2 (AddItem, Contribution guest, ThankYou, OfflineEnvelope). Avant : le body scroll lock se libérait mais le sheet restait visible.
/parametresne reste plus bloqué sur "Chargement du compte couple…" (BUG-41) si la latence Supabase > 10s — un timeout AbortController bascule en degraded view au lieu d'attendre indéfiniment.- Auth-token Supabase singleton (BUG-1) — plus de timeout 10s sur le Navigator Lock entre plusieurs instances browser concurrentes.
Aucun changement utilisateur direct sur les 44 nouveaux tests Vitest ajoutés en sprint J1-J10 — c'est de la sécurité de régression.
- Hero
- Version 2026-05-25.0125 mai 2026(IG Graph — Ops bandeau live + scanned-node badge)
Pour les admins/modérateurs uniquement (page
/admin/ig-graph) :- Bandeau Operations en direct sous le cosmos 3D : 6 KPIs compacts donnant l'état du scraping IG en un coup d'œil — nombre de scans complétés, activité 24h (scans + edges gagnés), dernier scan (relative), contacts (téléphones + emails capturés), méthodes actives, et compte à rebours du cool-down IG en cours (depuis l'incident rate-limit du 23 mai).
- Badge "✦ Follow-scanné" dans le panel de sélection d'un node : signale d'un coup d'œil les profils dont les followings ont déjà été scrapés au moins une fois (par opposition aux nodes "vus" mais jamais aspirés).
- Les labels temps-relatif (« il y a 1h », « T-1j 12h ») se rafraîchissent automatiquement chaque minute sans recharger la page.
- Version 2026-05-24.0724 mai 2026(Wishlist V2 — Sprint W.8 : i18n parity 4 locales + a11y + V1 SHIPPED)
🚀 Wishlist V2 est désormais GA (V1 milestone). Après 8 sprints (W.1 benchmark → W.8 polish ship), le module complet remplace le V1 monolith de 50KB et apporte aux couples LK :
- 5 types polymorphiques : cagnottes cash, items physiques (single ou group-gift), items externes (Amazon/Marwa Maison…), expériences à offrir, demandes d'aide (do/make) — chaque type avec son flow guest dédié.
- Cagnottes famille : pattern "Famille Bennani — Lune de miel à Bali" permet à un·e invité·e d'initier une cagnotte collective que les autres rejoignent.
- Multi-devises (MAD/EUR/USD/GBP/AED) pour les contributeurs diaspora.
- Tracking remerciements : composeur slide-over avec brouillon auto-généré + canal email/téléphone/en-personne/carte postale + envoi Resend direct ou marquage manuel.
- Enveloppes offline : batch entry post-mariage pour les contributions cash reçues en main propre (pattern Moroccain neggara).
- Feed live : 20 dernières contributions visibles côté couple, badges typés, KPI "Mercis à envoyer" surfacé dès qu'il y a un backlog.
Cette release (W.8) finalise le polish ship-quality :
- 🌍 i18n parity 4 locales : 281 chaînes UI externalisées vers
fr/en/es/nl(parité stricte, aucune dette). Le module est utilisable nativement par les couples francophones, anglophones, hispanophones et néerlandophones. Tous les flows guest + couple sont entièrement traduits — du sélecteur de devise au brouillon de remerciement. - ♿ Accessibility : les 4 slide-overs V2 (ContributionSheet, ThankYouModal, AddItemSheet, OfflineEnvelopeSheet) ont maintenant :
- ESC ferme le dialog systématiquement
- Focus trap : Tab/Shift-Tab cyclent dans le dialog (wrap-around), impossible de "sortir" du modal au clavier
- Focus restore : à la fermeture, le focus revient sur l'élément qui a ouvert le sheet
- Body scroll lock : plus de double-scroll mobile pendant qu'un sheet est ouvert
role="dialog"+aria-modal="true"+aria-labelledbysur tous les conteneurs
- Version 2026-05-24.0624 mai 2026(Wishlist V2 — Sprint W.7 : thank-you tracking + AI-ready draft)
Centre de remerciements débloqué côté couple. Chaque ligne du feed "Contributions récentes" expose maintenant un bouton Merci :
- À envoyer (rose gold) → ouvre un slide-over qui pré-rédige automatiquement un mot personnalisé pour cet·te invité·e.
- Envoyé (gris transparent) → "Revoir", permet d'éditer ou de re-marquer en attente.
Composeur de remerciements (slide-over droit sur desktop, bottom-sheet mobile) :
- Rappel du contexte en haut : nom de l'invité·e, montant ou rôle d'engagement, item ciblé, message laissé par l'invité·e (cité dans un blockquote crème).
- Sélecteur de canal (4 chips) : Email · Téléphone · En personne · Carte postale. Email désactivé si l'invité·e n'a pas laissé d'adresse.
- Brouillon éditable auto-généré : 3-4 phrases en français, personnalisées selon le type (cash vs do/make), le canal (email = closing chaleureux long, carte postale = court), avec mention du montant, de l'item, et un acquittement du message laissé. Bouton Régénérer repart d'un brouillon vierge.
- Envoyer maintenant (canal email) → envoi immédiat via Resend + flip atomique
thank_you_sent=true+ close après confirmation. - Marquer comme envoyé (autres canaux) → enregistre le canal + brouillon + sent timestamp, sans envoyer.
- Annuler l'envoi sur une contribution déjà thankée → revient en "à remercier" (rétro-action, utile en cas d'erreur).
5ème KPI dans le StatsHero : Mercis à envoyer apparaît automatiquement (carte ambrée avec ring) dès qu'au moins 1 contribution thankable est en attente. Remplace dynamiquement la tuile "Engagements (Aide)" pour pousser visuellement le couple à fermer la boucle.
Compteur en haut du feed : "X mercis à envoyer" en ambre quand backlog > 0.
- Version 2026-05-24.0524 mai 2026(Wishlist V2 — Sprint W.6 : guest UI publique polymorphique)
La page
/p/<slug>/cadeauxcôté invité·e est entièrement reconstruite pour la V2. Avant : une simple liste de cadeaux à réserver avec son prénom. Après : un cockpit polymorphique qui s'adapte à chaque type d'item proposé par les mariés.Au-dessus du fil :
- Coups de cœur des mariés — jusqu'à 3 items
most_wantedmis en avant en bandeau gold, avec étiquette "Coup de cœur ✨" et photo agrandie. - Familles déjà engagées — les cagnottes famille ouvertes (ex : "Famille Bennani — Lune de miel à Bali") sont affichées en cartes avec barre de progression + nombre de contributeurs + CTA "Rejoindre". Rejoindre une cagnotte famille pré-cible son item lié et roll-up automatiquement la nouvelle contribution sous la famille.
Filtres : chips horizontaux (Tous / Cagnottes / Cadeaux / Expériences / Aide à donner) avec compteurs par catégorie.
Cartes par type :
- Cagnotte / Expérience : barre de progression gold (verte si objectif atteint) + "X MAD sur Y" + nombre de contributeurs. État "Objectif atteint ✨" verrouille le CTA.
- Cadeau (physique single) : prix + quantité + CTA "Je l'offre" (réservation). État réservé → carte dimmed + "Réservé par X".
- Cadeau de groupe (
group_gift_enabled) : devient un cash flow avec CTA "Participer en groupe". - Cadeau externe (Amazon, Marwa Maison…) : retailer name + icône lien externe.
- Demande d'aide (do_or_make) : chips par rôle (taken/total, rayé si plein) + CTA rose "M'engager". Verrouillage si toutes les places sont prises.
Sheet de contribution (slide-over droite sur desktop, bottom-sheet mobile) — un seul composant
ContributionSheetpolymorphique avec 3 sous-flows :1. Cash (cagnottes, expériences, group-gift physiques) : 3 chips de montants pré-suggérés par les mariés (fallback 500 / 1000 / 2500 MAD), input custom + sélecteur de devise (MAD / EUR / USD / GBP / AED) → pertinent pour la diaspora FR/UAE/UK/US. Champs : prénom (requis) + email (optionnel pour remerciement) + message + toggle anonymous ("masquer mon nom des stats publiques, les mariés voient toujours en privé").
2. Réservation (cadeaux physiques single) : flow classique préservé, claim atomique idempotent + thank-you email best-effort.
3. Engagement do/make : sélecteur de rôle (avec liste des engagé·e·s déjà visible) + prénom + email + note pratique. Aucun paiement, aucun montant — c'est du temps offert.
Succès affiché en plein écran avec icône check verte + copy contextuel (cash : "les mariés vous contacteront pour le paiement" / réserve : "personne d'autre ne pourra l'offrir" / commit : "ils vous contacteront pour les détails pratiques").
Section Déjà offerts en bas de page, dimmée, regroupe cadeaux réservés + cagnottes complètes + do/make pleins. Section legacy "Envoyer un cadeau en argent" (PayPal / IBAN / CashPlus) préservée comme escape hatch.
- Coups de cœur des mariés — jusqu'à 3 items
- Version 2026-05-24.0424 mai 2026(Wishlist V2 — Sprint W.5b : do/make + experience + external + offline + contributions feed)
3 nouveaux types d'items débloqués dans le sheet "Ajouter" :
- Demande d'aide (do_or_make) : rôles dynamiques (préparer henné, conduire mariées, photos zaffa, garder enfants…). Liste de presets cliquables + ajout custom + nombre de slots par rôle. Différenciateur radical vs Zola/Joy.
- Expérience : dîner Riad, atelier, séjour. Titre + description + coût estimé optionnel + photo.
- Item d'une boutique (physical_external) : produit lié à une URL externe (Marwa Maison, Décathlon…) + nom de boutique + prix.
Nouveau bouton + Enveloppe dans le header → sheet pour enregistrer manuellement les enveloppes cash reçues le jour J (mode batch : "Enregistrer + en ajouter une autre" — pas besoin de fermer entre chaque). Tracked en
payment_method='offline_cash'+payment_status='completed', intégrées aux totaux KPIs.Nouvelle section Contributions récentes au bas du dashboard couple : feed live des 20 dernières contributions (cash + do_make commitments + offline envelopes) avec icône typée, badge anonymous, montant ou rôle, item lié, status paiement, temps écoulé, message guest si présent. Empty state friendly.
- Version 2026-05-24.0324 mai 2026(Wishlist V2 — Sprint W.5a : couple UI dashboard + V1 monolith deletion)
Le dashboard
/wishlist(côté couple) est entièrement reconstruit en V2. UI polymorphique propre, anti-monolithe, supporte les 5 types d'items (cash_fund, physical, physical_external, experience, do_or_make) avec des cards visuelles différenciées. Stats hero avec 4 KPIs. Filtres tabs. Add item sheet avec sélecteur de type + formulaires dédiés cash_fund + physical (3 autres types en W.5b).L'ancienne UI monolithe (
wishlist-client.tsx~50KB) et l'API route legacy/api/wishlistsont supprimées — elles devenaient orphelines après le swap de page.tsx vers V2. - Version 2026-05-24.0224 mai 2026(Wishlist V2 — Sprint W.4.5 : integrations placeholders Stripe + WhatsApp + Email)
Nouvelle page admin
/admin/integrationsqui liste les 3 intégrations externes (Email Resend, Stripe paiements, WhatsApp Business) avec leur status global. Nouvelle page couple/parametres/integrationsqui montre quelles intégrations sont actives sur leur compte.Avant : pas de visibilité sur quelle intégration était live vs mock. Maintenant : single source of truth, registry typé, providers swappable mock → live via env var sans toucher au code des features qui les consomment.
- Version 2026-05-24.0124 mai 2026(Wishlist V2 : polymorphic data model + V2 actions + route /cagnotte → /cadeaux)
La cagnotte mariage évolue vers une liste de cadeaux multi-types (Sprint W.1 → W.4 sur 8). Refonte data complète, nouvelle URL publique
/p/<slug>/cadeaux(l'ancien/cagnotte301 redirect), tracking des contributions guest, groupes famille, et configuration de payout. UI couple sera refactorée en W.5, UI guest publique en W.6. - Version 2026-05-23.0823 mai 2026(IG scan : extraction TOTALE — cap effectif illimité)
Le scheduler de découverte IG passe en mode « extraire TOUT » — plus aucune troncature. Pour chaque compte source scanné, on récupère la totalité de sa liste de followings jusqu'à ce que l'API IG retourne plus de cursor
next_max_id(= fin naturelle de la liste).Avant : cap=7000 → comptes qui suivent >7000 personnes tronqués. Cap actuel 50 000 + safety MAX_PAGES 1000 = ceiling effectif 100 000 records. Aucun pro du mariage marocain n'approche ces volumes → effectivement illimité.
- Version 2026-05-23.0723 mai 2026(IG scheduler : cap 500 → 7000 + auto-rebuild queue ratcheting)
Le scheduler de découverte IG corrigé sur 2 points fondamentaux après audit de qualité de capture :
1. Cap par défaut 500 → 7000 : l'audit a montré que la majorité des comptes wedding-industry top suivent 1000-7000 personnes (
@douni.alami6982,@help_mariage_maroc6962,@mahane.makeup_artist6310). Cap=500 = on capturait souvent <10% des followings.2. Auto-rebuild queue (ratcheting infini) : quand la queue se vide, le scheduler invoque automatiquement
build-queue --limit 50 --min-degree 2. Pattern « 500 → 600 → 700 → … » jusqu'à saturation (in-degree < 2 pour tous les restants). - Version 2026-05-23.0623 mai 2026(IG bio enrichment worker + scheduler tag-team lock)
Nouveau worker
scripts/ig-enrich-bios.mjsqui fetch les bios + follower_count + post_count + website/phone/email pour chaque handle non-noise sans bio dansinstagram_discovery_graph. Trié parweighted_score DESC: les acteurs les plus centraux du mariage marocain sont enrichis d'abord. Vision long-terme : alimenter à terme un classifier LLM + un scoring d'onboarding basé sur le contenu réel des bios (positionnement, budget, ville, spécialisation).Coexiste proprement avec le scheduler de découverte existant via un file lock (
tmp/ig-scan-active) : tag-team option B confirmée par le fondateur. - Version 2026-05-23.0523 mai 2026(IG taxo hotfix : bola_bola = Dakka Marrakchia (dj), pas traiteur)
Correction de classification : tous les groupes Bola Bola / Issawa / Dakka Marrakchia (animation musicale traditionnelle marocaine pour mariages — percussion ta'arija/qraqeb/bendir) qui étaient mal classés
noisesont maintenantdj. C'est de l'animation cérémoniale (sortie de mairie, accueil invités, lancement festivités), pas de la nourriture comme initialement supposé à cause du token "bola".18 handles distincts reclassifiés : 11 groupes Issawa, 7 groupes Bola Bola (bolabolawahib.officiel, mohcin_bola_bola_officiel, touzani_bolabola_royal, noujoum_fes.bola_bola, etc.).
- Version 2026-05-23.0423 mai 2026(IG taxo : ajout catégorie `makeup_artist` + reclassif bulk noise)
Nouvelle catégorie MUA (makeup artist) dans la carte IG du wedding ecosystem. Avant, les makeup artists étaient dispersés entre "coiffeur" et "noise" (la majorité — leurs handles ne contenant souvent ni "makeup" ni "coiffeur"). Maintenant : couleur rose dédiée, filter chip "MUA" cliquable, taxo cohérente.
Reclassif batch : 19 rows de
@leilaboulkaddat(validée par le fondateur), +18 distinct makeup_artists détectés par le nouveau regex, +37 coiffeurs (hairstyle/hairstyler), +45 DJs (orchestre/musique), +7 photographes (graphy). - Version 2026-05-23.0323 mai 2026(IG-graph 3D : refonte Cytoscape → Three.js cosmic map)
L'explorer admin
/admin/ig-graphpasse de Cytoscape 2D à un graphe 3D Three.js. Fond cosmos navy nuit, sphères avec catégorie-couleur tunées pour dark bg, particules stellaires gold pâle en arrière-plan, auto-rotate lent contemplatif, anneaux pulsants sur les hubs (nodes connectés à ≥3 catégories distinctes), halo rouge subtle sur les anomalies de classification, edges colorés au hover du voisinage. Filtres : search handle, multi-select catégorie (cliquables avec compte), min score, hubs only, cluster par ville. Détail panel slide-in avec metrics + voisinage top-10. - Version 2026-05-23.0223 mai 2026(BUG-191 : Sign out depuis Navbar ne déconnectait pas)
Sign out depuis le Navbar (avatar menu) fonctionne correctement. Avant : click → menu fermait → mais user restait loggé côté serveur (les pages auth-gated continuaient d'être accessibles). Maintenant : click → vraie déconnexion + redirect login.
- Version 2026-05-23.0123 mai 2026(Sprint Traiteurs Phase 7c : save all followings + centrality filter ever_kept)
N/A — pipeline integrity fix. Garantit qu'on ne perd plus aucune info IG, et que les noise handles ne polluent pas la centrality.
- Version 2026-05-22.1422 mai 2026(Sprint Traiteurs Phase 7b : IG scan scheduler daemon)
N/A — dev tooling. Le fondateur peut maintenant lancer un scanner en background le matin, ça churn jusqu'au soir sans intervention, avec auto-pause sur rate-limit IG.
- Version 2026-05-22.1322 mai 2026(Sprint Traiteurs Phase 7a : extraction city depuis bios IG)
Caterers en DB ont maintenant leur vraie ville (extraction depuis bios IG). Premier exemple : Festin Traiteur listé Casablanca par défaut → corrigé en Fès.
- Version 2026-05-22.1222 mai 2026(Sprint Traiteurs Phase 6 run : Round 3 scan headless + 10 traiteurs supplémentaires)
20 traiteurs total en
caterers(status='draft'). +10 nouveaux depuis Round 3 : Fassi, Fairytale, Traiteur Elidrissi, Driss, Lahrichi, Les Merveilleux, Fettah, Chhiwates Bennani, Boutayna Himmi, Lepicerie. - Version 2026-05-22.1122 mai 2026(Sprint Traiteurs Phase 6 : Playwright headless IG scanner)
N/A — dev tooling. Débloque le scaling vers 50+ comptes scannés sans le fondateur devant l'écran.
- Version 2026-05-22.1022 mai 2026(Sprint Traiteurs Phases 5b+5c+5d+5e+5f : map vivante + 10 traiteurs draft)
- Nouvelle page admin /admin/ig-graph : explorer Cytoscape de la map IG wedding-ecosystem marocain. 200 vendors nodes colorés par catégorie, edges = follows, taille = weighted centrality. Click sur node → side panel (bio/téléphone/site/IG link).
- 10 nouveaux traiteurs dans table
caterers(status='draft', pas visibles couples) : Festin Traiteur, Amande et Miel, Fleur de Sel, Said Himmi, Elouardi, Rahal, Zineb Kaib, Benouahoud, Chams, Lamrini.
- Version 2026-05-22.0922 mai 2026(Sprint Traiteurs Phase 5a : IG scan history + centrality views)
N/A — schema infrastructure. Pre-requisite pour le futur
/admin/ig-graphqui visualisera la map du wedding-ecosystem marocain. - Version 2026-05-22.0822 mai 2026(Sprint Traiteurs Phase 4 : Round 2 transitive + cross-refs validation)
2 venues du catalogue ont maintenant leur compte Instagram capturé : Hôtel Majorelle (
lamajorelle.eventspace) et Espace Cristal (weddingcristal). À terme : badge IG cliquable depuis la fiche venue. - Version 2026-05-22.0722 mai 2026(Sprint Traiteurs Phase 3 : IG Round 1 — 281 candidates, 320 rows inserted)
N/A — backend data acquisition. Le résultat sera visible quand la page de review founder existera et qu'on insérera les validés dans
caterers. - Version 2026-05-22.0622 mai 2026(Sprint Traiteurs Phase 2.5 : IG bio enrichment + cross-ref venues)
N/A — schema extensions pre-Phase 3.
- Version 2026-05-22.0522 mai 2026(Sprint Traiteurs Phase 1+2 : schéma + identity IG-aware)
N/A — infrastructure dev. Première application du playbook
vendor-category-pipelineailleurs que sur venues. - Version 2026-05-22.0422 mai 2026(Playbook : vendor-category-pipeline)
N/A — doc interne. Bénéfice pour le prochain sprint catégorie (traiteurs, photographes, neggafa, DJs, fleuristes, etc.) : un guide reproductible qui prédit le sprint à ±20 % sur le budget temps.
- Version 2026-05-22.0322 mai 2026(Étage B : infra de redirection 301/302)
Nouvelle page admin /admin/redirects : table de règles de redirection (source → destination, 301 ou 302, raison audit). Le middleware applique ces règles avant next-intl, donc une seule règle « locale-less » couvre les 4 langues. Bouton « Créer un 301 » sur chaque ligne du
/admin/404-logqui pré-remplit la source dans le formulaire d'ajout. Propagation après création : ≤ 60 s (TTL du cache Edge). - Version 2026-05-22.0222 mai 2026(Observabilité : journal des 404)
Nouvelle page admin /admin/404-log : liste les URLs qui ont déclenché un 404 ces 7 derniers jours, groupées par chemin, avec compteur de hits + dernier référent + sample user-agents. Filtre « Masquer les bots » activé par défaut (collapse Googlebot/Bingbot/Ahrefs/etc.) pour ne garder que le trafic humain actionnable. Section « Hits récents » en bas pour repérer un lien cassé à chaud.
- Version 2026-05-22.0122 mai 2026(R-137 : pre-push gate anti-silent-fetch)
N/A — gate dev, invisible côté utilisateur. Bénéfice indirect : la classe de bug BUG-190 (« skeleton infini sur erreur fetch côté client ») ne peut plus être ré-introduite sans qu'un push soit bloqué.
- Version 2026-05-21.1121 mai 2026(P1 : /planning template apply button)
Couple qui arrive sur
/planningsans tâches voit désormais une bannière « Démarrez avec un template ? » — 1 clic = 54 tâches pré-remplies persistées en DB (avec dates calculées depuis la date de mariage). Avant : le couple voyait 54 démos client-side qui s'évanouissaient au premier ajout réel. - Version 2026-05-21.1021 mai 2026(P1 polish : blog CTA + portail infos empty state)
- Articles de blog : un visiteur SEO qui lit 4000 caractères tombe désormais sur une vraie carte CTA (« Prêt·e à organiser votre mariage ? · Créer mon espace · gratuit ») au lieu d'un simple lien inline. Lien secondaire vers
/blogpour explorer plus. - Portail public
/p/<slug>/infosvide : remplace l'italique tristounet « Pas encore de fiches dans cette catégorie » par un empty state guidant — texte d'aide + 4 exemples de fiches typiques (parking, navettes, dress code, hôtels). Le invité sait quoi attendre et pourquoi c'est vide.
- Articles de blog : un visiteur SEO qui lit 4000 caractères tombe désormais sur une vraie carte CTA (« Prêt·e à organiser votre mariage ? · Créer mon espace · gratuit ») au lieu d'un simple lien inline. Lien secondaire vers
- Version 2026-05-21.0921 mai 2026(BUG-190 : /parametres skeleton infini débloqué)
Sur
/parametres, la carte « Chargement du compte couple… » ne reste plus bloquée indéfiniment quand/api/my-coupleéchoue. Affiche désormais soit le contenu réel (cas normal), soit un message d'erreur explicite + bouton « Réessayer » (cas d'échec). - Version 2026-05-21.0821 mai 2026(BUG-189 : 404 branded sur routes non-matchées) [infra]
Tape une URL qui n'existe pas (
/infos,/foo,/invitations/bidon) → tu vois maintenant la page « Cette page s'est égarée dans la médina » avec logo + 3 cartes d'orientation (annuaire, blog, outils), au lieu du « 404 / This page could not be found » nu et anglais. Trust préservé pour quiconque tape une URL devinée. - Version 2026-05-21.0721 mai 2026(Refactor : BBOX source unique)
Rien. Refactor pur — élimine une dérive silencieuse.
- Version 2026-05-21.0621 mai 2026(Refactor : wedding-blacklist module dédié)
Rien. Refactor pur.
- Version 2026-05-21.0521 mai 2026(Refactor : helper Supabase Management partagé) [infra]
Rien visible. Cleanup interne — réduction de la duplication dans les scripts d'audit/seed/backfill.
- Version 2026-05-21.0421 mai 2026(Salles : doc sync + 5 bug fixes faibles)
Rien visible. Cleanup post-arc venues (7 ships en 24h) : documentation alignée sur l'état réel + 5 micro-bugs faibles patchés.
- Version 2026-05-21.0321 mai 2026(Salles : blacklist riads médina + Maison d'hôtes)
L'autocomplete ne propose plus les petits riads de la médina ni les maisons d'hôtes / boutique hôtels dans les premiers résultats. Insight fondateur : un mariage marocain (300-500 invités) se tient dans un palais à la Palmeraie ou une salle de fête, jamais dans un riad médina 5-20 chambres. 447 riads Marrakech, 26 Rabat, 6 Tanger correctement écrasés à score minimum. 50 venues supplémentaires enrichies (Sprint 3c partiel) avant le blacklist.
- Version 2026-05-21.0221 mai 2026(Salles : wedding-blacklist + enrichment +24)
L'autocomplete ne propose plus les hostels, écoles, banques, sites historiques, jardins communautaires, instituts de beauté, agents immobiliers, stations-service, hôpitaux etc. dans les premiers résultats — ces lieux n'organisent jamais de mariage. Ils sont écrasés à score minimum (5/100) et n'apparaissent qu'en dernier recours quand aucune vraie salle ne matche. 24 nouvelles venues enrichies en plus (Sprint 3 partiel).
- Version 2026-05-21.0121 mai 2026(Salles : enrichment Sprint 2 — Marra + reviews v2)
Top-10 autocomplete s'enrichit : Dar Laaziza (4.6★/193 avis, Bouskoura) entre en #6. 4 nouvelles salles passent en top-tier (80-100), portant la sélection « excellente » de 52 à 56 venues. La précision du scoring augmente : 78 venues qui avaient une note mais pas de compteur d'avis l'ont maintenant — le score Bayesien est plus représentatif.
- Version 2026-05-20.0420 mai 2026(Salles : autocomplete noise-terms + scoring tune)
Taper un mot-type générique dans l'autocomplete salles — « palais », « salle », « hôtel », « riad », « domaine » — retourne maintenant toutes les salles dont le nom le contient (ex : « palais » ramène Palais Elga, Palais Mirabeau, Palais des Ambassadeurs…). Avant, ces termes étaient strippés par le canonicaliseur et ne retournaient quasi rien. Les hôtels descendent un peu dans le ranking au profit des salles dédiées mariage (plus net distinct entre « lieu de mariage » et « lieu d'accueil possible »).
- Version 2026-05-20.0320 mai 2026(Salles : enrichissement bulk + scoring)
L'autocomplete salles propose maintenant les meilleures salles en premier (au lieu d'ordre alphabétique). Chaque suggestion affiche aussi le rating Google (« ★ 4.8 ») et la catégorie (« Lieu de mariage », « Salle des fêtes »…) en sous-ligne. Couverture addresses : 99-100 % (vs 35-49 % avant). Top-10 Casa actuel : Palais Elga (4.8★/150 avis), Pavillon Maya (4.7★/129), Salle Rayan (4.8★/157), Le Carré d'Or (4.5★/500), etc.
- Version 2026-05-20.0220 mai 2026(Salles : identité multi-signal + merge Ambassadeurs)
L'autocomplete salles dans le composeur ne propose plus « Les Ambassadeurs » _et_ « Palais des Ambassadeurs : Salle des Fêtes de Mariage & Cérémonies » côte à côte (même lieu, deux sources). Une seule rangée, avec le nom descriptif d'origine, les bonnes coordonnées GPS, et le fiche Google fonctionnel. 1156 salles uniques (vs 1157 dans 2026-05-20.01).
- Version 2026-05-20.0120 mai 2026(Salles : fix doublons cross-source + audit gate géo-aware)
Sur l'autocomplete salles, la rangée fantôme « Salle des Fêtes Dar El Ghalia — Casablanca » _en plus_ de la même salle taguée Bouskoura n'apparaît plus. 1 doublon mergé, 1157 salles uniques restantes. Aucun impact UX sur les autres salles (rendu d'étiquette ville préservé : « Bouskoura » continue d'apparaître pour les salles péri-zone alors que la ville canonique en base est « Casablanca »).
- Version 2026-05-19.2019 mai 2026(Autocomplete salles multi-villes — Phase C : composeur)
Sur le composeur public
/invitations, le champ Salle propose maintenant les vraies salles (4 villes), celles de la ville choisie en tête. Choisir une salle renseigne aussi la Ville automatiquement (visible dans le menu, corrigeable) et relie sa fiche Google au « Ouvrir dans Maps ». Salle absente → saisie libre, jamais bloqué. - Version 2026-05-19.1919 mai 2026(Autocomplete salles multi-villes — Phase B : /events débloqué)
Dans /events, le champ Lieu propose maintenant les salles de toutes les villes (Rabat/Marrakech/Tanger inclus, ~1000 salles qui étaient invisibles), chacune étiquetée par sa ville (« Nom — Ville ») pour lever toute ambiguïté.
- Version 2026-05-19.1819 mai 2026(Autocomplete salles multi-villes — Phase A : core + ranking)
Rien de visible encore (fondation). Prépare l'autocomplete à proposer les salles de toute ville (Rabat/Marrakech/Tanger inclus), classées par pertinence ville.
- Version 2026-05-19.1719 mai 2026(DB salles — couche curée Rabat/Marrakech/Tanger)
Ajout des salles de fête / palais des fêtes les mieux notées de Rabat, Marrakech, Tanger que la donnée OSM (orientée hôtels/riads) ratait — chacune avec son lien vers sa fiche Google dès le nom. Base à 1158 venues sur les 4 villes.
- Version 2026-05-19.1619 mai 2026(DB salles — 4 villes + enrichissement contacts OSM)
La base de salles passe de 179 à 1139 venues sur Casablanca (+ Bouskoura/Dar Bouazza), Rabat, Marrakech, Tanger — avec téléphone (261) et site web (283) quand disponibles, et un lien fiche Google pour 100 %.
- Version 2026-05-19.1519 mai 2026(DB salles — « Ouvrir dans Maps » ouvre la fiche du lieu)
Le bouton « Ouvrir dans Maps » du faire-part ouvre désormais la fiche Google du lieu (nom, photos, avis, horaires, itinéraire) au lieu d'un point GPS anonyme. Un lieu nommé rassure bien plus l'invité.
- Version 2026-05-19.1419 mai 2026(DB salles — 3 zones + couche luxe Google Maps)
La base de salles passe de 117 à 179 venues sur Casablanca + Bouskoura + Dar Bouazza, dont les salles/domaines de luxe (Dar Laaziza, Palais des Ambassadeurs, Palace Layali, Palais Elga, Prestige Palace, Victoria Palace, Pavillon des Rêves, Palais Atlas…) — proposées en autocomplete dans /events.
- Version 2026-05-19.1319 mai 2026(Fix BUG-187 — venue_id périmé après saisie libre)
Correctif invisible : quand on choisit une salle dans la liste puis qu'on la remplace par une saisie libre, le lien interne vers l'ancienne salle est maintenant bien effacé (cohérence des données — pas d'impact visible aujourd'hui, évite une mauvaise attribution future).
- Version 2026-05-19.1219 mai 2026(DB salles · POC Casablanca — Phase 4 : autocomplete /events)
Dans /events, le champ « Lieu » propose maintenant les salles connues de Casablanca à mesure que vous tapez. Choisissez-en une → nom + position exacte pré-remplis (la carte du faire-part sera précise, sans ressaisie). Salle absente de la liste ? Vous tapez la vôtre, comme avant — rien n'est bloqué.
- Version 2026-05-19.1119 mai 2026(DB salles · POC Casablanca — Phase 3 : seed OSM Overpass)
Rien de visible encore — on amorce la base : 117 salles/hôtels de Casablanca importés depuis OpenStreetMap, prêts à être proposés en autocomplete (Phase 4).
- Version 2026-05-19.1019 mai 2026(DB salles · POC Casablanca — Phase 2 : flywheel first-party)
Rien de visible — boucle d'apprentissage silencieuse : chaque salle qu'un couple saisit dans /events alimente discrètement notre future liste de salles. Aucun changement pour le couple.
- Version 2026-05-19.0919 mai 2026(DB salles · POC Casablanca — Phase 1 : fondations + cœur dédup)
Rien de visible encore — c'est la fondation d'une future amélioration : proposer aux couples une liste de vraies salles de fête (nom + localisation déjà vérifiés) au lieu de tout ressaisir et dépendre de comment un lieu est listé sur le net.
- Version 2026-05-19.0819 mai 2026(Fix BUG-186 — faire-part Programme : date exemple en dur pour tout couple)
Sur le faire-part « Riad », la section « Programme » affichait toujours « Samedi 19 septembre 2026 » (une date d'exemple), même quand le compte à rebours juste au-dessus annonçait la vraie date du mariage. Le Programme affiche désormais votre vraie date, cohérente avec le reste du faire-part.
- Version 2026-05-19.0719 mai 2026(Localisation salle — R3 : le composeur public capte le lieu)
Sur le composeur public
/invitations, un champ « Lien Google Maps » : collez-le et la vraie carte du lieu s'affiche aussitôt dans l'aperçu. À l'inscription, le lieu est repris dans votre compte — pas de ressaisie. - Version 2026-05-19.0619 mai 2026(Localisation salle — R2 : géocodage Nominatim au save)
Le couple n'a plus besoin de chasser un « lien Partager » : il tape simplement l'adresse de sa salle dans
/events→ au save, la position est trouvée automatiquement et la carte du faire-part s'affiche. (Le collage d'un lien Maps reste possible en complément, prioritaire s'il est fourni.) - Version 2026-05-19.0519 mai 2026(Fix : titre carte = salle exemple + rework plan v2 post-rétro — BUG-185)
La section « Adresse » du faire-part affiche enfin le nom de la vraie salle du couple en titre (avant : « Domaine de la Roseraie » en dur pour tout le monde, sous une carte pourtant réelle).
- Version 2026-05-19.0419 mai 2026(Localisation salle — Phase 3 : vraie carte interactive dans le faire-part)
Quand le couple a renseigné le lieu (Phase 2), la section « Adresse » du faire-part affiche maintenant une vraie carte interactive du vrai lieu (zoomable, épinglée) et le bouton « Ouvrir dans Maps » ouvre le bon endroit. Sans lieu renseigné → l'illustration
MedinaMapactuelle reste (l'art n'est jamais cassé). - Version 2026-05-19.0319 mai 2026(Localisation salle — Phase 2 : saisie Adresse + Lien Maps dans /events)
Dans Mes événements (
/events), l'édition d'une cérémonie propose maintenant « Adresse » et « Lien Google Maps ». En collant le lien « Partager » de Google/OpenStreetMap, un retour live confirme « 📍 Position détectée ». (Le rendu de la carte sur le faire-part arrive en Phase 3.) - Version 2026-05-19.0219 mai 2026(Localisation salle — Phase 1 : modèle structuré + parser maps)
Aucun changement visible. Fondations back de la feature « localisation de la salle » (plan
docs/plans/2026-05-19-venue-location-maps.md) : le couple pourra bientôt coller un lien Google/OSM Maps, et le faire-part affichera une vraie carte du vrai lieu. - Version 2026-05-19.0119 mai 2026(Fix : contenu sample en dur dans le faire-part Riad — R-126/BUG-184)
Le faire-part « Riad en aplats » ne montre plus l'exemple à la place des vraies données du couple : l'écran scellé et l'enveloppe affichaient « Aïcha & Younes » pour tout le monde ; la section Adresse et la bénédiction étaient bloquées sur « Marrakech » (+ un trajet « ≈ 25 min depuis Marrakech » inventé). Désormais : vrais prénoms sur la cover et l'enveloppe, vraie ville dans l'adresse, bénédiction sans lieu/mois en dur, et la ligne « distance » fantaisiste est retirée.
- Version 2026-05-18.0618 mai 2026(Fix : la « Ville » ne mettait pas à jour l'aperçu du faire-part)
Sur
/invitations, changer la Ville (ou la salle) met enfin à jour le lieu affiché sur l'aperçu du faire-part. Avant, l'aperçu affichait toujours « · Marrakech » quoi qu'on choisisse — déroutant, surtout pour un couple connecté dont la ville réelle n'était jamais reflétée. - Version 2026-05-18.0518 mai 2026(R-124 : gate « clé i18n orpheline » namespace-aware + ratchet)
Aucun changement visible. Garde-fou anti-récurrence.
- Version 2026-05-18.0418 mai 2026(R-123 : purge 5 clés i18n orphelines + correction du diagnostic)
Aucun changement visible (purge de clés mortes invisibles).
- Version 2026-05-18.0318 mai 2026(Rattrapage post-consolidation : copie /invitations corrigée + smoke deploy + tag d'archive)
La page
/invitationsne se contredit plus. Les sections « Comment ça marche » et « Fonctionnalités » décrivaient encore l'ancien studio modulaire (« choisissez un style : 3 templates », « pas de compte à créer », « sauvegarder plusieurs versions ») alors que le produit est UN modèle « Riad en aplats » qu'on compose librement puis qu'on enregistre via un compte gratuit. Tout le discours est réécrit pour refléter la réalité (les 4 langues). Le menu ne montre plus deux entrées (« Invitations » dans « Invités » + « Faire-part » dans « Mon mariage public ») qui menaient à la même page : une seule entrée « Faire-part », dans « Mon mariage public ». - Version 2026-05-18.0218 mai 2026(Redirections de migration : anciennes URLs faire-part → nouveau composeur)
Les anciennes adresses du faire-part (
/invitations/studio,/invitations/mine,/invitations/preview) mènent désormais automatiquement au nouveau composeur « Riad en aplats » au lieu de tomber sur une page introuvable. Mieux : un vieux lien partagé qui portait les infos du couple (?names=Salma+%26+Yassir&date=…&venue=…) pré-remplit directement le composeur — le visiteur retrouve ses données sans les retaper. Aucune URL connue ne fait plus d'impasse. - Version 2026-05-18.0118 mai 2026(Cleansing : suppression du POC galerie/showroom + namespace i18n mort + stub preview)
Aucun changement visible pour les couples. La partie faire-part a connu plusieurs POCs ; on ne maintient que le dernier — le composeur public
/invitations(« Riad en aplats », live). Tout le reste (la galerie/showroom de templates jamais lancée, l'ancienne URL d'aperçu) est retiré. Le lien « Faire-part » du menu mène désormais directement au composeur. - Version 2026-05-17.0817 mai 2026(Cleansing : purge des débris des templates faire-part abandonnés)
Aucun changement visible. Hygiène post-consolidation : suppression des résidus des templates supprimés (le studio modulaire 96-combos et le template #1 « Letterpress ») laissés par le purge initial.
/invitationsdevient un composeur public. Un visiteur non connecté renseigne ses informations (prénom de la mariée, prénom du marié, date, salle, ville) et voit son faire-part « Riad en aplats » se créer en direct à chaque frappe. Pour l'enregistrer, il crée un compte gratuit — et ses informations sont déjà pré-remplies à l'inscription, il ne les retape pas. Un couple déjà connecté voit son faire-part rempli avec ses vraies données et le bouton mène à son espace.Un visiteur non connecté qui ouvre
/invitationsvoit maintenant le faire-part « Riad en aplats » (échantillon localisé) — avant, il était renvoyé vers/loginet ne voyait jamais le faire-part. C'était précisément la régression que la consolidation devait supprimer. Les couples connectés voient toujours leurs vraies données (inchangé). Dans le showroom, le sélecteur de couleur affiche enfin l'accent : « Henné » (au lieu de « Henne »).Le studio de faire-part passe de « 96 combinaisons modulaires + 2 templates fragmentées » à une seule faire-part art-directée : « Riad en aplats ».
1. La page
/invitationsaffiche désormais votre vraie faire-part. Elle n'essaie plus de vendre l'éditeur modulaire : elle rend directement la template « Riad en aplats » remplie avec vos vraies données de mariage (vos prénoms, la date et l'heure de l'événement, le lieu, le code vestimentaire) lues depuis votre compte. Un visiteur non connecté voit la même template avec un exemple soigné (jamais de faire-part vide ou cassée).2. Faire-part muette qui ne s'affichait pas — corrigée. Des clés de traduction orphelines (héritées de l'ancien studio) faisaient planter le moteur de langue de l'app sur la faire-part, qui restait blanche. Nettoyées : la faire-part s'affiche à nouveau dans les 4 langues (FR / EN / ES / NL).
3. Galerie de templates (
/templates, en preview interne) recentrée sur l'unique template retenue, sans l'ancien moteur.L'éditeur modulaire, la template « Letterpress + enveloppe » et la galerie de presets sont retirés — le produit est volontairement resserré sur une seule belle faire-part de qualité plutôt qu'un configurateur générique.
- Version 2026-05-17.0417 mai 2026(Template #2 « Riad en aplats » — Hero v2 from claude.ai/design : monogramme tracked-caps, enveloppe locked, mashrabiya filigrane, fenêtres onion-dome)
Rework du Hero illustration + sceau + enveloppe, fait à 95% via claude.ai/design (Anthropic Labs Research Preview, Opus 4.7 dédié design). Quatre améliorations visuelles concrètes :
1. Sceau de cire — monogramme refait : remplacement du « A&Y » en script Great Vibes (qui débordait + chevauchait à petite échelle) par un monogramme tracked-caps « A & Y » en Italiana (display brand) flanquant un ampersand italic Cormorant. Uppercase lisible à toutes tailles. 3 calques par glyphe pour relief (cast shadow / mid surface / lit face) au lieu de 3 calques au total. Founder feedback 2026-05-17 : « c mieux avec des majuscules ».
2. Enveloppe verrouillée kraft/cream indépendamment du colorway. Avant, la couleur de l'enveloppe dérivait de
p.paperqui devenait sombre en nuit — une vraie enveloppe de mariage n'est jamais bleu nuit. Couleurs hardcodées (envBody=oklch(0.86 0.045 75),envBodyShade,envInk). Plus de filigrane parasite sur le rabat : il reste plain kraft sur les deux faces, le sceau au centre reste le focal.3. Mashrabiya filigrane sur arche principale : nouveau pattern
lk-riad-mashrabiya(tile 28×28) en strokecurrentColorqui contient une étoile khatem 8-branches creuse + 8 radials connectant les pointes aux bords + quart-croix aux coins (s'assemblent en croix pleines avec les tiles voisins). Permet de remplir les spandrels et le tympanum de l'arche principale en filigrane or fin sans surcharger l'intérieur de la scène.4. Fenêtres latérales onion-dome : nouvelle silhouette parametric (jambes verticales jusqu'à 50% de la hauteur → débord horseshoe → épaule onion → apex pointu) qui matche les designs de la planche de référence marocaine partagée par le founder. Remplace l'ancienne horseshoe simple. Mullion interne réduit (1 vertical au lieu de 2 vertical + 1 horizontal — plus subtil, lit pierced lattice).
- Version 2026-05-17.0317 mai 2026(Template #2 « Riad en aplats » — khatem zellige authentique + fenêtres marocaines latérales + croissant de lune propre)
Trois polish founder feedback sur l'illustration Hero :
1. La grille en X gold sur les murs latéraux (qui faisait treillis générique haut-contraste) est remplacée par un vrai motif zellige khatem — l'étoile à 8 branches qu'on voit dans toutes les madrasas et palais marocains (Bou Inania, Bahia, Ben Youssef). Couleur ton-sur-ton (rgba noir à 20%) pour que ça lise comme une texture embossée discrète, pas comme un fond chargé.
2. Une fenêtre marocaine ajoutée sur chaque mur latéral — arche en fer à cheval, mullions mashrabiya à l'intérieur, ciel nocturne visible avec une étoile à 5 branches scintillant à travers, encadrement gold avec petit allège zellige.
3. Le croissant de lune est nettoyé — l'ancien empilement de 3 cercles (disque + cercle masque skyMid + outline accent) trahissait le truc (le masque ne matchait pas exactement la couleur du ciel, l'outline servait à rien). Remplacé par un seul
<circle>avec un<mask>SVG qui fait du SET-MINUS propre. Pure silhouette de hilal, zéro élément parasite. - Version 2026-05-17.0217 mai 2026(Template #2 « Riad en aplats » — refonte illustration Hero en cour intérieure marocaine + raffinement silhouettes couple)
L'illustration Hero du template #2 est entièrement refaite. Avant ce ship, le toit incurvé de la façade + les arbres en bâtonnets + les étoiles à 8 branches lisaient « pagode chinoise » plus que Marrakech. Maintenant la scène est une cour intérieure de riad authentiquement marocaine : grande arche en fer à cheval (horseshoe) en avant-plan, mashrabiya en treillis sur les murs latéraux, palmier-dattier dans la cour, fontaine à plateaux centrale, ciel étoilé visible par l'atrium au-dessus, lanterne brass marocaine suspendue. Toutes les étoiles sont à 5 branches (étoile du drapeau marocain).
La silhouette du couple est également raffinée. Le marié a maintenant des cheveux clairement plus courts que ceux de la mariée (avant les deux portaient la même calotte noire), avec une vraie ligne de raie et un nœud papillon en forme de papillon (pas un blob jaune). La mariée a sa chevelure visible cascadant aux épaules sous le voile, des boucles d'oreilles en or, et un vrai bouquet de mariée : cinq pivoines blanches et crème, deux feuilles de sauge, ruban or autour des tiges (remplace les deux cercles jaunes qui ressemblaient à des olives).
Composition mobile-first préservée — l'aspect ratio reste 390×460, la scène fonctionne à toutes les tailles de fenêtre.
- Version 2026-05-17.0117 mai 2026(Template #2 « Riad en aplats » — rework de l'animation d'ouverture du sceau : SVG pur + chorégraphie 3 temps + axe de rotation corrigé · BUG-182)
L'animation d'ouverture de la lettre scellée du template #2 a été entièrement repensée. Avant ce ship, le tap sur le sceau de cire produisait un mouvement « pas terrible » : le monogramme
A&Ydébordait du disque doré, le rabat de l'enveloppe « scoopait » bizarrement de 14 pixels avant de basculer, la rotation 3D paraissait aplatie, et les timings étaient désaccordés (le rabat mettait 1,1 s à finir mais tout disparaissait en fondu à 0,6 s).Maintenant l'ouverture se déroule en trois temps séquencés : (1) le sceau de cire se rétracte et fade en 350 ms, comme s'il « libérait » le rabat, (2) le rabat se lève proprement autour de sa vraie charnière haute en 500 ms — avec une vraie sensation de profondeur 3D —, (3) le calque scellé s'efface en 400 ms et la carte Hero émerge avec un stagger éditorial des blocs (eyebrow → noms script → date → lieu, chacun déphasé de 110 ms). Total : ~1,5 s, lecture nette.
Le monogramme
A&YGreat Vibes a été recalibré pour tenir à l'intérieur du puits du sceau (pas de débordement même avec les jambages les plus longs du&).Aucun impact visible sur les six autres sections — seul l'écran scellé et la transition d'ouverture changent.
- Version 2026-05-16.0916 mai 2026(Template #2 « Riad en aplats » — second-pass hydration fix via dynamic-import + no-SSR boundary)
Suite du ship
2026-05-16.08: Chrome MCP a re-testé la preview Vercel après le déploiement de la première passe de fixes (a88b5d2) et l'erreur React #418 persistait — toujours plusieurs occurrences dans la console post-déploiement, et toujours le même symptôme (tap sur sceau → écran navy entièrement vide ; Countdown + Blessing apparaissent en scrollant mais Hero/Photo/Schedule/Map/RSVP restent absents ; toggle « Ouvert » continue de ne pas pré-ouvrir l'expérience).Le template #2 charge maintenant côté client uniquement (avec un squelette navy pendant le téléchargement du bundle), ce qui élimine définitivement la classe entière de bugs d'hydratation. Le reviewer Mode-B verra le squelette navy pendant ~200ms puis l'expérience riad complète apparaîtra, déjà ouverte ou sealed selon le toggle. SEO non concerné :
/templates/<slug>estrobots: { index: false, follow: false }(page de taste-gate interne, pas une surface couples). - Version 2026-05-16.0816 mai 2026(Template #2 « Riad en aplats » — fix hydration #418 + revealed sections blank)
Le template #2 « Riad en aplats » ouvrait correctement l'enveloppe scellée mais, une fois le sceau tapoté, seuls le Countdown et la ligne de bénédiction apparaissaient — le Hero (illustration riad + Aïcha & Younes en script + couple silhouettes + AVEC GRAND BONHEUR · SE MARIENT INSHA'ALLAH · Domaine de la Roseraie) restait un rectangle navy vide, et les sections Photo / Schedule / Map / RSVP étaient carrément absentes du DOM. La cause : une erreur React #418 (mismatch d'hydratation) faisait bailler React du tree à partir du Countdown — Hero/Photo/Schedule/Map/RSVP étaient les victimes collatérales.
Côté showroom (
/templates/riad-aplats), le toggle « État → Ouvert » faisait basculer l'UI du bouton mais le template restait scellé : tapotage du sceau toujours nécessaire. Désormais le toggle pré-ouvre l'expérience comme attendu, ce qui permet au reviewer Mode-B d'inspecter les 7 sections sans rejouer le ritual à chaque variant. - Version 2026-05-16.0716 mai 2026(Template #2 « Riad en aplats » → digital-experience refactor)
preset:riad-aplatsquitte le paradigme « carte papier sur écran » et devient une expérience digitale native mobile-first : enveloppe kraft scellée → tap sur le sceau de cire en relief (Canvas 2D, monogramme A&Y embossed Great Vibes) → scroll à travers 7 sections :0. Sealed — enveloppe kraft + sceau de cire 3D + nudge thé à la menthe après 12 s d'inactivité
1. Hero — illustration riad full-bleed 4 plans (atlas → drapé/arche/lanternes/zellige → palmiers/guirlandes → couple silhouettes Western)
2. Countdown — D:H:M:S live (4 unités tabular-nums, tick chaque seconde) avec easter egg « Mabrouk ! » + pluie de 14 tuiles zellige le jour J
3. Blessing — ligne de bénédiction hash-seedée (1 parmi 5 par couple/jour)
4. Photo — backdrop signature gold + indigo (rideau zellige, lanternes, halo doré) avec silhouettes Western en attendant la photo couple uploadée
5. Schedule — 3 blocs éditoriaux (Cérémonie 17h30 · Dîner 20h00 · Voiturier) avec icônes inline tintées par le colorway
6. Map — médina stylisée aplats avec pin Domaine de la Roseraie + CTA « Ouvrir dans Maps »
7. RSVP — 3 cartes radio (Oui, joie / Plus tard / Avec regrets) + compteur live « 23 / 145 ont confirmé » + 3 partages (WhatsApp / Calendrier ICS / Partager natif)
Entre sections : dividers henné qui se dessinent à l'apparition (IntersectionObserver). Greeting personnalisé « Pour {guest} » via le token
?guest=de l'URL.Le colorway par défaut bascule de
courànuit(gold + indigo = signature LK). 4 colorways dispo : Cour · Henné · Safran · Nuit, plus 5 locales : FR / EN / ES / NL / AR (RTL natif sur AR, silhouettes mirror, font swap Cairo). Le toggle bar du showroom (/templates/riad-aplats) reste identique : Colorway · Locale · State · Content · Motion. - Version 2026-05-16.0616 mai 2026(Template line #2 « Riad en aplats » — `preset:riad-aplats`)
Deuxième pièce de la ligne de templates curés (après
letterpress-sceaushippé le 2026-05-16.05). Le couple découvre maintenant un faire-part « Riad en aplats » — papier sable-crème chaud, terracotta médina, encre olive profonde, noms en cursive Great Vibes au sommet, une scène marocaine illustrée en aplats dessous (arche d'un riad blanchi à la chaux avec motif zellige dans l'embrasure, palmiers-dattiers en frondaison qui flanquent l'arche, guirlande de 5 lanternes en caténaire entre les couronnes, silhouettes Atlas en arrière-plan, et un couple — mariée en robe blanche A-line + marié en smoking — au point focal). Triptyque jour · chiffre · lieu en bas. Le rituel template #1 est reconduit : enveloppe kraft scellée par une étoile zellige 8-points ; un tap sur l'étoile déclenche la cascade illustration en 12 étapes (1350 ms).Disponible derrière le flag
NEXT_PUBLIC_TEMPLATE_GALLERY=previewsur/templates/riad-aplats. 3 colorways au choix dans le showroom :henne(registre traditionnel henné),safran(heure dorée),nuit(réception du soir, accent bleu + lanternes saffron). 4 langues (fr/en/es/nl) + arabe-script natif. - Version 2026-05-16.0516 mai 2026(Template line #1 « Letterpress + enveloppe » — `preset:letterpress-sceau`)
Première pièce de la ligne de templates curés annoncée le 2026-05-16.03. Le couple va découvrir un faire-part « Sceau de cire » — papier ivoire chaud, encre marine, noms en cursive, sceau de cire au centre, et surtout le rituel : la carte arrive _scellée_ dans une enveloppe lettrée ; un tap sur le sceau de cire la fait s'ouvrir et révèle l'invitation.
Disponible derrière le flag
NEXT_PUBLIC_TEMPLATE_GALLERY=preview: une nouvelle galerie/templatesliste la ligne curée ; chaque entrée a son showroom/templates/<slug>avec une barre de toggles (couleur · langue · scellé/ouvert · contenu court/long · animation) pour évaluer le template sur toutes ses variantes en une page. Aucun changement de la chrome existante (studio, marketing) — le redesign du site reliera les routes plus tard. - Version 2026-05-16.0416 mai 2026(Spec « gold » de référence : template #1 Letterpress + enveloppe — étalon de calibration pour la boucle)
Aucun changement visible. Pose de l'étalon qualité que Cowork donnera à Claude Design pour caler le niveau ET le format du premier template.
- Version 2026-05-16.0316 mai 2026(Pivot stratégique : ligne de templates curés vs 96-combos + scaffolding orchestration Cowork→Design→Code)
Aucun changement visible immédiat. Décision produit actée + outillage d'exécution posé : on abandonne l'approche « 96 combinaisons modulaires » exposée à l'utilisateur au profit d'une ligne de templates art-directés (à la invite.ma / Dribbble), gratuits et en 4 langues. Le couple choisira une pièce finie, plus des axes.
- Version 2026-05-16.0216 mai 2026(Doctrine image-uploads documentée + gate durci drag-drop/paste + audit exhaustif site-wide)
Aucun changement visible utilisateur. Travail d'infrastructure : garantir que la compression automatique des photos couvre vraiment tout le site, maintenant et pour toute future surface d'upload, et documenter la règle.
- Version 2026-05-16.0116 mai 2026(Studio faire-part : auto-compression photo + gate anti-régression image-normalize site-wide)
L'upload de la photo du couple dans le studio faire-part rejetait les photos trop lourdes (« Échec du téléchargement. Réessayez avec une image plus légère. »). Une photo de téléphone moderne fait 5-12 Mo — l'utilisateur n'avait aucun recours.
Désormais la photo est automatiquement optimisée dans le navigateur avant l'envoi : redimensionnée (≤ 2400 px), ré-encodée WebP qualité 0.85, métadonnées EXIF supprimées (vie privée). Une photo de 8 Mo devient ~400 Ko. Toutes les photos passent, et elles se chargent plus vite chez les invités. C'est le même comportement que les autres surfaces du site (photos prestataires, galerie portail, livre d'or, messagerie).
- Version 2026-05-15.0815 mai 2026(Ship 2.5 hotfix : darken photo-full-cover placeholder wash pour fixer le contraste texte-overlay — Chrome MCP retest)
Le preset
Photo cursive romantique(preset:photo-cursive-romance) montrait un faire-part presque illisible quand le couple n'avait pas encore uploadé sa photo : les noms cursifs blancs apparaissaient sur un fond rose pastel ultra-clair, contraste quasi-nul. Le wax seal, la date et le venue étaient à peine visibles.Fix : le placeholder (sans photo) utilise désormais un dégradé
accent → text(du dusty-rose au brun-rose pour la palette rose-pastel), simulant la luminosité d'une photo réelle. Les noms cursifs blancs ressortent immédiatement. Quand une vraie photo est uploadée, le rendu reste identique (le placeholder n'est plus dessiné). - Version 2026-05-15.0715 mai 2026(Ship 2/3/4 hotfix : Framer Motion stuck opacity:0 + i18n keys non résolues — révélé par Chrome MCP test pass)
Chrome MCP test pass post-Ship 4 a révélé deux bugs critiques qui rendaient le studio inutilisable :
Bug A — Cartes preview vides : Framer Motion stuck à
opacity: 0sur les blocks. L'initialest appliqué (opacity:0) mais l'animatene fire pas après hydratation. Probable race condition SSR/hydration sur Vercel.Bug B — Labels des presets en raw : le picker affichait
invitationDesign.preset.dore-classicau lieu de « Doré classique ». Cause : next-intl interprète les.dans les clés comme path nested, et mon JSON merge avait écrit les clés en flat avec dots dans le nom. - Version 2026-05-15.0615 mai 2026(Pre-push gate : `next build` ajouté pour prévenir les silent deploy failures du type Ship 1-2-2.5)
Aucun changement utilisateur. Ship interne d'infrastructure.
- Version 2026-05-15.0515 mai 2026(Ship 4 / invitation studio : Framer Motion entrances + animations SVG natives — le faire-part respire)
Le faire-part prend vie au mount du renderer :
- Entrance orchestration Framer Motion : chaque bloc apparaît avec un fade + slide-up subtil, staggered par index. 3 intents :
subtle(défaut) — 50ms stagger, 350ms easeOut. Discret.ceremonial— 120ms stagger, 600ms easeInOut. Pour Photo cursive romantique.playful— spring, 80ms stagger. Pour Wedding App.- Sceau de cire qui « respire » : scale 1 → 1.015 → 1 en 4.5s + SMIL sur le highlight gradient (effet cire fraîche).
- Hairlines dorées qui « shimmerent » : gradient sweep 6s (effet métal poli).
- prefers-reduced-motion respecté partout — désactivation automatique pour a11y.
- Version 2026-05-15.0415 mai 2026(Ship 3 / invitation studio : CountdownBlock + MapsLinkBlock + EditorialBlock — le faire-part devient une mini-app)
Ship 3 transforme le faire-part d'une « carte statique » en une mini-app utile pour les invités. 3 nouveaux types de blocks + 1 nouveau layout + 1 nouveau preset :
1. CountdownBlock — décompte live jusqu'au jour J. 3 granularités (jours / heures-min-sec / format compact). Mise à jour 1×/sec en mode HMS, 30s en compact, 5min en days. Affiche « Aujourd'hui ! » / « Demain » / « Passé » selon le contexte.
2. MapsLinkBlock — bouton « Itinéraire » qui ouvre Google Maps avec le lieu pré-rempli. URL universal-link Google Maps → route automatiquement vers l'app native sur mobile (iOS / Android). 3 variants visuels (filled / outline / ghost) × 3 formes (pill / rounded / sharp).
3. EditorialBlock — section éditoriale free-text style invite.ma : titre + body. Supports FR + AR. Pour « Enfants admis · Les enfants sont les bienvenus », « Code vestimentaire · Tenue traditionnelle marocaine », « Cadeaux · Vos vœux nous suffisent », etc. 3 variants (card / minimal / outlined).
4. Nouveau layout
wedding-app— vertical phone-screen feel (aspect 0.55) avec frieze + names + date + venue + countdown + maps button + editorial section. Le couple obtient en 1 preset un faire-part « mini-app ».5. Nouveau preset
wedding-app-dore— combine wedding-app layout + palette doré + typo Cormorant. Le picker passe à 10 presets. - Version 2026-05-15.0315 mai 2026(Hotfix : Vercel build cassé depuis Ship 1 — collision de routes `/invitations` entre landing publique et dashboard couple)
Ship 1, Ship 2 et Ship 2.5 n'avaient jamais atteint la production : Vercel rejetait silencieusement chaque build et rollbackait à
2026-05-14.10. Le site live restait sur l'ancienne version sans aucune indication d'échec.Conséquence : le
/invitations/studio?preset=...partagé tout à l'heure renvoyait 404 (la route n'existait pas dans le build deployé). Toutes les nouveautés du moteur modulaire + photo + cursive étaient invisibles pour les utilisateurs. - Version 2026-05-15.0215 mai 2026(Ship 2.5 / invitation studio : photo couple plein-cadre + cursive Great Vibes + sceau de cire — match visuel d'invite.ma)
Après comparaison directe avec invite.ma (concurrent marocain), j'ai constaté que leur « premium feel » ne vient PAS de Lottie ou d'animations complexes — c'est du Shopify classique. Le facteur waow vient de 3 éléments visuels précis qu'on n'avait pas :
1. Photo du couple plein-cadre en arrière-plan
2. Typographie cursive (Great Vibes-style) pour les noms
3. Sceau de cire comme centerpiece
Ship 2.5 ajoute ces 3 éléments à notre moteur modulaire. Concrètement dans le studio :
- Nouvelle section « Photo du couple » dans le form : upload click-to-browse, preview live, bouton retirer. JPG/PNG/WebP, 5 Mo max.
- Nouveau layout « Photo plein cadre + cursive » : la photo téléversée devient le fond plein-cadre, avec scrim 35% + vignette pour la lisibilité du texte par-dessus.
- Nouvelle typographie « Cursive — Great Vibes » : police calligraphique pour les noms du couple. Body reste en Cormorant.
- Nouveau sprite « Sceau de cire » : centerpiece SVG inline avec gradient highlight + monogramme M.
- Nouveau preset « Photo cursive romantique » : combo qui showcase les 3 nouveautés.
Le picker passe de 8 à 9 presets. Quand la photo n'est pas téléversée, le layout photo-full-cover affiche un gradient palette wash en fallback — gracieux « avant-upload ».
- Version 2026-05-15.0115 mai 2026(Ship 2 / invitation studio refonte : moteur modulaire à 3 axes Layout × Palette × Typographie)
Le studio de faire-part bascule du modèle « 3 templates monolithiques » vers un moteur modulaire à 3 axes :
- 4 layouts : Vertical classique · Bandeau horizontal · Photo plein cadre · Minimal centré
- 6 palettes OKLCH : Doré · Sauge · Indigo · Terracotta · Noir · Rose pastel
- 4 typographies : Fraunces moderne · Cormorant élégant · Italiana éditorial · Manrope minimal
- 8 presets curated dans le picker (vs. 3 templates avant) — chaque preset = combinaison vérifiée d'un layout × palette × typo
Concrètement, dans le studio :
- Le picker affiche maintenant 8 cases au lieu de 3, chacune avec ses 2 pastilles de couleur
- Le rendu (sur les cards FR/AR/EN) utilise les nouvelles fontes Cormorant Garamond + Italiana en plus de Fraunces + Manrope existantes
- Les designs sont rendus en HTML/SVG/CSS pur (server component), SEO-friendly + email-friendly
- Le faire-part affiche les noms en arabe (police Cairo, direction RTL) automatiquement quand on affiche la carte AR — plus de double-blocs codés à la main
Les 3 anciens templates (classic-dore, henne-vert, modern-blanc) continuent de fonctionner via un legacy resolver : pas de migration nécessaire, les designs déjà sauvegardés s'affichent identiquement.
Animation des décors et entrées : arrive en Ship 2.5 (next ship — invoque le skill
svg-animationspour les zellige animés + Framer Motion pour les reveals). - Version 2026-05-14.1114 mai 2026(Ship 1 / refonte invitation studio : fondations — marketing landing + studio relocation + DB persistence + i18n 4 locales)
User a décidé de refondre complètement le studio de faire-part. Ship 1 (sur 3) pose les fondations sans changer le design ni l'éditeur — l'objectif est de débloquer les vrais P0 avant les ships UX.
Nouveautés visibles :
/invitationsest désormais une landing marketing publique (avant : 404). Hero avec aperçu live d'un faire-part, présentation 3-étapes, galerie de templates cliquable, features grid, CTA final./invitations/studioremplace/invitations/preview(le nom préfigurait mal — c'est un éditeur, pas un aperçu). L'ancienne URL/previewcontinue de fonctionner via une 308 redirect avec préservation des query params (toutes les URL faire-part déjà partagées avec la famille resteront actives).- « Sauvegarder dans mon compte » : nouveau bouton dans le studio pour les couples connectés. Auto-save 1s après le dernier keystroke. Indicateur de statut (saving · saved · error) en pied de form.
- « Mes faire-parts » : nouvelle page
/dashboard/invitationsqui liste les designs sauvegardés du couple. Edit en un clic, vue de toutes les versions. - i18n parité 4 locales (fr/en/es/nl) : 67 nouvelles clés sur 3 namespaces (
invitationStudioenrichi,invitationsLanding+invitationsDashboardcréés). Visiteurs sur/en/invitationsvoient enfin de l'anglais (avant : tout était hardcodé en français).
Ce qui n'a PAS changé (pour Ship 2) :
- Les 3 templates existants restent (classique-doré, henné-vert, moderne-blanc) — le moteur modulaire 3-axes arrive en Ship 2
- Le form de l'éditeur reste plat 2-colonnes — le wizard / drag-and-drop arrive en Ship 3
- Version 2026-05-14.1014 mai 2026(BUG-179 fix : le morph Option C ne se déclenchait jamais — IntersectionObserver observait `null` parce que le sentinel arrivait après le mount du provider)
Après le ship 2026-05-14.09 qui débloquait la
CoupleSummaryBar, le morph Option C ne s'activait toujours pas au scroll. Tu scrollais, le cockpit disparaissait du viewport, et la barre restait sur sa ligne event-wide au lieu de basculer vers les stats page-specific.Maintenant : sur
/seating,/budget,/planning,/invites, au scroll past du cockpit, la barre swap instantanément vers la version page-specific (ex. « 121/156 placés · 35 sans table »). Re-scroll en haut → retour à la ligne event-wide. Animation fluide en 160 ms (fade + slide). - Version 2026-05-14.0914 mai 2026(BUG-178 fix : CoupleSummaryBar bloquée en placeholder permanent — Option C morph désormais visible)
Pendant le test pass du ship 2026-05-14.08, je suis tombé sur un bug critique : sur toutes les pages dashboard couple-side (
/seating,/budget,/planning,/invites,/dashboard,/parametres…), la barre sticky qui affiche habituellement « J-X · invités confirmés · budget · tables remplies » restait bloquée sur un placeholder vide de 53 px indéfiniment. Aucune information ne s'affichait — juste un trait blanc sous la navbar.Conséquence : le ship Option C de tout à l'heure (le morph navbar↔cockpit) n'avait littéralement aucun effet visible, parce que la barre qui devait recevoir le morph n'arrivait pas à monter sa version populée.
L'utilisateur l'avait déjà signalé plus tôt (« y a une barre vide et une barre au dessus, c'est normal ? faut pas les merger ? ») mais on pensait que c'était lié au cockpit. C'était en fait un bug latent de la barre.
Ce que tu vois maintenant :
- Placeholder visible ~150 ms le temps que
/api/couple-summaryréponde, puis transition douce vers la ligne populée. - Au scroll : sur
/seating, la barre passe à « 121/156 placés · 35 sans table », sur/budgetà « 45.500 / 265.000 MAD · 17% », etc. — c'est-à-dire le morph Option C qui marche enfin. - Sur
/dashboard: pas de morph (volontaire), juste la barre event-wide qui reste affichée.
- Placeholder visible ~150 ms le temps que
- Version 2026-05-14.0814 mai 2026(Option C cockpit shipped : la summary bar morphe entre stats event-wide et stats page-specific au scroll)
User a choisi Option C dans la preview comparative
/preview/cockpit/{a,b,c}. Le verdict était clair : « morph hybride » — au repos la barre sticky sous le navbar continue d'afficher l'aperçu de tout le mariage (J-X · invités confirmés · budget · tables remplies, comme aujourd'hui), mais dès qu'on scrolle au-delà du cockpit étendu de la page, la barre absorbe les stats page-specific + le CTA principal.Concrètement, sur les pages avec cockpit :
/seating: la barre passe de « J-7 · 130/162 confirmés · 12k/30k MAD · 13/13 tables » à « 130/162 placés · 32 sans table » pendant qu'on scrolle la grille de tables — le contexte d'action reste collé en haut./budget: passe à « 12 450 / 28 900 MAD · 43% » avec le bouton + Ajouter une dépense toujours accessible./planning: passe à « 18/40 fait · 3 en retard · 45% » avec le bouton + Ajouter une tâche en sticky./invites: passe à « 130/162 confirmés · Relancer 14 » avec la CTA Relancer toujours visible./dashboard(home) : pas de morph — la barre event-wide est déjà la bonne info sur cette page.
Mobile (< 768px) : pas de morph, le cockpit scrolle normalement avec la page. Confirmé par l'user dans la phase de décision (« pas de navbar pour le mobile »).
Le trigger est précis :
IntersectionObserversur une sentinelle posée au bas du cockpit étendu — le morph se déclenche à la frame près quand le cockpit sort du viewport, pas à un seuil arbitraire de pixels. - Version 2026-05-14.0714 mai 2026(Preview cockpit : enrichi avec mock complet de /seating pour donner du contexte aux bars)
User feedback : « fill the bars so that I see the final look and decide ». La preview précédente avait juste une grille minimaliste de fake tables ; les bars (navbar + cockpit) paraissaient hors-contexte. Maintenant les 3 pages preview rendent un clone fidèle de
/seating: filter rail à gauche + tables column au centre + pool « Sans table » à droite.URLs (inchangées) :
/preview/cockpit/a— Sticky 2-bar/preview/cockpit/b— Page scroll (current ship)/preview/cockpit/c— Hybrid morph
Chaque page montre maintenant les bars dans leur vrai contexte d'utilisation.
- Version 2026-05-14.0614 mai 2026(Cockpit redesign : 3 preview pages live pour comparer A / B / C en scroll réel)
Pages preview internes (auth-gated) pour comparer les 3 options de design de la barre cockpit, suite à la demande user « create pages for illustration ». Chacune est un environnement complet (navbar dashboard réel + cockpit + 12 fake tables) où l'utilisateur peut scroller réellement pour ressentir la différence de comportement.
URLs :
/preview/cockpit/a— Sticky 2-bar (compact bar persistante sous le navbar)/preview/cockpit/b— Page scroll (current ship — cockpit scrolle avec la page)/preview/cockpit/c— Hybrid morph (navbar absorbe les stats quand scrolled)/preview/cockpit→ redirige vers/preview/cockpit/b
Switcher flottant en haut de chaque page pour basculer rapidement entre les 3.
- Version 2026-05-14.0514 mai 2026(Méta : 4 nouvelles règles CLAUDE.md + BUG-177 consolide la cascade seating + nettoyage des comment-bloats)
Pas de changement utilisateur. Ship interne suite à un post-mortem demandé : « what could you have done better here ? ». L'audit a remonté 7 process improvements ; cette release en livre 3.
- Version 2026-05-14.0414 mai 2026(Header dashboard : homogénéisation — suppression du compact cockpit sticky sur les 6 pages cockpit)
User feedback : « faut pas merger les 2 bandes et garder que la bande large grande ? Aussi, fait un assessment de l'homogénité de cette barre sur tout le site. »
Avant : 18 pages dashboard, header inconsistant :
- 6 pages avec
<DashboardCockpit>(budget, dashboard, invites, planning, seating) → navbar 65px + compact cockpit sticky 40-50px = ~115px de sticky UI - 12 pages sans cockpit → navbar 65px = ~65px de sticky UI
Maintenant : header homogène partout. Navbar (65px) est la SEULE bande sticky sur l'ensemble du site. L'expanded cockpit (la grosse section en haut des 6 pages cockpit) continue d'exister comme contenu de page — il scroll naturellement quand on descend. Plus de redondance visuelle, plus de discrepance entre pages cockpit / non-cockpit.
Trade-off accepté : sur les 6 pages cockpit, si on scrolle loin la status persistante (« MARIAGE 121/156 placés ») disparaît. Pour la retrouver → scroll up. Cohérent avec ce que font 99 % des dashboards productivity (Linear, Notion, Asana — navbar uniquement, contexte dans le contenu de page).
- 6 pages avec
- Version 2026-05-14.0314 mai 2026(Navbar + cockpit compact : fusion visuelle (suppression du border-b doublon))
User feedback : « y a une barre vide et une barre au dessus, c'est normal ? faut pas les merger ? »
Avant : la navbar dashboard a un
border-b border-ink-200. Le cockpit compact sticky qui dock juste en-dessous (àtop-[65px]) a aussi son propreborder-b+shadow-md. Résultat : 2 lignes horizontales visibles entre navbar / cockpit / contenu — l'impression de 2 barres stackées.Maintenant : un seul « header strip » visuel. Sur les pages avec cockpit, la navbar perd son
border-b→ la navbar et le cockpit forment un bloc unifié. Leborder-b+ shadow du cockpit reste comme seule séparation header/contenu.Sur les pages sans cockpit (login, certaines pages settings), la navbar garde son
border-b— le selector:has()est opt-in. - Version 2026-05-14.0214 mai 2026(Plan de table : amend BUG-176 — « à inviter » visible partout, seuls les déclinés exclus)
User feedback (correction du premier fix BUG-176) : « non pour moi à inviter doivent être dans les deux cotés car on a prévu de les inviter. On exclut seulement ceux qui ont confirmé qu'ils seront pas là. »
Le
2026-05-14.01avait mal interprété le spec : il EXCLUAITto_invitepartout (cockpit + pool + auto-suggester). Le SPEC réel inverse :to_invitedoit apparaître dans le seating pour que le couple puisse pré-placer ces invités avant d'envoyer l'invitation formelle.Maintenant :
- Cockpit, pool, auto-suggester : tous voient les
to_invite - Seuls les
declinedsont exclus - Nouvelle checkbox « À inviter » dans le rail STATUT (cochée par défaut, dot ink-soft neutre placée en premier de la liste de stages)
- Cockpit, pool, auto-suggester : tous voient les
- Version 2026-05-14.0114 mai 2026(Plan de table : hotfix BUG-176 — cockpit ↔ pool count alignment (32 vs 28))
User feedback : « les sans tables c'est 32 à gauche mais 28 à droite ? »
Avant : cockpit montrait
Sans table 32, pool « Sans table (28) ». 4 invités fantômes en plus côté cockpit. Cause : les invités à statut « to_invite » (rowguest_event_rsvpexists maisstatus = NULL+invited_at = NULL+opened_at = NULL) passaient le filtre serveur mais étaient cachés par le filtre client.Maintenant : un seul prédicat
isVisibleInSeating(rsvp)partagé entre cockpit, pool, auto-suggester. Les 3 surfaces voient la même headcount. - Version 2026-05-13.4213 mai 2026(Plan de table : 2 hotfixes — BUG-174 declined-out-of-auto-suggest + BUG-175 planner sync depuis initial)
User feedback (screenshot) : « rien ne va dans cette vue, une part affiche 43 sans table, une autre 49 (exclue pas les declined), et les tables ne sont pas mises à jour automatiquement quand on clique sur proposer plan. »
3 incohérences observées :
1. Cockpit affichait
43 sans tableMAIS toast affichait49 sans place(= 49 incluait les déclinés)2. Tables ne se mettaient pas à jour visuellement après « Proposer un plan » (mais cockpit oui)
3. Pool « Sans table (57) » ≠ cockpit « 43 sans table » (même cause que #2)
- Version 2026-05-13.4113 mai 2026(Plan de table — Sprint K.11.1 : la parenthèse gold est maintenant draggable comme un groupe entier)
User feedback : « je veux pouvoir selectionner et dragger le groupe aussi quand je clique sur la barre laterale gold. Ainsi, si je bouge les deux à la fois. »
Avant : pour déplacer un couple entier, il fallait drag UN chip, attendre la modale 3-boutons (« Déplacer le groupe entier » / « Détacher » / « Annuler le groupement »), cliquer confirmation. 2 actions + 1 décision pour ce qui devait être un seul geste.
Maintenant : un petit grip icon
⋮⋮gold pâle apparaît sur la parenthèse qui englobe le couple (haut-gauche, ring-1 brand). Drag-and-drop ce grip → les 2 membres du couple bougent ensemble vers la table cible. Pas de modale, intent explicite (le user a choisi le bracket comme handle).Drag chip individuel = comportement inchangé : modale 3-boutons pour confirmation. C'est l'override « détacher du couple », pas le geste principal.
La parenthèse draggable est disponible :
- À table : couple entièrement assis sur la même table (existait déjà visuellement K.9.30, maintenant draggable)
- Dans la pool « Sans table » sticky-aside (xl+) : couple entièrement sans table — la parenthèse + son grip apparaissent en couvrant les 2 chips
- Drop sur "Sans table" : désassigne les 2 membres en parallèle
La pool default (mobile/lg grid) garde le rendu flat (les couples sont adjacents grâce à
reorderCouplesAdjacentK.9.28, mais un bracket dans un grid casserait la mise en page). - Version 2026-05-13.4013 mai 2026(Plan de table : barre de recherche sticky + couleur distincte dans la pool « Sans table »)
User feedback : « quand on scroll les sans tables, il faut que la barre recherche soit visible mm si on va plus bas. De plus, il serait bien de pouvoir la différentier en ayant une autre couleur. »
Avant : le header (titre + search input) défilait avec la liste. Pour chercher un invité quand on était scrollé bas dans la pool xl-sidebar, il fallait remonter en haut. La search input avait le même
bg-white border-ink-200que les chips → indistinguable visuellement.Maintenant :
1. Sticky header : le bloc titre + search + bouton « annuler sélection » reste accroché en haut de la zone scrollable quand on défile (variant
stickyseulement, l'xl+ sidebar). Backdrop cream avecbackdrop-blur-smpour que les chips qui passent dessous soient discrètement visibles.2. Search bar gold tint : passe de
bg-white border-ink-200àbg-brand-50 border-brand-500/30. Affordance interactive distincte des chips. Hover/focus garde la sémantique gold du brand. Placeholder text passe detext-ink-300(default) àtext-ink-500pour rester lisible sur le fond pâle.Le variant inline (mobile/lg, < xl) garde son comportement non-sticky : la page entière scrolle, le sticky header conflit-erait avec la navbar dashboard au-dessus.
- Version 2026-05-13.3913 mai 2026(Plan de table : hotfix BUG-173 — cascade trigger supprime les seats des déclinés, débloque assignSeat)
User feedback (après le ship K.10.5 / BUG-172 initial) : « aussi, je veux que tu résous le bug 172 ». L'investigation Chrome MCP + queries DB directes a déterré la vraie cause du symptôme « Table pleine » qui faisait échouer
assignSeatmême pour des membres Confirmés.Avant : un invité qui décline son RSVP gardait son
seat_assignmentsrow dans la DB. L'UI les filtre (vialistGuestsForSeatingWithRsvp), donc la table apparaît « 7 invités / 10 » dans la planner mais a 10+ rows en DB. →assignSeatcapacity check rejette toute nouvelle assignation avec « Table pleine ».Maintenant : quand un invité décline (
guest_event_rsvp.status = 'declined'), un trigger DB supprime automatiquement ses seat_assignments pour cet événement. La capacité réelle correspond à la capacité visible. Plus de « Table pleine » trompeur. Cleanup one-shot des zombies existants (vérifié sur prod : Table d'honneur passe de count 10+ à 7). - Version 2026-05-13.3813 mai 2026(Plan de table : hotfix BUG-172 — les déclinés sont retirés des groupes de placement)
User feedback : « on enlève systématiquement les personnes déclinées du groupe. Donc si sur un groupe de deux une seule personne a validé (ou en tentative), c'est un peu comme si y a plus de groupe. »
Avant : un couple où un membre a
Déclinél'événement créait un groupe fantôme côté seating. Le membre survivant gardait l'icône Link2 + la modale « Cet invité fait partie d'un groupe » s'ouvrait au drag. Click « Déplacer le groupe entier » → échec serveur (« 2 membre(s) du groupe n'ont pas pu être assignés ») → rien ne bouge.Maintenant : si un membre du couple a
Déclinépour cet événement, la partnership est filtrée hors de la vue seating. L'autre est traité comme solo :- Pas d'icône Link2 sur son chip
- Pas de bracket gold
- Drag → déplacement immédiat sans modale
- L'auto-suggester (
applyAutoSuggestion) ignore aussi le groupe fantôme et place le membre confirmé sans contrainte de partenariat
La partnership reste intacte côté DB (
guest_partnershipsnon touché). Le wall/invites, la cascade contact, et les autres événements continuent de voir le couple normalement. C'est uniquement la VUE seating de l'événement actif qui filtre les déclinés. - Version 2026-05-13.3713 mai 2026(Plan de table : hotfix BUG-171 « déplacer le groupe entier » ne déplace qu'un partenaire dans l'UI)
User report : « quand je déplace Mariam Andaloussi il me demande si je veux déplacer Mustapha aussi, je valide mais y a que Mariam qui est déplacée. »
Scénario : couple Mariam ↔ Mustapha. Mariam visible dans la pool (passe le filtre RSVP actif), Mustapha caché (filtré out). Drag Mariam → modale « Déplacer le groupe entier » → click confirm → seul Mariam apparaît à la nouvelle table dans l'UI. Côté serveur Mustapha EST bien déplacé, mais l'UI ne s'en aperçoit qu'après un reload manuel.
Maintenant : après la décision « Déplacer le groupe entier », l'UI fait un
debouncedRefresh()qui ré-fetche l'état serveur. Les 2 partenaires apparaissent à la nouvelle table immédiatement (à 600ms près). - Version 2026-05-13.3613 mai 2026(Plan de table — Sprint K.10.5 : remplacer window.confirm par une modale brand-aligned)
Sprint K.10.5 — dernier sprint de K.10. Les 2 prompts
window.confirm()du Plan de table (« Proposer un plan auto » et « Supprimer cette table ») apparaissaient avec le style natif du navigateur (gris/blanc avec OK/Cancel) au milieu d'une interface gold/cream. Visuellement dissonant, KO accessibilité (pas de focus trap, pas de scrim), et bloquant pour Chrome MCP qui ne sait pas piloter ces dialogues natifs.Maintenant : une
<ConfirmModal>brand-aligned, même pattern que<GroupDecisionModal>(scrim noir 40%, scrim cream, focus auto sur l'action primaire, Escape pour annuler, click outside ferme). Le bouton « Supprimer » utilisevariant="destructive"(rouge), distinct du gold confirmateur classique. - Version 2026-05-13.3513 mai 2026(Plan de table — Sprint K.10.4 : extraction de seating-planner.tsx en 5 fichiers, -26% de LOC)
Sprint K.10.4 — refactoring interne, zéro changement visuel ou comportemental. Pas un sprint « feature », un sprint « santé du code ». Le fichier
seating-planner.tsxavait gonflé à 2502 lignes (orchestrateur + 6 sous-composants + 4 helpers inline) — devenait fragile à modifier. - Version 2026-05-13.3413 mai 2026(Plan de table — Sprint K.10.3 : memoize activeEvent + totalGuests, supprime les events.find redondants)
Sprint K.10.3 — micro-optimisations identifiées par l'audit perf. La virtualisation
@tanstack/react-virtualinitialement prévue est reportée (intégration DnD-kit non-triviale ; gains marginaux après K.10.1). À la place, série de petites optimisations avec un excellent ratio impact/effort.Pas de changement visuel. Gains :
- 1
events.find()au lieu de 6 par render dans le Plan 2D (Konva) - 1 calcul
totalGuestsau lieu de 3 par render - Suppression des
as { … } | undefinedcasts redondants → JSX plus lisible
- 1
- Version 2026-05-13.3313 mai 2026(Plan de table — Sprint K.10.2 : router.refresh debounced + batch moveMany en 1 setState)
Sprint K.10.2 — moins de roundtrips serveur quand on place les invités rapidement. Pas de changement visuel. Gains :
- Placement séquentiel : si on place 5 invités en 3 secondes, 1 seul fetch RSC au lieu de 5.
- « Déplacer le groupe entier » : 1 setState batch au lieu de N×2 setStates (réduit le travail du reducer React).
- Version 2026-05-13.3213 mai 2026(Plan de table — Sprint K.10.1 : DnD perf, React.memo sur chips + lookups O(1) + callbacks stables)
Sprint K.10.1 sur recommandation d'audit perf — la page
/seatingreste fluide même pour les mariages 150-200 invités. Pas de changement visuel. Gains mesurables :- Hover sync (passer la souris sur un membre de couple) : avant, les 150 chips se re-rendaient. Maintenant, seulement les 2 chips concernés.
- Search dans la pool : chaque keystroke ne re-render plus toute la liste.
- Drag overlay : le lookup du nom de l'invité tiré est O(1) au lieu d'un
flatMap().find()sur 150 éléments à chaque pointer-move.
- Version 2026-05-13.3113 mai 2026(Plan de table : modale de décision — boutons en colonne, libellés FR plus de troncature)
User screenshot K.9.29 → 3 boutons en grid horizontal (
grid sm:grid-cols-3) dans une modalemax-w-lg(~512px). Les libellés FR (« Déplacer le groupe entier », « Détacher (groupe trop petit) ») débordaient leurs boutons avecwhitespace-nowrap, créant l'illusion que les boutons se chevauchaient (le texte du 1er sortait par-dessus le 2ème).Maintenant :
flex flex-col gap-2— les 3 boutons sont empilés verticalement, full-width, libellés complets. Layout simple, lisible, pas de troncature. - Version 2026-05-13.3013 mai 2026(Plan de table : 1 parenthèse gold qui englobe le couple, au lieu d'une par personne)
User feedback : « quand on voit le design comme ça, pas possible de détecter les groupes. Au lieu d'une parenthèse chacun on peut faire une parenthèse en gold à gauche qui couvre tout le groupe ? »
Avant : chaque membre du couple à la même table recevait son propre
border-l-2 border-brand-500/40 pl-1.5. Visuellement, 2 petits traits gold côte à côte sur 2 chips adjacents — ça ressemblait à une parenthèse cassée avec un mini-gap, pas à un signal de « groupe ».Maintenant : un seul trait gold continu (
border-l-2 border-brand-500/50 pl-1.5) sur un wrapper<li role="group">qui englobe les 2 chips du couple. Le bracket ressemble à une vraie parenthèse qui « tient » le couple ensemble. Solos rendus à plat (pas de bracket). Solo + couple peuvent se mélanger dans la même table. - Version 2026-05-13.2913 mai 2026(Plan de table : modale de décision de groupe — banner inline → vraie pop-up centrée)
User feedback : « quand j'essaye de déplacer une personne faisant partie d'un groupe, le message pour confirmer si je déplace le groupe entier ou juste la personne est affiché en haut (je le vois mm pas). Pour moi, cela doit être plutôt un pop up non ? »
Avant : la confirmation 3 boutons (« Déplacer le groupe entier » / « Détacher (groupe trop petit) » / « Annuler le groupement ») apparaissait sous forme de banner inline en haut de la colonne des tables. Quand on drop depuis la pool « Sans table » (en bas, ou à droite en sticky), le banner s'affichait hors viewport — le drag semblait silencieusement ne rien faire jusqu'à scroller manuellement vers le haut.
Maintenant : vraie modale centrée avec scrim (
bg-black/40), bordure gold, focus auto sur le bouton primaire (« Déplacer le groupe entier ») pour Enter immédiat, et Escape pour annuler. Click-outside ferme aussi. Aligné sur le pattern deRoomDimensionsModal(cohérence avec le reste du dashboard). - Version 2026-05-13.2813 mai 2026(Plan de table : barre sticky compacte + couples regroupés dans la liste)
User feedback : « la barre blanche en haut reste vide. Aussi, quand un groupe (couple) est dans la même table ou sans table, je pense faut les mettre l'un après l'autre. »
Avant :
1. La barre sticky compacte (affichée pendant le scroll) avait un gros vide entre les stats « invités placés » et l'indicateur « 5/9 tables » : le
ml-autopoussait les tables tout à droite, laissant un espace blanc visuellement bizarre.2. Le tri dans la pool « Sans table » et dans chaque carte de table était alphabétique sur le
display_name. Conséquence : Hassan Ouazzani et Aïcha Bennani (couple) étaient séparés par 80 autres invités. Pareil dans les tables — un couple à la même table pouvait avoir 4 personnes entre eux.Maintenant :
1. La barre sticky est dense, alignée à gauche, lisible d'un coup d'œil — toutes les stats côte-à-côte sans vide.
2. Dans la pool « Sans table » comme dans chaque carte de table, les couples apparaissent adjacents. L'algo garde l'ordre d'origine pour le 1er membre, puis injecte son partenaire juste après si le partenaire est aussi dans la liste. Les solos restent à leur place.
- Version 2026-05-13.2713 mai 2026(Plan de table : palette d'anneaux Tailwind → 3 niveaux brand-aligned)
User feedback : « les couleurs qui entourent les noms ici correspondent pas à la charte du site non ? »
Avant : chaque couple recevait un ring d'une couleur Tailwind générique (
ring-rose-400,ring-emerald-400,ring-sky-400,ring-amber-400,ring-fuchsia-400,ring-teal-400,ring-orange-400,ring-lime-400) cyclée modulo 8. Avec 43 couples → ~5 couples par couleur, donc Ahmed Lazrak (teal) et Kenza Tetouani (teal) avaient le MÊME ring sans être du même couple. Et la palette était hors charte (rose vif, fuchsia, lime) face au cream/gold du site.Maintenant — système 3 niveaux brand-aligned :
1. Persistent (faible) : tous les chips d'invités en couple reçoivent une petite icône
Link2lucide en gold pâle (text-brand-600/70) à côté du nom. Signale « cette personne a un partenaire ». Aucune discrimination par couple.2. Same-table (moyen) : quand les 2 partenaires sont à la même table, leurs chips ont un border-l-2 gold (
border-brand-500/40 pl-1.5). Chaque couple a son propre bracket — zéro collision possible.3. Hover sync (fort) : hover sur un chip de couple → les 2 membres du même partenariat reçoivent un ring
brand-500/60. Utile pour localiser le partenaire quand il est à une autre table. - Version 2026-05-13.2613 mai 2026(Navbar : Plan de table déménage de « Mariage » vers « Invités »)
User feedback : « je comprends pas pourquoi seating et invités sont dans 2 sections différentes ». Le plan de table manipule les mêmes invités (et les mêmes couples depuis K.9) que la liste RSVP — le flow naturel est ajouter invité → définir RSVP → assigner à table. 3 actions, mêmes données.
Avant :
```
Mariage : Accueil · Planning · Budget · Plan de table
Invités : Liste & RSVP · Invitations · Livre d'Or · Messages
```
Maintenant :
```
Mariage : Accueil · Planning · Budget
Invités : Liste & RSVP · Plan de table · Invitations · Livre d'Or · Messages
```
- Version 2026-05-13.2513 mai 2026(Sprint K.9.12 : fix `applyAutoSuggestion` côté serveur — partnerships cascaded)
Avant : « Proposer un plan » sur /seating plaçait les invités en ignorant les couples (régression silencieuse depuis 0.63). Karim → Table 4, Karima → Table 7.
Maintenant : 43/43 couples placés à la même table par l'auto-suggester. Drag manuel d'un membre du couple → banner décision avec 3 choix (Déplacer ensemble / Détacher / Annuler groupement).
- Version 2026-05-13.2413 mai 2026(Sprint K.9.11 : partnerships visibles dans le plan de tables — color-code + auto-place)
Sur la page
/seating, les couples (issus deguest_partnerships) sont désormais :1. Color-codés dans la liste « Sans table » et dans les tables — chaque couple a sa propre couleur de bordure pour qu'on les repère d'un coup d'œil.
2. Auto-placés ensemble par le bouton « Proposer un plan » (l'auto-suggester traite chaque partnership comme un groupe de 2 qui doit s'asseoir à la même table).
3. Décision groupe au drag : quand on déplace Karim, la modale 3-boutons existante (« déplacer tout le groupe / détacher / dissoudre ») s'active automatiquement.
- Version 2026-05-13.2313 mai 2026(Audit K.9 — trigger DB cascade soft-delete partnerships)
Aucun impact visible direct — fix de cohérence invisible aux utilisateurs sains mais qui empêche 2 classes de bugs silencieux trouvés via un audit post-K.9.9 :
1. BUG-1 :
deleteGuestsoft-delete un guest sans cascader sur la partnership. La rowguest_partnershipsorpheline pointait sur un guest fantôme —submitPublicRsvpcascade pouvait écrire des RSVPs sur un guest soft-deleted.2. BUG-2 :
mergeClustermême problème — fond un guest dans un couple, la partnership reste active mais le partner pointe sur un fantôme. - Version 2026-05-13.2213 mai 2026(Sprint K.9.9 : management UI couples dans la fiche — Lier / Délier)
User feedback : « hassan et aicha sont liés mais j'arrive pas à checker ou ni à les délier ». Le bracket sur le wall montrait la liaison mais aucune surface ne permettait de naviguer FROM Aicha TO Hassan, ni de dissoudre le couple.
Nouvelle section LIAISON COUPLE dans la fiche détail, juste sous le bloc « Autres cérémonies » :
État lié (le guest fait partie d'un couple) :
```
LIAISON COUPLE
🔗 LIÉ·E À
Hassan Ouazzani [ Ouvrir la fiche → ]
Partenaire · Couple
🔓 Délier
```
Click « Ouvrir la fiche » → navigation vers la fiche du partenaire.
Click « Délier » → confirmation inline → dissolution (soft-delete).
État solo (guest sans partenaire) :
```
LIAISON COUPLE
[ 🔗 + Lier à un partenaire ]
```
Click → expand un picker avec search + list des autres invités → sélection → linkPartnership.
- Version 2026-05-13.2113 mai 2026(Polish K.9 : retrait des cœurs ♥ sur les couples — bracket + quick-add toggle)
User feedback : « the hearts you are putting here are too much ». Sur un wall avec 44 couples, 44 micro-pills ♥ collés en haut-droite de chaque bracket créaient une pollution visuelle. Idem pour l'icône Heart dans le toggle « Couple ? » du quick-add.
Retrait des deux. La bordure pointillée gold du bracket suffit à signaler « ces 2 sont liés » ; le texte « Couple ? » / « Couple » suffit pour le toggle.
- Version 2026-05-13.2013 mai 2026(Sprint K.9.8 : portail RSVP public — cascade « Même réponse pour {partner} »)
Quand un invité partenaire d'un couple ouvre son lien RSVP public, un bandeau gold checkbox apparaît en tête du formulaire :
```
☑ Même réponse pour Saadia
Décocher si Saadia souhaite répondre séparément.
```
Coché par défaut. Au submit, la réponse d'Abdelhakim (Présent / Absent / Peut-être) cascade sur la row de Saadia — sauf si Saadia a déjà répondu indépendamment via son propre lien (règle conservatrice K.9.2, mirror serveur-side).
L'utilisateur peut décocher si il sait que Mme préfère répondre par elle-même via son propre lien.
- Version 2026-05-13.1913 mai 2026(Sprint K.9.7 : DROP `plus_one*` legacy columns + cleanup 17 consumers)
Le wall et la fiche sont visiblement nettoyés : le badge
+1 Saraqui doublait l'info à côté du partner row a disparu. Inass + Abdelfettah, Sara + Hamza, Hassan + Aicha — chaque bracket gold contient maintenant exactement 2 chips propres, sans badge+1 Nameredondant.Côté fiche : la section CONNEXION n'a plus le sélecteur 4-options « Pas d'accompagnant / Demandé / Autorisé / Confirmé avec nom » + champ « Nom de l'accompagnant ». Les couples se créent via le
+ Couple ?du quick-add (K.9.5) ou seront édités via le futur+ Lier à un partenairedans la fiche. - Version 2026-05-13.1813 mai 2026(Sprint K.9.6 : seed update — vraies partnerships au lieu de `+1 inline`)
Non-user-facing — c'est l'évolution du seed dev
scripts/seed-invites-stress.mjs. Au re-roulage, le test-couple-a est repeuplé avec 134 entrées → 178 invités → 44 vraies partnerships au lieu de l'ancien patternplus_one_status='confirmed_with_name'qui dépendait du backfill K.9.1 (qui ne se déclenche qu'à la migration). - Version 2026-05-13.1713 mai 2026(Sprint K.9.5 : quick-add couple mode — bouton « ♥ Couple ? » + 4 champs)
Le formulaire inline « Ajout rapide » sur /invites a maintenant un toggle « ♥ Couple ? » dans son header. Au clic, le formulaire bascule de 3 champs (Nom complet · Téléphone · Cercle) à 4 champs (Nom de monsieur · Nom de madame · Téléphone du couple · Cercle), et le bouton « Ajouter » devient « Ajouter le couple ».
Au submit, 2 invités liés + 1 row
guest_partnershipssont créés en une seule action atomique. Le partenaire hérite automatiquement duside / category / circledu lead. Le téléphone (si renseigné) vit sur le lead et est cascadé en lecture vers le partenaire. RSVPs pending fanout-ed sur les 2 membres pour chaque événement actif.Le mode couple est sticky : après un add réussi, le formulaire reste en mode couple, le cercle reste sélectionné. Idéal pour ajouter une rafale de 5 couples d'amis dans la même tranche (même cercle).
- Version 2026-05-13.1613 mai 2026(Sprint K.9.4 : fiche partenaire — bandeau « contact hérité via {lead} »)
Quand on ouvre la fiche d'un partenaire qui n'a pas son propre téléphone/email, la section CONTACT affiche un bandeau crémeux gold : « CONTACT HÉRITÉ VIA MAROUANE » + numéro de téléphone + email du lead, avec un hint italique « Tape ci-dessous pour ajouter un contact propre ». Les inputs restent éditables — taper override le cascade.
Affichage par canal indépendant : si Mme a son propre email mais pas son propre téléphone, seul le téléphone apparaît dans le bandeau hérité.
- Version 2026-05-13.1513 mai 2026(Sprint K.9.3 : bracket gold sur le wall pour les couples liés)
Premier impact UX visible du data model K.9. Sur le wall /invites, les 2 membres d'un couple sont désormais visuellement liés :
- Les chips Karim Bennani + Karima Bennani sont rendus contigus dans un cadre pointillé or, avec un petit ♥ en haut à droite.
- Le tri alphabétique de la section continue à s'appliquer, mais les paires sont automatiquement rapprochées (ex : Yasmine Andaloussi + Driss Andaloussi sont posés côte à côte même si l'ordre alphabétique séparerait Yasmine et Driss).
- Au hover sur n'importe quel chip d'un couple, le cadre gold s'épaissit (halo synchronisé — l'utilisateur sait visuellement que les deux sont liés).
- La navigation clavier (flèches gauche/droite) respecte maintenant l'ordre visuel : les 2 membres d'un couple sont contigus dans
visibleIds.
- Version 2026-05-13.1413 mai 2026(Sprint K.9.2 : server actions `addCouple` + `upsertRsvpForCouple` + cascade contact lecture)
Pas encore de changement visible utilisateur — c'est la couche serveur qui s'aligne sur le data model K.9.1. La cascade contact est désormais calculée à la lecture, prête à être consommée par l'UI dans K.9.3-4.
- Version 2026-05-13.1313 mai 2026(Sprint K.9.1 : data model `guest_partnerships` — couples = 2 rows liées, pas `+1` inline)
Pas de changement visible utilisateur ce sprint — c'est une fondation data model. Les écrans (wall, fiche, quick-add) continuent à afficher les
+1inline comme avant. Les sprints suivants (K.9.2-5) câblent l'UI sur ce nouveau modèle.Pourquoi cette refonte : le modèle
plus_one_name(texte libre attribut du lead) bloque 5 capacités futures :1. Le partenaire n'est pas une entité → impossible de lui donner un RSVP indépendant, un régime, un hero_role, un statut Henné distinct.
2. Comptage faussé : « 155 invités » sous-estime de 25 chaises à table.
3. Le seating ne peut pas placer 2 personnes via un seul chip.
4. La moonshot « gender auto-detection → filtre Henné femmes-only » n'a aucun row à filtrer.
5. Le dedup ne voit pas si quelqu'un retape « Karima Bennani » alors qu'elle est déjà la
+1de Karim Bennani. - Version 2026-05-13.1213 mai 2026(Sprint K.8.2 : drop `origin` + merge `dietary_notes` → `notes`)
Suite à feedback utilisateur : « tu peux supprimer origin et inclure dietary notes dans note libre ». 2 simplifications de modèle :
1. Champ
origin(local / national / international) supprimé :- Filter rail : le bloc « Origine » disparait (4 chips supprimés)
- Fiche invité : le select dropdown « Origine » dans Connexion disparait
- Wall : le drapeau ✈ « international » sur les chips disparait
- État URL : le paramètre
?origin=...est ignoré
2. Champ
dietary_notesfusionné dansnotes:Données préservées : ce qui était dans
dietary_notesest appendé au champnotesavec préfixe « Régime : » via UPDATE SQL atomique au moment de la migration. Le champnoteslibre absorbe désormais aussi les préférences alimentaires informelles. Les champs séparésdietary_restrictions(array structuré pour le traiteur) etallergies(info de sécurité) restent. - Version 2026-05-13.1113 mai 2026(Sprint K.8.1 : ajout rapide inline — 3 champs au lieu de 19)
Le bouton
+ Ajoutern'ouvre plus une fiche vide à 19 champs. À la place, un formulaire inline apparaît directement sous la toolbar avec 3 champs seulement :| Champ | Statut | Comportement |
| ----------- | ----------------------------------------- | -------------------------- |
| Nom complet | obligatoire | autofocus à l'ouverture |
| Téléphone | optionnel | reset après save |
| Cercle | obligatoire (default : Famille immédiate) | sticky entre les saves |
Flow rapide : tape un nom → Tab vers téléphone → optionnellement saisir → Enter → invité créé + champ Nom remis à zéro et refocus → tu peux taper le suivant. 20 invités en 2 minutes au lieu de 30 minutes.
Le bouton « Ajouter » bascule en « Fermer » quand le formulaire est ouvert.
Escferme aussi.L'ancienne UX (placeholder + ouverture fiche complète) reste accessible via :
- Le CTA « Ajouter un invité » de l'empty state (couples qui débutent)
- La command palette
⌘K → Ajouter un invité(power users)
- Version 2026-05-13.1013 mai 2026(Sprint K.8.0 : drop des 3 champs Voyage diaspora — réduction de friction de saisie)
La fiche invité passe de 19 champs gérés à 16. Les 3 champs supprimés sont ceux du bloc « Voyage » diaspora : Date d'arrivée, Hôtel, Vol confirmé. Le bloc bleu qui apparaissait pour les invités
origin === "international"ou"national"disparaît entièrement. Les couples qui veulent tracker des infos voyage utilisent désormais le champ librenotes.Mécaniquement, ça élimine 5 sources de bugs i18n (les
MISSING_MESSAGEde la K.7.9) et simplifie la friction de saisie pour les invités diaspora. - Version 2026-05-13.0913 mai 2026(Sprint K.7.9 hotfix : 5 clés i18n manquantes dans /invites/<id>)
Le bloc « Voyage » de la fiche invité (visible uniquement quand
origin === "international"ou"national", soit pour les invités diaspora) levait 5 erreursMISSING_MESSAGEdans la console Next.js et s'affichait avec les clés brutes au lieu des libellés français/anglais/espagnol/néerlandais.Maintenant les libellés s'affichent correctement :
- « Voyage » (section title)
- « Date d'arrivée » (input label)
- « Hôtel » (input label)
- « ex. Sofitel Casablanca » (input placeholder)
- « Vol confirmé » (checkbox label)
- Version 2026-05-13.0813 mai 2026(Sprint K.7.8 : la toolbar ne cache plus le haut du plan)
La toolbar flottante en haut du canvas (
+ Table,+ Honneur, Dimensions, etc.) ne mange plus le haut de la salle. Le rectangle cream du sol est désormais positionné EN DESSOUS du toolbar, avec une marge de respiration. Plus de tables masquées dans la zone supérieure. - Version 2026-05-13.0713 mai 2026(Sprint K.7.7 : tables ajoutées via la toolbar 2D apparaissent immédiatement)
Bug remonté : « quand j'ajoute des tables, elles apparaissent pas dans le plan ». Cause précise :
Le
SeatingPlannergarde un état localtablesviauseState(initial.tables)— initialisé UNE seule fois au mount. Quand la toolbar 2D appelleaddTable()directement, la DB voit bien la nouvelle ligne ETrevalidatePath("/seating")est appelé, mais le composant React du planner ne se ré-initialise pas tout seul. Conséquence : la nouvelle table est en base, le toast « Table ajoutée » s'affiche, mais le canvas et la rangée Liste restent figés avec l'ancien jeu de tables. Il fallait recharger la page (Cmd+R) pour la voir.À partir de ce ship : la nouvelle table apparait instantanément dans le Plan 2D dès le clic sur
+ Tableou+ Honneur. Pareil pour la duplication et la suppression depuis la toolbar 2D. - Version 2026-05-13.0613 mai 2026(Sprint K.7.6 hotfix : drag table save n'attendait plus 300 ms perdus au reload)
Bug remonté : « j'ai modifié la disposition de kk tables et ça n'a pas été enregistré ». Cause précise identifiée et corrigée — le
setTimeout(300ms)du debounce était tué par le reload navigateur avant que leupdateTablene parte. Si tu dragues plusieurs tables en rafale et reloads vite, les dernières ne se sauvaient pas.Désormais le drag d'une table déclenche un save immédiat (pas de debounce). La gestion de la rafale rapide est cosmétique de toute façon — chaque drag-end est un geste utilisateur discret (relâchement de souris), pas un flux continu.
Le debounce 300 ms reste actif pour le nudge clavier (les flèches peuvent vraiment spammer), avec la même fonction
scheduleSavequ'avant.Une garde
beforeunloadwarne si l'utilisateur ferme/reload pendant un save en vol — pas bloquant, juste un confirm navigateur natif. - Version 2026-05-13.0513 mai 2026(Sprint K.7.5 : feedback de sauvegarde + viewMode persistant en URL)
Deux frictions de perception remontées (« l'autosave ne marche pas dans la vue 2D ») alors que les données SE sauvent bien — la cause était l'absence de feedback + le retour brutal en vue Liste après reload :
1. Indicateur de sauvegarde visible dans le coin haut-droite du canvas pendant et après le drag d'une table :
- Pendant le debounce / la requête : badge gris « Enregistrement… »
- Après succès : badge or « ✓ Sauvegardé » pendant 2 s puis fade
- Sur erreur : toast rouge (comportement existant)
2. viewMode persistant via URL hash : quand tu es en Plan 2D et que tu reload (
Cmd+R), tu restes en Plan 2D. Avant, tu retombais en vue Liste, ce qui donnait l'impression que le reload « a perdu » tes changements. - Version 2026-05-13.0413 mai 2026(Sprint K.7.4 : drag-drop natif invités → Konva tables)
Le 2D récupère le drag-and-drop des invités sans casser la spatialisation :
- Glisser un invité du rail droite vers une table du Plan 2D → ça l'assied (toast + refresh).
- Liseré or 3px en
inset shadowsur la table sous le curseur pendant le drag — feedback instantané. - Liseré rouge + curseur not-allowed si la table est pleine.
- Aucun changement au comportement Konva : cliquer une table ouvre son panneau, dragger une table la déplace dans la salle.
- Version 2026-05-13.0313 mai 2026(Sprint K.7.3 : Plan 2D devient lecture seule pour les invités)
Séparation propre des responsabilités entre les deux vues du plan de table :
- Vue Plan 2D : placement et dimensionnement des tables dans la salle (drag de tables, modale Dimensions, ajout de tables). Le panneau qui s'ouvre quand on clique sur une table est désormais en lecture seule : on voit qui est placé, l'occupation, mais on n'asseoit/retire plus depuis là.
- Vue Liste : tout ce qui touche aux invités (assignation, drag-and-drop depuis le rail, suppression d'un invité d'une table).
Concrètement, dans le panneau Plan 2D :
- Suppression du bouton « Asseoir » sur chaque invité non placé
- Suppression du bouton « Retirer » au hover des invités placés
- Suppression de la section « non placés » entière
- Ajout d'un CTA discret « Modifier dans la vue Liste → » qui bascule la vue automatiquement, avec un hint « Encore N invités à placer » ou « Tous les invités sont placés ».
Pourquoi ce choix : la vue Liste a déjà tous les superpouvoirs pour l'assignation (drag DOM natif, recherche, filtres), pendant que la 2D est imbattable pour la spatialisation. Forcer chaque vue à tout faire dilue les deux. Précédent produit : Notion table view ≠ board view.
Au passage, ça enlève deux bugs reportés en usage : (1) le retirer qui ne rafraîchissait pas le panneau immédiatement, (2) l'absence de drag-drop depuis le rail vers les cercles Konva.
- Version 2026-05-13.0213 mai 2026(Sprint K.7.2 : propagation du diamètre repensée, toutes les tables s'alignent)
Bug remonté par l'utilisateur : « les tables n'ont pas les mêmes dimensions ». Cause profonde corrigée — quand on change le diamètre standard dans la modale, TOUTES les tables (sauf l'honneur et les enfants) s'alignent. Avant, seules les
kind='standard'strictement matched étaient touchées, ce qui laissait les Famille mariée/marié et les tables seedées intactes à 180 cm pendant que les nouvelles tombaient à 160 cm.Effet visible immédiat : ouvrir
/seatingaprès le ship → toutes les tables d'un même mariage ont strictement le même diamètre. - Version 2026-05-13.0113 mai 2026(Sprint K.7.1 : 3 frictions UX du plan de table)
Trois frictions remontées en usage réel — fixées d'un coup :
✅ Bouton « Dimensions » promu dans la toolbar canvas (icône Règle, label, tooltip). Avant : minuscule lien souligné caché en bas du canvas, invisible. Maintenant : bouton ligne au milieu de la toolbar, à portée immédiate.
✅ Le pan canvas ne fait plus déplacer la salle au repos : à zoom 100 % la salle est centrée et tient dans le viewport, donc pouvoir la pousser hors écran n'a aucun intérêt. Le drag-pan reste actif uniquement quand on a zoomé (
zoom > 1), là où c'est utile.✅ Les tables au format ancien (rectangle / carré) sont automatiquement normalisées en rondes au save de la modale Dimensions, à la taille standard configurée. Plus de plan visuellement hétérogène avec une grande ronde, un rectangle, une carrée — c'est physiquement irréaliste pour un mariage marocain et ça cassait l'aesthetic du sol K.6.6. Seules les tables
kind='standard'sont concernées ; les tables honor et kids gardent leur shape. - Version 2026-05-12.3612 mai 2026(Sprint K.6.8 hotfix : keyboard nudge ignore les flèches dans le panel)
Petit fix de comportement repéré au test Chrome MCP de K.6.7 : quand le panel « qui est à cette table » est ouvert et que l'utilisateur survole/clique dans la liste des invités, presser les flèches du clavier ne va plus déplacer accidentellement la table sélectionnée. La nudge clavier reste active dès que le focus est sur le canvas (et non dans le panneau ou un dialog).
- Version 2026-05-12.3512 mai 2026(Sprint K.6.7 : test Chrome MCP end-to-end du flow K.6 complet)
Pas de changement applicatif — ship d'un rapport de test live qui valide les 6 sprints précédents (K.6.1 → K.6.6).
- Version 2026-05-12.3412 mai 2026(Sprint K.6.6 : refonte du sol — luxe paper, dot grid, ombrage)
Le canvas plan-de-table change radicalement d'aesthetic :
- Background extérieur : cream
lk-paper-darkplus chaud (au lieu du blanc cassant CAD). - Sol de la salle : rectangle cream clair
lk-cream(chaud) + bordure or fine (lk-or-pale, 1.5px) + coins arrondis (14px) + ombre portée subtile dorée. Effet « plan posé sur un papier épais d'agenda de mariage », pas blueprint d'architecte. - Grille : devient des points or transparents au lieu de lignes pleines (50cm), désactivée par défaut. Le couple voit un sol pristine cream ; activer la grille reste possible pour des alignements précis.
- Ombre intérieure subtile : 2e Rect blanc 0.5px à 4cm de marge intérieure simule un highlight d'inset (Konva n'a pas de vraie
inner-shadow). - Indicateur dimensions : déplacé en haut-droite, italique 11px gris muted (au lieu du badge blanc en bas-gauche qui faisait concurrence à la toolbar).
- Background extérieur : cream
- Version 2026-05-12.3312 mai 2026(Sprint K.6.5 : numéro de table dans cercle + glyphe honor + label sous-titre)
L'intérieur des cercles tables est désormais épuré :
- Un grand chiffre centré : le numéro de table (
1,2,3…) en Fraunces gras, taille proportionnelle au rayon de la table. Plus de texte tronqué. - Capacité dessous, petit gris :
0 / 10,2 / 12— discret mais lisible. - Glyphe ✦ or pour la table d'honneur (coin supérieur droit), liseré or épaissi (3.5px). Repérable d'un coup d'œil même sur un plan dense.
- Label long sous la table (Famille mariée, Cousins de Fatima…) : affiché en permanence si court (≤14 chars), sinon au hover seulement. Plus de wrap moche dans le cercle.
- Un grand chiffre centré : le numéro de table (
- Version 2026-05-12.3212 mai 2026(Sprint K.6.4 : findFreePosition + no-overlap au drag)
- Nouvelle table apparait dans un slot libre du sol (centre de la salle si vide, spirale vers l'extérieur sinon). Plus de tables qui empilent sur la même position après chaque ajout.
- Drag-and-drop avec garde anti-chevauchement : si on lâche une table à un endroit qui chevauche une autre, elle revient à sa position d'origine + toast d'erreur « Position invalide : cette table chevauche une autre. »
- Erreur explicite si la salle est pleine : « La salle est pleine — agrandissez-la dans les Dimensions pour ajouter d'autres tables. »
i18n : 4 locales avec les nouvelles clés
errorRoomFull(toolbar) eterrorOverlap(canvas). - Version 2026-05-12.3112 mai 2026(Sprint K.6.3 : Konva Transformer retiré + 2 boutons d'ajout atomiques)
L'éditeur de plan de table se range sur la réalité physique des salles de réception :
- Plus de poignées de redimensionnement sur le canvas. Cliquer une table = la sélectionner (outline or épais), c'est tout. La taille des tables se règle dans la modale Dimensions, une fois pour toutes.
- Dropdown 4-presets remplacé par 2 boutons distincts :
+ Tableajoute une table ronde au diamètre standard de l'événement (180 cm par défaut, configurable)+ Honneurajoute la table d'honneur au diamètre honneur (220 cm par défaut, configurable) — désactivé dès qu'une table d'honneur existe (un mariage n'en a qu'une)
Tooltip des boutons : « Ajouter une table ronde Ø {diameter} cm » — l'utilisateur voit exactement la taille qui va être créée.
i18n : 4 locales, 21 clés chacune (bloc
preset.*supprimé, ajoutaddStandard*+addHonor*). - Version 2026-05-12.3012 mai 2026(Sprint K.6.2 : modale Dimensions enrichie 4 champs + propagation visible)
La modale « Dimensions de votre salle » passe à 4 champs en 2 sections :
Salle de réception (m)
- Largeur · Longueur
Tables (cm)
- Ø Table standard · Ø Table d'honneur
Hint clarifié : « Une seule taille pour toutes les tables standard (votre traiteur les louera identiques). La table d'honneur est l'exception visible — souvent un peu plus grande. »
Au save, toutes les tables standard rondes de l'événement passent à la nouvelle taille en une transaction. Toast : « Dimensions enregistrées — toutes les tables sont mises à jour. »
i18n : 4 locales (fr/en/es/nl) chacune à 18 clés (renommée
errorOutOfRange→errorRoomOutOfRange, ajoutéeerrorDiameterOutOfRange, nouvelles sections). - Version 2026-05-12.2912 mai 2026(Sprint K.6.1 : per-event default table diameters DB + schema + action)
Préparation invisible côté DB pour que la prochaine modale « Dimensions » (qui arrive avec K.6.2) puisse contrôler un diamètre standard ET un diamètre table d'honneur au niveau de l'événement — et que tous les ronds existants s'alignent automatiquement quand le couple change la valeur.
Pas de changement visible UI dans ce ship, c'est uniquement la fondation pour le sprint K.6 « réalisme physique du plan » (plus de resize par table, taille unique par venue).
- Version 2026-05-12.2812 mai 2026(Sprint K hotfix : 3 bugs surfacés par le test Chrome MCP live)
Trois micro-frictions corrigées dans l'éditeur de plan de table, toutes attrapées en testant le flow complet de bout en bout (dimensions → ajout preset → drag → click table → asseoir invité) :
✅ Cockpit / rail cohérents — quand 3 invités sont sans table mais filtrés par le RSVP, le rail à droite ne dit plus mensongèrement « 🎉 Tous vos invités ont une table » ; il affiche « N invités masqués par les filtres — modifiez les filtres pour les voir ».
✅ Côté mariée / marié lisible — dans le panneau « qui est à cette table », chaque invité affichait
seatingStagePanel.side.bri...(clé i18n brute tronquée) au lieu de « Côté mariée ». Le panel utilisait un namespace différent de celui où vivent les libellés.✅ Asseoir met à jour la liste tout de suite — quand on clique « Asseoir » dans le panneau, l'invité passait bien en DB mais la liste « N invités non placés » restait figée jusqu'au prochain reload. Maintenant ça se rafraîchit instantanément (même invariant que les autres actions de l'éditeur).
- Version 2026-05-12.2712 mai 2026(Sprint K hotfix : Tailwind v4 @source restriction + Supabase error UX)
Le rendu de l'éditeur de plan de table marche. Test Chrome MCP exécuté sur dev server local :
✅ Login
/login→ redirige sur/seatingcorrectement (Salma Alaoui, 24 invités, 6 tables).✅ Toggle
Plan 2D→ empty state s'affiche : "Donnez vie à votre salle" + CTA.✅ Click "Définir les dimensions de ma salle" → modale s'ouvre avec defaults 10 m × 15 m, hint "Exemple : 10 m × 15 m pour une réception de 200 invités".
⚠️ Click "Enregistrer" → la modale tente d'écrire
room_width_cmetroom_length_cmsurwedding_eventsmais ces colonnes n'existent pas encore dans la DB locale (la migration K.1 a été commit mais pas encore appliquée à Supabase — c'est BUG-011 process gap connu).✅ L'erreur Supabase est maintenant affichée proprement (message extrait du PostgrestError) au lieu de leaker le raw object stringifié.
- Version 2026-05-12.2612 mai 2026(Sprint K.5 : seating editor V1 — keyboard nav + Vitest unit tests)
Keyboard navigation : avec une table sélectionnée, les flèches du clavier la déplacent par pas de 10 cm. Shift + flèches = 50 cm (le pas de la grille). Le déplacement est borné aux limites de la salle.
- Version 2026-05-12.2512 mai 2026(Sprint K.4 : seating editor V1 — side panel "qui est à cette table")
Click une table → vous voyez qui y est assis. C'est la fonctionnalité que tu voulais.
Un panneau apparaît à droite (≥ 1280 px) ou en bas (1024-1279 px) avec :
- Le nom de la table + capacité (8/10 placés · 2 places restantes).
- Notes éventuelles de la table.
- Liste des invités à cette table avec avatar + nom + côté (époux/épouse). Bouton "Retirer" sur hover.
- Liste des invités non placés (top 8, "voir plus" pour le reste) avec un bouton "Asseoir" qui place directement à la table sélectionnée.
- Si la table est pleine, le bouton "Asseoir" est désactivé avec tooltip "Cette table est pleine".
- Version 2026-05-12.2412 mai 2026(Sprint K.3 : seating editor V1 — toolbar + presets + resize + lock mode)
L'éditeur prend forme — vous pouvez maintenant :
- Ajouter une table depuis la toolbar avec 4 presets : Ronde 8p (Ø 140 cm), Ronde 10p (Ø 180 cm) ← défaut, Rectangulaire 8p (200 × 80), Carrée 4p (120 × 120).
- Dupliquer la table sélectionnée (offset 3 % vers le bas-droite).
- Supprimer la table sélectionnée (confirmation si invités déjà placés).
- Pivoter 90° (rectangles et carrés seulement).
- Redimensionner chaque table en glissant ses poignées (round = ratio préservé, rectangle = libre).
- Verrouiller le canvas pour éviter les déplacements accidentels.
- Zoom +/− depuis la toolbar (en plus de Ctrl + molette).
- Version 2026-05-12.2312 mai 2026(Sprint K.2 : seating editor V1 — Konva Stage interactif (drag + snap + zoom + persistence))
Le canvas devient enfin interactif. Sur la vue "Salle" du
/seating(desktop ≥ 1024 px), une fois les dimensions de la salle renseignées, l'éditeur affiche :- La salle réelle en cm (par exemple 10 m × 15 m visualisée à l'échelle).
- Chaque table dessinée à sa taille physique (rond 180 cm, rectangle 200×80, etc.).
- Drag chaque table dans la salle. Snap automatique sur grille de 10 cm. Contrainte aux bords (les tables ne sortent pas de la salle).
- Toggle grille on/off (lignes 50 cm).
- Zoom Ctrl + molette (30%-300%).
- Pan par drag du fond.
- Sélection d'une table au click (préfigure le panel invités de K.4).
- Persistence automatique 300 ms après la fin du drag (debounce).
- Version 2026-05-12.2212 mai 2026(Sprint K.1 : seating editor V1 foundations — Konva install + dimensions schema + room modal)
Première étape du nouveau plan de table interactif. Visible côté utilisateur :
- Nouvelle option dans la vue "Salle" (toggle déjà présent) qui demande maintenant les dimensions réelles de la salle de réception avant d'afficher quoi que ce soit. Modale claire : largeur + longueur en mètres.
- Le V0 read-only canvas (qui était jugé "nul") est retiré. Le placeholder explique que l'éditeur interactif arrive.
- Version 2026-05-12.2112 mai 2026(Sprint I7 : test-suite expansion — a11y + visual regression coverage)
Pas de changement visible : Sprint I7 (le dernier du post-mortem testing strategy) étend la couverture des tests Playwright (a11y + visual regression) sans rien changer au produit. Quatre surfaces marketing supplémentaires sont maintenant gardées + un primitive-level snapshot des heros.
- Version 2026-05-12.2012 mai 2026(Sprint I6 : 3 nouveaux gates Priority-2 — ICU plurals + mock data + UTC/locale leakage)
Pas de changement visible : suite à Sprint I5 (5 nouveaux gates Priority-1), Sprint I6 ajoute les 3 gates Priority-2 du post-mortem testing strategy. Aucune correction utilisateur, juste de la prévention. Le payoff : 3 classes supplémentaires de bugs ne reviendront plus.
- Version 2026-05-12.1912 mai 2026(Sprint I5 : post-mortem testing strategy — 3 production-audit fixes + 5 new pre-push gates)
Trois corrections issues de l'audit production Playwright (mvp-mlk1.vercel.app) :
1. Console plus propre pour tous les visiteurs anonymes : la requête
/api/notificationsne déclenche plus une erreur 401 à chaque chargement de page publique. L'API renvoie maintenant{ notifications: [], unread: 0 }en HTTP 200 pour les utilisateurs anonymes — comportement sémantiquement équivalent ("vous n'avez aucune notification") sans casser la doctrine defense-in-depth.2. Images vendor sur
/annuaireplus jamais cassées : la fonctionbuildSizedUrln'ajoute plus ses paramètres de transformation Supabase aux URLs externes (Unsplash, Google CDN). Avant : 2 cartes vendor étaient bloquées par Chrome ORB sur l'annuaire à cause d'une URL Unsplash avec paramètres dupliqués. Après : les URLs non-Supabase passent inchangées.3. Warning CSP éliminé : le navigateur n'affiche plus l'avertissement _"The Content Security Policy directive 'upgrade-insecure-requests' is ignored when delivered in a report-only policy"_ à chaque chargement de page. Cette directive ne peut s'appliquer qu'à un CSP enforced, où elle était déjà déclarée.
Côté invisible mais important : 5 nouveaux pre-push gates qui empêchent ces classes de bugs (et 3 autres) de revenir. Chaque future PR qui rouvre une de ces brèches sera bloquée avant le push.
- Version 2026-05-12.1812 mai 2026(Sprint I4.A : landing audit + hero motion migration vers TW_MOTION.fadeUpHero)
Aucun changement visible — la page d'accueil garde son rendu actuel à la frame près. Cleanup interne : le
<h1>du hero/adopte le drawerTW_MOTION.fadeUpHeroajouté danssrc/lib/motion.ts, au lieu d'inlininganimate-in fade-in-0 slide-in-from-bottom-2 duration-700directement dans le JSX. - Version 2026-05-12.1712 mai 2026(Sprint I3 : inline style triage — 46 occurrences éliminées, font-display Tailwind class adoptée)
Zéro changement de rendu côté utilisateur. C'est du nettoyage interne : on enlève les inline
style={{}}redondants dans le JSX au profit des classes Tailwind équivalentes. Bénéfice : un futur changement de typographie (par exemple swapper Fraunces pour une autre serif éditoriale) ne demandera plus de chasser 40+ inline-styles éparpillés à travers le portail public + le dashboard. - Version 2026-05-12.1612 mai 2026(Sprint I2 : token hardening — BUG-170 closure, OG hex extracted, animation timing en motion-lib, text-caption/label migration)
Cette release durcit les fondations design-system avant la grande refonte UI prévue. Aucun changement de fonctionnalité ni de pixel visible pour l'utilisateur final — c'est de la plomberie de design tokens. Le payoff arrive à la prochaine refonte : changer la palette de marque ne touchera plus que 1 fichier au lieu de 13+.
Quatre chantiers consolidés :
1. BUG-170 fermé — 12 cartes-prestataires alignent maintenant leur rayon sur
rounded-2xl(16 px) comme toutes les autres cartes du dashboard, au lieu durounded-lg(10 px) hérité d'avant la doctrine.2. Cartes Open Graph (les aperçus WhatsApp / LinkedIn / X) — les couleurs de marque sont maintenant chargées depuis un fichier de constantes unique (
src/lib/brand-constants.ts), au lieu d'être copiées-collées en hex dans chaque route OG. Une future refonte palette ne nécessitera plus qu'un seul edit.3. Vocabulaire d'animations de hero centralisé : les 4 chaînes Tailwind
animate-in fade-in-0 slide-in-from-bottom-2 duration-500répétées à traversPageHero,PublicBrowsingHeroetLandingQuickStartsont maintenant des utilitaires nommés (TW_MOTION.fadeUp,TW_MOTION.fade,TW_MOTION.fadeUpLong) danssrc/lib/motion.ts. Un changement de langage de mouvement = un seul edit.4. Chips & badges 10 px / 11 px : 15 occurrences de
text-[10px]→text-caption+ 3 occurrences detext-[11px]→text-label(tokens déjà définis dansglobals.cssmais sous-utilisés). - Version 2026-05-12.1512 mai 2026(Sprint I1 : polishing pass — countdown live, back-link unifié, grille de nav recentrée, citation lisible)
Quatre détails du portail public passent de "fonctionnel" à "intentionnel" :
1. La carte "Compte à rebours" sur
/p/<slug>affiche le vrai nombre de jours : "Plus que 47 jours avant le grand jour." (au lieu d'un placeholder statique "Plus que… jours"). Le jour J, la carte bascule sur "C'est aujourd'hui !". Les pluriels sont gérés en 4 langues (fr/en/es/nl).2. Le lien "retour" est désormais identique sur les 12 surfaces du portail : « Retour au save the date » partout, au lieu du mélange précédent « Retour à l'accueil » / « Retour au portail » / « Retour au save the date » selon la section. L'invité comprend immédiatement où il revient.
3. La grille de navigation des 11 sections ne laisse plus de vide en bas à droite : la dernière rangée (2 cartes : "Liste de cadeaux" + "Compte à rebours") se centre désormais horizontalement au lieu de s'aligner à gauche en laissant une 3ᵉ colonne fantôme.
4. L'aperçu du livre d'or sur la home
/p/<slug>ressemble enfin à une citation : un grand guillemet "“" en Fraunces ouvre chaque card, posé à l'intérieur du padding et aligné avec la première ligne du message. Avant : une icône circulaire flottait hors du coin haut-gauche, détachée du texte, comme un badge mal placé.Le portail public
/p/<slug>expose désormais les 11 sections shippées cette semaine dans une grille de navigation lisible. Avant : 2 boutons-pilules (Livre d'or + Cagnotte) — les 9 autres sections (notre histoire, journal, programme, infos, témoins, photos, faq, quiz, compte à rebours) étaient orphelines, accessibles uniquement par URL directe.Maintenant : un sub-header "EXPLORER LE MARIAGE" en lk-gold uppercase, suivi d'une grille 3-col desktop / 2-col tablet / 1-col mobile. Chaque carte : icône lucide en cercle gold (size-10), titre Fraunces semibold lk-navy, descripteur Manrope 1-ligne en ink-500, chevron ArrowRight qui glisse à droite au hover. Bordure
lk-or-pale/40qui passebrand-700au hover + ombreshadow-card.Les invités peuvent enfin découvrir toutes les sections du portail au premier coup d'œil, au lieu de devoir deviner leur existence.
- Version 2026-05-12.1312 mai 2026(Sprint H3 : <PublicBrowsingHero> primitive + /annuaire + /blog migrated)
Aucun changement visible utilisateur — /annuaire et /blog (marketing) gardent leur signature visuelle EXACTE. Le hero navy/full-width de /annuaire reste navy, le hero cream-centered de /blog reste cream-centered. Seule différence : ils sont désormais générés par une primitive partagée au lieu de 2 implémentations sur-mesure dupliquant les mêmes 30 lignes de markup.
C'est un changement zéro-visible-mais-structurant : le code qu'on écrit demain pour
/villes/casablanca(ou n'importe quelle autre page de browsing public) atterrit déjà sur une primitive éprouvée au lieu de réinventer la roue. - Version 2026-05-12.1212 mai 2026(Sprint H2 : /livre-dor admin migré vers <PageHero>)
L'admin
/livre-dor(le Livre d'Or côté mariés) gagne le même header signature que les 11 autres pages admin : eyebrow lk-gold uppercase "Vos invités", titre Fraunces avec underline gold décoratif, sous-titre Manrope italic pour les stats, action "Partager le lien" alignée à droite sur desktop.Visuellement : l'icône BookHeart a disparu (cohérence avec les autres admin pages qui n'utilisent pas d'icônes dans le hero), le titre passe en
text-3xl sm:text-4xl lg:text-5xl(la taille canonique PageHero), et la mise en page hero gagne l'animation d'entrée stagger (eyebrow → title → subtitle → action sur 240ms). - Version 2026-05-12.1112 mai 2026(Sprint H1 : design-system doctrine + 2 modal radius fixes)
Aucun changement visible utilisateur (sauf 2 modals dont les coins sont passés de 10 px à 24 px — celui de la prévisualisation de fichier dans
/messageset celui de l'édition de prestataire dans/admin/vendors/[id]). Le vrai livrable de ce ship est non-visible mais structurel : la doctrine du design système, jusqu'ici implicite après 12 features cohérentes, est désormais documentée. - Version 2026-05-12.1012 mai 2026(Public-portal Sprint 2 + 3 : 6 more sections — Notre histoire, Témoins, Programme, Countdown, QR-photos, Quiz)
Six nouvelles sections atterrissent sur le portail public des mariés. Avec les 3 sections du Sprint 1 livrées plus tôt aujourd'hui, le portail expose désormais 9 surfaces publiques + le save-the-date — couvrant les 8 sections « universelles » des plateformes US/EU (Joy / Zola / The Knot / Zankyou) + les 2026-flavoured polish features (live countdown, QR photo upload, polls/quiz).
Sprint 2 — sections narratives :
- Notre histoire (
/p/<slug>/notre-histoire) — la section centrale décrite par 99 % des couples sur Joy/Zola/Knot. 4 actes : Comment on s'est rencontrés, La demande, Notre chemin jusqu'ici, Pourquoi maintenant. Toggle « double perspective » : chaque section a deux colonnes — chaque marié écrit sa version (format viral sur Instagram). - Témoins & héros (
/p/<slug>/temoins) — bios des témoins / demoiselles d'honneur / héros / proches. Groupé par côté (mariée / marié), photo, prénom + rôle + 2 phrases. Vrai sujet culturel pour les mariages marocains. - Programme (
/p/<slug>/programme) — timeline multi-jours réutilisant la tablewedding_eventsexistante. Henné J-1 → mariage J → sbouhi J+1, groupés par date. Time gutter + venue + dress code par événement.
Sprint 3 — polish 2026 :
- Compte à rebours (
/p/<slug>/countdown) — vue plein écran : « Plus que 42 jours », Fraunces 20vw sur fond gradient ivoire. Trois états : future / today / past. Time-zone-aware (anchored Africa/Casablanca, pas de drift entre invités). Pinterest-trending feature pour les couples qui screenshot vers les stories Instagram. - Photo gallery QR (
/p/<slug>/photos/upload+/photos) — les invités scannent un QR sur les marque-places le jour J, uploadent depuis leur téléphone (pas d'app à installer), les mariés modèrent à/photos-moderation. Galerie publique avec 2 onglets : « Avant le mariage » (curated) / « Le jour J » (guest-upload). Remplace le pattern « shared Google Drive folder ». - Quiz « Qui nous connaît le mieux ? » (
/p/<slug>/quiz) — kahoot-style. Les mariés construisent une question-à-la-fois (choix multiple / vrai-faux / réponse libre) ; les invités jouent ; les mariés voient les résultats agrégés à/quiz-couple/results/[pollId]. 5 templates de questions starter (premier date, plat préféré, lune de miel…) dans l'admin.
- Notre histoire (
- Version 2026-05-12.0912 mai 2026(Public-portal Sprint 1 : Journal/blog + FAQ + Infos pratiques — 3 new sections)
Le portail public des mariés gagne trois nouvelles sections que les invités attendaient depuis des semaines :
1. Notre journal (
/p/<slug>/blog) — les mariés racontent leur préparatifs en posts datés : la demande, la khotba, la première visite de salle, les essayages caftan, le compte à rebours. Les invités scrollent une timeline newest-first, avec photos de couverture et lecture plein écran par post. 14 modèles de posts pré-écrits (de "Notre demande en mariage" à "Merci" post-mariage) accompagnent les mariés au lieu de leur laisser une page blanche.2. Foire aux questions (
/p/<slug>/faq) — la page la plus consultée d'un site de mariage selon les benchmarks US/EU (Joy / Zola / Knot — les invités y reviennent 3-4 fois entre le save-the-date et l'arrivée). Q&A structurées groupées par catégorie : Voyage, Tenue, Programme, Enfants, Cadeaux, Repas, Photos, Autres. 6 questions starter ("Où me garer ?", "À quelle heure arriver ?", "Les enfants sont-ils invités ?") sont suggérées au premier post.3. Infos pratiques (
/p/<slug>/infos) — les hôtels avec code promo négocié (copy-paste en un clic), le parking, la navette de fin de soirée, les recos resto/médina pour les invités qui découvrent la ville, le wifi, le hashtag du mariage. 8 types de fiches couvrent la totalité des questions logistiques.Pour les mariés : trois nouveaux espaces admin (
/mon-blog,/faq-mariage,/infos-pratiques) où ils éditent leurs sections séparément. Le blog gagne une galerie de modèles qui s'ouvre au clic sur "Nouvel article" — 14 cartes regroupées en 4 catégories (Récit du mariage / Pratique pour les invités / Traditions à expliquer / Souvenirs post-mariage) — la couple choisit, le brouillon démarre déjà rempli. - Version 2026-05-12.0812 mai 2026(Album i18n plural fix + bug-ledger cleanup : 5 closures + 1 reclassification)
Sur l'album imprimable du livre d'or (
/livre-dor/album), la légende sous la date de mariage corrige enfin son français :1 voeu gravé pour toujours.au singulier (au lieu de1 voeux gravé, qui mélangeait pluriel et singulier). Les locales EN/ES/NL gagnent au passage un message d'état vide poétique pour les couples qui ouvrent l'album avant d'avoir reçu leur premier message — au lieu d'afficher0 voeux gravés, on lit "Aucun voeu gravé pour toujours." / "No wishes carved forever yet." / "Ningún deseo grabado todavía." / "Nog geen wens vastgelegd.".Cosmétique mais visible sur un livre destiné à être imprimé.
- Version 2026-05-12.0712 mai 2026(Bug tracker restructure : frontmatter Markdown dossiers + retro-log gap + CI gate)
Le suivi des bugs sort de l'archive. Avant aujourd'hui, trois conventions coexistaient (un vieux
BUG_TRACKER.mdinline figé, 39 dossiers per-filedocs/bugs/BUG-111..149.mdfigés aussi, et un lien CHANGELOG vers GitHub Issues qui n'a jamais reçu une seule entrée). Résultat : 10 jours de fixes entre le freeze du 2 mai et aujourd'hui ne figuraient nulle part dans un ledger indexable — uniquement dans le CHANGELOG.Maintenant : 124 dossiers unifiés à
docs/bugs/BUG-NNN.md, tous au même format (frontmatter YAML + corps Markdown), indexés automatiquement à [docs/bugs/INDEX.md](docs/bugs/INDEX.md) avec un tableau de bord par sévérité/statut + les fixes des 30 derniers jours en tête. Commandenpm run bug:new -- "titre"pour en créer un nouveau. Un garde pre-push assure que chaque entrée fix-flavor du CHANGELOG a son dossier associé — la dérive de convention détectée aujourd'hui ne se reproduira pas. - Version 2026-05-12.0612 mai 2026(Livre d'or v2 hotfix : phantom `status` column broke couple-side reads)
Le dashboard couple Livre d'or (
/livre-dor) et l'album imprimable (/livre-dor/album) affichaient "0 voeux gravés pour toujours" et "Aucun message à imprimer pour l'instant" même après que les mariés aient approuvé un message dans la file de modération. La page publique (/p/<slug>/livre-dor) elle, montrait correctement le message. La désynchro entre les deux surfaces était silencieuse : aucun message d'erreur côté UI.Maintenant : un message approuvé apparaît immédiatement dans le dashboard couple, dans l'album souvenir, et sur le compteur du cover ("1 voeu gravé pour toujours."). E2E vérifié via Chrome MCP sur preview Vercel.
- Version 2026-05-12.0512 mai 2026(Livre d'or v2 hotfix : TimelineList render-prop crash on /p/[slug]/livre-dor)
La page publique du livre d'or (
/p/<slug>/livre-dor, celle que les invités voient quand ils cliquent le lien partagé par les mariés) affichait l'écran d'erreur Lalla Kenza ("Quelque chose ne s'est pas passé") au lieu du nouveau design émotionnel shippé en Phase 2. Cause : un composant React mal câblé côté serveur. La page rendre maintenant correctement le couple, le formulaire avec photo optionnelle, et la timeline des voeux.Le calendrier prestataire passe d'une liste verticale primitive à une vraie grille interactive. Pour la première fois, le vendor peut cliquer sur un jour, ajouter une note, ou sélectionner plusieurs jours et les marquer en bloc (Maj-clic pour étendre une plage, Cmd/Ctrl-clic pour ajouter à la sélection). 12 mois affichés en grille 4×3 sur desktop (au lieu d'une longue liste qui prenait 800+px).
L'éditeur de photos accepte maintenant tous les formats d'erreur côté optimisation (HEIC/HEIF, décodage, encodage) traduits dans les 4 langues — EN/ES/NL/FR. Sur mobile, la barre compacte du cockpit est resserrée et accepte un slot d'action mobile-only pour ne pas déborder à 320-375px.
Hotfix : un commentaire JSDoc contenait un escape-hatch class-pattern en exemple, que Tailwind v4 a interprété comme une vraie classe et émis du CSS invalide → 500 sur toutes les pages. Détecté par le walkthrough automatique du dev server.
- Version 2026-05-10.0810 mai 2026(Vendor photos editor — fluide refresh : drag-reorder + bulk select + lightbox + cover hierarchy + auto-optimisation)
L'éditeur de photos prestataire passe d'un outil "fonctionnel" à un outil fluide. Six améliorations qui se renforcent :
- Optimisation auto à l'upload — vous pouvez maintenant déposer vos photos originales (jusqu'à 20 Mo) directement depuis votre iPhone ou appareil photo. Le site les redimensionne intelligemment (max 2400 px) et les compresse en WebP avant de les sauvegarder. Plus besoin d'aller dans Photoshop pour "réduire la taille" — le toast confirme l'optimisation : "Photo ajoutée. Optimisée : 5,2 Mo → 0,9 Mo."
- Glisser-déposer pour réorganiser — finis les boutons ▲ ▼ qu'il fallait cliquer 19 fois pour amener une photo en première position. Saisissez la poignée en haut à droite de la photo et glissez-la où vous voulez. Marche aussi au clavier : Tab pour naviguer, Espace pour saisir, flèches pour déplacer, Espace pour relâcher.
- Sélection multiple + suppression en lot — bouton "Sélectionner" en haut → cochez plusieurs photos → "Supprimer N". Supprimer 25 anciennes photos prend 1 confirmation au lieu de 25.
- Aperçu plein écran — cliquez sur une photo pour l'agrandir. Flèches ←/→ pour naviguer, Échap pour fermer, modification de la légende inline.
- La couverture est enfin évidente — la photo de couverture porte une bordure dorée + un halo + un badge "COUVERTURE" plus visible. Quand vous changez de couverture, la nouvelle photo monte automatiquement en première position pour rester synchronisée avec votre fiche publique.
- Confirmations propres — la fenêtre "Supprimer cette photo ?" du navigateur est remplacée par un toast élégant avec boutons Confirmer / Annuler.
L'éditeur fonctionne dans les 4 langues actives (FR, EN, ES, NL) avec pluriels corrects ("1 photo ajoutée" / "3 photos ajoutées" / etc.).
- Version 2026-05-10.0710 mai 2026(Cockpit consolidation — R-007 rollout to /seating, /planning, /dashboard, /vendor + R-008 sidebar + R-011 tests + R-028 wedding-date + R-032 VendorCard primitives)
Quatre nouvelles surfaces du tableau de bord (
/seating,/planning,/dashboard,/vendor) reçoivent le cockpit éditorial déjà présent sur/budgetet/invites: un en-tête narratif tone-driven avec barre compacte qui reste collée en haut pendant le scroll. Vous voyez en permanence "où en est-on" sans devoir remonter.- Plan de table — les 4 tuiles deviennent une ligne stats inline ; le cockpit dit "X invités encore sans table" en orange si du travail reste.
- Planning — la barre de progression descend dans le cockpit ; le sticky compact surface "X/Y terminées · J% · Z en retard" pendant que vous scrollez les tâches.
- Tableau de bord (accueil) — "{prénom} · J-X" reste visible quand vous explorez la page.
- Espace prestataire — note moyenne (4.6 ★) et taux de réponse toujours visibles dans la barre compacte.
Petits correctifs glissés en passant : "Modifier ma fiche" et "Aperçu public" (espace prestataire) sont enfin traduits dans les 4 langues actives. Le calendrier prestataire refuse désormais les dates aberrantes (typos type
12/31/2026qui devenaient0026-12-31). Et la note publique des prestataires (Dar El Ghalia) ne dérive plus entre 4.6 (page vendor) et 4.79 (annuaire) — un seul filtre Sprint X.2 partout. - Version 2026-05-09.379 mai 2026(Ship AW.14 : audit revisions sur public_vendors)
- 🕵️ Trace des modifications de fiche prestataire — désormais, chaque modification d'un champ de la fiche publique d'un prestataire (nom, slug, description, ville, catégorie, contact, etc.) est tracée avec son before/after. L'équipe Lalla Kenza peut auditer cette trace depuis
/admin/vendors/<id>/activitydans la nouvelle section « Modifications de champs ». Utile pour les disputes Phase 9 escrow ("le prestataire a divisé la capacité par 2 deux jours après confirmation du deal") et pour vérifier qui a touché à quoi quand un modérateur intervient.
- 🕵️ Trace des modifications de fiche prestataire — désormais, chaque modification d'un champ de la fiche publique d'un prestataire (nom, slug, description, ville, catégorie, contact, etc.) est tracée avec son before/after. L'équipe Lalla Kenza peut auditer cette trace depuis
- Version 2026-05-09.359 mai 2026(Ship AW.12 : deals couple ↔ vendor)
- 💰 Suivi des deals couple ↔ prestataire — quand un couple choisit un prestataire onboardé, l'un comme l'autre peut désormais saisir le montant total et l'acompte sur la même fiche partagée. Couple voit ses deals sur
/prestataires/deals, prestataire voit les siens sur/vendor/deals(nouveau bouton « Deals » dans la navigation prestataire). Les deux côtés modifient la même ligne ; chaque modification est visible chez la contrepartie après refresh. Bouton « Marquer l'acompte comme versé » disponible des deux côtés. Notes partagées (5000 caractères) pour acter les conditions, modes de paiement, etc. - 📊 Activité bucket « Deals & paiements » — sur
/vendor/activityun nouveau filtre regroupe les événements financiers : création de deal, modification de montants, acompte versé/remis en attente, notes éditées, suppression. Trace complète accessible aussi depuis l'audit admin/admin/vendors/<id>/activity.
- 💰 Suivi des deals couple ↔ prestataire — quand un couple choisit un prestataire onboardé, l'un comme l'autre peut désormais saisir le montant total et l'acompte sur la même fiche partagée. Couple voit ses deals sur
- Version 2026-05-09.349 mai 2026(Ship AW.11 : vendor custom slug + CI optim + ROADMAP audit)
- 🔗 URL personnalisée prestataire — un prestataire peut désormais choisir son lien public (
/annuaire/<slug>) depuis/vendor/profile, exactement comme l'URL personnalisée de LinkedIn. Affichage live de la disponibilité (✓ disponible,✗ déjà pris,✗ format invalide,✗ réservé) avec debounce 250 ms. Format : minuscules + chiffres + tirets, 3 à 50 caractères. Liste de mots réservés (admin, comparer, pending, etc.) pour éviter les collisions de routes. Avertissement explicite : changer l'URL casse les liens partagés précédemment (Instagram bio, cartes de visite). Le changement est tracé dans le fil d'activité (slug_changedkind).
- 🔗 URL personnalisée prestataire — un prestataire peut désormais choisir son lien public (
- Version 2026-05-09.329 mai 2026(Ship AW.9 : vendor activity feed + audit trail)
- 📊 Fil d'activité prestataire — nouvelle page
/vendor/activityqui montre, en chronologique, tout ce qui se passe sur la fiche : couples qui shortlistent, avis posés, demandes de devis, photos ajoutées/supprimées/réorganisées, modifications de fiche par soi-même ou par l'équipe, modération des avis. Filtres par catégorie (Avis / Demandes & shortlists / Fiche & photos / Calendrier). Le prestataire voit son activité en temps réel — début de la "raison de revenir au dashboard". - 🔍 Audit trail admin — nouvelle page
/admin/vendors/<id>/activityaccessible depuis le bouton « Activité » dans le dialog d'édition vendor. Pour les admins / modérateurs : journal complet de chaque action sur la fiche, avec acteur (couple, vendor, modérateur, admin) et timestamp. Sert à tracer la modération et les éditions admin. - 📭 L'inbox des demandes de devis (
/vendor/inquiries) était déjà shippée (Sprint 0.22.4-B), juste loggée dansFEATURES.md(entrée VEN-08 manquante).
- 📊 Fil d'activité prestataire — nouvelle page
- Version 2026-05-09.319 mai 2026(Ship AW.7 : polish post-AW.6 audit + doc drift)
- 🪞 Mode propriétaire de fiche — quand un prestataire consulte sa propre fiche publique (via le bouton « Aperçu public » de
/vendor/profile), il voit désormais un bandeau dédié : « Vous consultez votre propre fiche publique. C'est exactement ce que voient les couples qui vous découvrent dans l'annuaire. » avec un bouton primary « ✏️ Modifier ma fiche » qui pointe directement vers/vendor/profile. Plus de confusion avec le bandeau « mode prestataire » utilisé pour les concurrents. - 🛡 Bandeau admin / modérateur — un admin ou modérateur consultant une fiche publique voit maintenant un bandeau gris discret « Vous consultez cette fiche en mode administrateur. La modération et l'édition se font dans /admin/vendors. » + bouton « Modifier dans /admin/vendors ». Pré-AW.7 ils voyaient une fiche silencieusement vide de CTA, sans explication.
- 🧹 Barre sticky compacte supprimée pour les non-couples — quand un prestataire / admin / modérateur scrolle, la barre sticky chrome ne s'affiche plus (elle ne portait plus aucun CTA depuis AW.6, c'était du bruit visuel). Les couples conservent la barre comme avant.
- 👨👩👧 Cohérence rôle famille — les helpers famille (rôle
family) ne voient plus les CTA « Choisir / Shortlist / Contacter » dans le hero (cohérent avec la visibilité du formulaire de demande, déjà couple-only). Décision : seul le couple lui-même prend les décisions de réservation, pas ses helpers.
- 🪞 Mode propriétaire de fiche — quand un prestataire consulte sa propre fiche publique (via le bouton « Aperçu public » de
- Version 2026-05-09.309 mai 2026(Ship AW.6 : fiche prestataire vue par un prestataire)
- 🤝 Mode prestataire sur les fiches publiques — quand un prestataire (rôle
vendor) consulte la fiche d'un autre prestataire (/annuaire/<slug>), il ne voit plus les CTA destinés aux couples : « Choisir ce prestataire », « Contacter », « Demander un devis » (inline + dialog), « Écarter pour notre date », « Citer dans une demande de devis ». À la place, un bandeau discret rappelle : « Vous consultez cette fiche en mode prestataire. Les actions de réservation sont réservées aux couples qui planifient leur mariage ». Les contenus restent lisibles (pricing, packages, avis éditorial, calendrier) — c'est de la veille concurrentielle, pas une transaction. - 🛡 Idem pour admins / modérateurs — eux non plus ne sont pas des « clients » potentiels : leur surface dédiée vit dans
/admin/vendors, pas sur la fiche publique. - 📭 Anonymes — les CTA « Demander un devis » sur les packages / « Citer » sur les buckets sont désormais cachés (le formulaire de demande qu'ils déclenchaient n'apparaît qu'après login, donc le clic ne menait nulle part). Le CTA « Contacter » dans le hero reste visible et redirige toujours vers la connexion.
- 🤝 Mode prestataire sur les fiches publiques — quand un prestataire (rôle
- Version 2026-05-09.299 mai 2026(Ship AW.5 batch 3 : vendor self-edit + preview links)
- 🛠 Espace prestataire — édition de fiche — nouvelle page
/vendor/profilequi permet au prestataire de modifier sa propre fiche après onboarding : description, photos (drag-drop, captions, cover, reorder, delete), téléphone, WhatsApp, email, Instagram, site web, adresse. Les autres champs (catégorie, ville, vérification, avis éditorial, packages, calendrier) restent gérés par l'équipe Lalla Kenza. - 👁 Aperçu public — bouton « Aperçu public » disponible sur :
- Le dashboard vendor (
/vendor) — ouvre la fiche publique dans un nouvel onglet. - La page d'édition vendor (
/vendor/profile) — idem. - Le dialog admin/modérateur d'édition vendor — idem.
- 🔗 Lien « Modifier ma fiche » sur le dashboard vendor — accès direct à
/vendor/profile.
- 🛠 Espace prestataire — édition de fiche — nouvelle page
- Version 2026-05-09.289 mai 2026(Ship AW.5 batch 2 : vendor reply to reviews + moderation delete)
- 💬 Droit de réponse pour les prestataires — chaque avis sur la fiche peut désormais recevoir une réponse du prestataire (italic Fraunces, border-left or, eyebrow uppercase « RÉPONSE DU PRESTATAIRE · le 20 avril 2026 »). Éditable par : vendor owner sur sa fiche, admin, modérateur. Jamais par le couple auteur.
- 🛡 Modération avis — un admin/modérateur peut soft-supprimer un avis jugé abusif via
status='rejected'. Le row reste en base (audit) mais ne s'affiche plus côté public.
- Version 2026-05-09.279 mai 2026(Ship AW.5 batch 1 : photo lightbox filmstrip + admin photos editor + DEG enriched)
- 📷 Lightbox photos avec filmstrip — la lightbox affiche maintenant une bande de miniatures en bas. Plus besoin de cliquer next/next/next : on voit toutes les photos d'un coup d'œil et on saute directement à celle qu'on veut. La miniature active s'auto-centre quand on navigue.
- 🛠 Admin/Modérateur peuvent maintenant uploader des photos — la section « Photos & Vidéos » dans le dialog d'édition admin était un placeholder « Upload à venir ». Désormais : drag-drop multi-fichiers (JPEG/PNG/WebP, 5 Mo, 30 max), légendes éditables, toggle photo de couverture, réordonnement up/down, suppression avec confirmation.
- 📍 Dar El Ghalia données précises — récupérées depuis Google Maps : adresse plus-code (C7RH+MJ, Bouskoura, Maroc), lat/lng exactes (33.441654, -7.72093), téléphone +212669161648, URL Google Maps complète.
- Version 2026-05-09.269 mai 2026(Ship AW : avis intelligents + page test Dar El Ghalia Bouskoura)
3 améliorations sur les avis + une page test seedée pour la démo :
- 🛡 Avis post-mariage gated par la date du mariage — si la date du couple est dans le futur, l'option « Oui, le mariage a eu lieu » disparaît du formulaire et un hint explique « Votre mariage n'a pas encore eu lieu — vous pourrez laisser un avis post-mariage le moment venu. ». Évite le flash d'erreur côté serveur que personne ne lisait.
- 🏷 « Signaux pré-mariage » → « Retours avant mariage » — formulation plus humaine. Sous-texte aussi reformulé.
- 📑 Avis collapsed par défaut — la section avis montre la note moyenne + l'histogramme par étoile. Le détail des avis est replié sous un
<details>summary« Lire les 14 avis ↓ ». Les couples qui veulent juste la note voient juste la note ; ceux qui veulent lire ouvrent. - 🏛 Nouvelle page test : Dar El Ghalia Bouskoura —
/fr/annuaire/dar-el-ghalia-bouskoura. 20 photos, bio + contacts depuis Instagram, 14 avis post-mariage (note 4,79 / 5) + 1 retour pré-mariage, 12 dates au calendrier (8 réservées + 4 en option). Sert de démo pour Sprint AV.
- Version 2026-05-09.259 mai 2026(Ship AV : « respiration » — page prestataire éditoriale, navbar full-bleed, calendrier adaptatif)
Suite à un retour utilisateur sur la lourdeur de la page prestataire, 10 changements par retrait (Editorial Minimalism, skill
ui-ux-pro-max) :- 🪶 Navbar full-bleed — drop du
max-w-7xlqui laissait 144 px de gutter mort. Logo + liens à gauche, auth à droite (ml-auto). Tagline masquée sur les surfaces produit. - 🚫 Section nav supprimée — la cockpit-bar sticky suffit ; les ids restent pour les deep-links.
- 📜 Verdict en pull quote éditorial — fini les 3 dots colorés. Blockquote italique Fraunces, border-left or, attribution « L'avis Lalla Kenza ».
- 💗 Hiérarchie CTA — Choisir = primary, Contacter = outline, Ajouter à ma liste = icône cœur 40×40 (mode
iconOnly). - 📊 Pulse activité en ligne fine — 4 cards énormes → une phrase :
33 vues · 5 demandes · 8 shortlistés · 2 choix · 7 derniers jours. - ✨ Suppression des SVG ZelligeFrieze décoratifs dans Trust Ribbon + Editorial Review. Conservation uniquement de l'ornement signature en hero.
- 🎀 Trust ribbon en filet — panel amber → ligne fine
border-yuppercase tracking-widest. - 📦 Description sans card —
max-w-prose(65ch) avec eyebrow tracking-widest. - 🎚️ Crowdsource fondu sous le calendrier — ex-panel amber XL →
<details>summary inline. - 🟢 Compare peek en pastille — ribbon vertical doré → pastille navy 48×48 bottom-right + badge gold.
- 🗓️ Calendrier adaptatif (AV.9) — vue compacte par défaut :
- Verdict line couple-aware au-dessus si la date de mariage est connue.
- Liste chronologique si ≤ 8 indispos.
- Heatmap 12 mois si > 8 indispos (pattern annuel style GitHub).
- Grille 12 mois disponible en deep-dive via « Voir le calendrier complet ↓ ».
- Réduction typique : ~700 px → ~150 px (5× plus compact).
- 🪶 Navbar full-bleed — drop du
- Version 2026-05-09.249 mai 2026(Ship AU : page prestataire phase 2 — lightbox photos, calendrier auto-révélant, CTA par pack, tap-to-call, nav scroll-spy, avis tronqués)
Suite à un nouvel audit design (post-Ship AT), 6 améliorations qui transforment la fiche prestataire en outil de décision rapide :
- 📸 Lightbox photos — clic sur n'importe quelle photo → galerie plein écran avec flèches, ESC, swipe mobile, compteur "3 / 12", caption. Bouton flottant « Voir les N photos » sur la photo principale (pattern Airbnb).
- 📅 Calendrier qui se signale — barre d'aide « Cliquez sur une date pour voir disponibilité + 5 alternatives » au-dessus de la grille. Hover state visible (bg-brand-500/15 + ring) sur chaque jour libre. Aujourd'hui surligné. Bouton « + N autres mois » avec chevron, plus visible (ressemble à un contrôle, pas à une note de bas de page).
- 💳 CTA par package — chaque card a maintenant un bouton plein largeur « Demander un devis pour ce pack → » qui pré-remplit le formulaire en 1 clic (au lieu de 3 : card → dialog → bouton). Le path détails reste inchangé pour qui veut lire avant de demander.
- 📞 Appeler / WhatsApp en boutons — les contacts deviennent des boutons brand-colored (Appeler en or, WhatsApp en vert) au lieu d'un texte gris. Toujours
tel:etwa.meactifs. - 🧭 Barre de navigation sticky — sous le header, 5 onglets
Présentation · Packages · Calendrier · Avis · Contactqui scroll-spy l'avancement de lecture. Click = scroll smooth + URL hash mis à jour pour deep-link. - 📝 Avis tronqués — chaque avis > 360 caractères est clampé à 4 lignes avec « Lire la suite » expand inline (pas de modal).
- Version 2026-05-09.239 mai 2026(Fix BUG-AT-3 : seed-test-data.mjs créait des catégories invalides → "taskCategories.Neggafa" leak sur le dashboard)
Sur le dashboard, les tâches affichaient parfois
taskCategories.Neggafa,taskCategories.Restauration,taskCategories.logisticsbrut au lieu du joli label « Neggafa & Tenues » / « Salle & Traiteur ». Tout est maintenant lisible — 20 lignes existantes corrigées en base + script de seed corrigé pour éviter la régression. - Version 2026-05-09.229 mai 2026(Fix BUG-AT-2 : i18n flat dotted keys cassaient les labels crowdsource & date-finder)
Sur la page prestataire, le formulaire de signalement « Vos infos sur ce vendor ? » affichait
annuaire.vendorPage.crowdsource.kindOption.claimau lieu de « J'ai réservé ce prestataire » dans le<select>. Pareil pour les badges des signalements existants. Sur/annuaire/dates-disponibles, les statuts de prestataires ((réservé),(en option)) affichaient(status.booked),(status.tentative)brut. Tout est maintenant lisible. - Version 2026-05-09.219 mai 2026(Ship AT : refonte interactive de la fiche prestataire — calendrier cliquable, pulse sparkline, éditorial tabs, compare peek, map preview)
La fiche prestataire passe d'une page de lecture passive à une page transactionnelle. Suite à un audit design (52/100 sur l'interactivité), 6 sub-ships viennent transformer chaque section :
- 📅 Calendrier interactif — fini le mur de 1080 px statique. Vue compacte 3 mois par défaut (+ N autres mois ↓). Clic sur un jour → panel avec statut détaillé, alternatives proches libres (algorithme
suggestAlternativeDatesqui propose ±1d/±2d/±1w/±2w/±3w), CTA « Demander un devis pour cette date » qui pré-remplit le formulaire. - 📊 Pulse activité interactive — chaque chiffre devient un bouton hover/focus. Au survol : sparkline 7 jours + delta vs semaine précédente (« ↗ +18% »). Sur tap mobile, cliquer pin l'état.
- ✍️ Avis Lalla Kenza tabs — au lieu de 3 colonnes statiques, segmented
[Forces (4)] [Faibles (2)] [À savoir (3)]. Chaque bullet a une affordance « Citer » au hover qui pré-remplit le formulaire de devis avec la ligne en quote. - 🆚 Compare peek flottant — bouton sticky à droite « Voir 2 alternatives » (visible toute la page). Drawer side avec 4 vendors curés (même catégorie + ville) + CTA « Comparer ».
- 🗺️ Carte de l'emplacement — l'info pratique de l'adresse intègre maintenant un mini-iframe OpenStreetMap centrée sur le prestataire (quand lat/lng curées).
- ↕️ Tri des avis — dropdown « Trier » : Plus récents (défaut) / Mieux notés / Pire notés.
- 📅 Calendrier interactif — fini le mur de 1080 px statique. Vue compacte 3 mois par défaut (+ N autres mois ↓). Clic sur un jour → panel avec statut détaillé, alternatives proches libres (algorithme
- Version 2026-05-09.209 mai 2026(Ship AS : disponibilités crowdsourcées pour les prestataires non-onboardés)
Le calendrier de disponibilité fonctionne maintenant même quand le prestataire n'a pas rejoint Lalla Kenza :
- 🤝 Calendrier partagé par les couples — quand un prestataire n'est pas onboardé, son mini-calendrier est nourri par les couples utilisateurs : « j'ai réservé ce prestataire pour le 22 août » ou « j'ai appelé, ils m'ont dit que cette date était indisponible ».
- 🎨 Distinction visuelle nette — pastilles pleines rouges = calendrier officiel (prestataire onboardé) ; pastilles rouges contournées + bandeau ambre « Reporté par les couples Lalla Kenza » = données partagées (non vérifiées par le prestataire).
- ⚖️ Pas d'infos contradictoires — si 2 couples différents prétendent avoir réservé le même jour, on n'affiche RIEN (mieux vaut une absence de signal qu'un signal trompeur).
- ➕ Couple peut signaler — sur la fiche d'un prestataire non-onboardé, un formulaire « Vous avez des infos sur ce prestataire ? » permet aux couples connectés de partager leurs réservations ou les retours d'appel téléphoniques. Privé (seuls les compteurs agrégés sont publics).
- Version 2026-05-09.199 mai 2026(Ships AQ + AR : compare same-category + date-finder dans /outils + stratégie acquisition)
- 🔒 Comparaison verrouillée par catégorie — quand vous ajoutez une salle dans la comparaison, les boutons « Comparer » des autres catégories (traiteur, photographe…) deviennent grisés avec « Catégorie différente » en tooltip. Comparer une salle avec un traiteur n'avait aucun sens. Le drawer affiche une pastille « Catégorie : Salle de fête » + un X pour vider et redémarrer.
- 🛠️ Outils enrichis — la page
/outilsliste 2 nouveaux outils : Date croisée prestataires (public, sans compte) et Fenêtre de mariage flexible (avec compte). - 🎯 Date-finder reste cross-catégorie — l'outil de date croisée n'enforce PAS le verrou : c'est exactement le cas d'usage (chanteur + salle + maquilleuse).
- Version 2026-05-09.189 mai 2026(Ships AN + AO + AP : guide tests humains + date croisée + fenêtre flexible)
- 🎯 Outil de date croisée (
/annuaire/dates-disponibles) — croise les calendriers de plusieurs prestataires sélectionnés (chanteur + salle + maquilleuse) avec votre fenêtre de mariage. Pastille « Parfait » sur les dates où tout le monde est libre. Accessible depuis le drawer de comparaison via « Trouver une date ». - 🗓️ Fenêtre flexible (
/profil/date-mariage) — 3 modes : date fixée / fenêtre flexible (avril–juin 2027) avec jours préférés (vendredi + samedi) / pas encore décidé. Le couple peut noter les disponibilités au fil des appels prestataires, puis cristalliser. - 📖 Guide de tests humains (
docs/HUMAN_TEST_GUIDE.md) documente les 11 ships AC..AP : URLs, comptes seed, slugs des 5 featured, scénarios + template de bug report.
- 🎯 Outil de date croisée (
- Version 2026-05-09.179 mai 2026(Ships AJ + AK + AL + AM : housekeeping, MCP audit, bug fixes, tests)
Quatre micro-ships consolidés en une release de stabilisation post-AC..AI :
- 🌐 Annuaire fonctionnel en production — la prod servait un état vide alors que la DB avait 45 prestataires vérifiés. Cause :
SUPABASE_SERVICE_ROLE_KEYconfiguré uniquement sur Preview/Dev, pas sur Production. Corrigé. - 🖼️ Cartes prestataires avec photos — les 5 prestataires « featured » affichent maintenant une vraie cover (Riad Al Nour, Studio Lumière, Saveurs Royales, Neggafa Khadija, DJ Younes).
- 🗺️ Vue carte fonctionnelle — l'iframe OpenStreetMap était bloquée par notre Content-Security-Policy. CSP relaxée pour autoriser
openstreetmap.org(frame-src) +images.unsplash.com(img-src pour les seeds).
- 🌐 Annuaire fonctionnel en production — la prod servait un état vide alors que la DB avait 45 prestataires vérifiés. Cause :
- Version 2026-05-09.169 mai 2026(Ship AI : social-proof activity pulse sur la fiche prestataire)
Chaque fiche prestataire montre maintenant son activité récente :
- 🔥 Pulse d'activité 7 jours — un bandeau compact 4 stats sur chaque fiche (juste sous le ruban éditorial) : nombre de couples qui ont consulté, demandes de devis envoyées, ajouts en shortlist, et couples qui ont choisi ce prestataire dans les 7 derniers jours. Les stats à 0 sont masquées (pas de section vide).
- 🛡️ Anonyme et agrégé — aucune information identifiante exposée. Seuls les compteurs sont visibles ; les
couple_idrestent strictement internes.
- Version 2026-05-09.159 mai 2026(Ship AH : annuaire vue carte — pins OpenStreetMap + toggle Liste/Carte)
L'annuaire offre maintenant deux vues complémentaires :
- 🗺️ Vue Carte — un toggle « Liste / Carte » à côté du compteur. La vue carte affiche une carte OpenStreetMap centrée sur les prestataires géolocalisés, plus une liste latérale cliquable. Chaque prestataire pointe vers sa fiche.
- 📍 Pas de carte vide — si aucun prestataire de la sélection courante n'a de coordonnées, on affiche un état vide friendly qui invite à revenir à la liste (les coordonnées sont curées progressivement).
- Version 2026-05-09.149 mai 2026(Ship AG : calendrier de disponibilités prestataire)
Les couples voient maintenant un mini-calendrier de disponibilités sur la fiche prestataire :
- 📅 Mini-calendrier 12 mois — sur chaque fiche, sous les packages : 12 mois de calendrier compact avec des pastilles colorées sur les jours que le prestataire a explicitement marqués (vert = libre, ambre = option / RDV en cours, rouge = réservé). Les jours non marqués restent considérés comme libres — le calendrier ne s'affiche QUE quand le prestataire a curé sa disponibilité (sinon section masquée).
- 🛡️ Confirmation toujours requise — un texte explicite rappelle aux couples de toujours confirmer par message avant de signer (le calendrier est un signal, pas un engagement).
- Version 2026-05-09.139 mai 2026(Ship AE : filtres avancés annuaire — prix + capacité + style + libre-date)
L'annuaire passe d'une grille à 2 axes (catégorie + ville) à un vrai moteur de recherche : prix, capacité, style et disponibilité, tous combinables :
- 💰 Budget maximum — 5 paliers en boutons (≤ 5K / 20K / 50K / 100K / 250K MAD). Les prestataires sans prix indiqué restent affichés (on ne pénalise pas ceux qui n'ont pas encore renseigné leurs tarifs).
- 👥 Capacité (nombre d'invités) — un champ numérique : « capacité 200 invités » garde uniquement les prestataires capables d'accueillir 200 personnes (ceux dont la capacité n'est pas tracée — photographes, faire-part — restent visibles).
- 🎨 Style — chips multi-sélection : Traditionnel, Contemporain, Minimaliste, Bohème, Luxe, Intimiste, Festif, Champêtre. OR-semantics (cocher 2 styles élargit la sélection).
- 📅 « Libre le {date_mariage} » — uniquement quand le couple a renseigné sa date. Cocher le toggle filtre directement sur leur date — aucun prestataire écarté ne ressort.
- 🧹 Réinitialiser — un seul lien efface tous les filtres avancés.
Le panneau de filtres avancés est replié par défaut (
<details>) — il n'encombre pas le visiteur qui ne cherche qu'à parcourir. - Version 2026-05-09.129 mai 2026(Ship AF : comparaison 2-3 prestataires côte-à-côte)
Les couples peuvent maintenant comparer 2 ou 3 prestataires côte à côte sans devoir ouvrir 3 onglets :
- ✅ Bouton « Comparer » sur chaque carte — un toggle compact en bas de la carte annuaire ajoute / retire le prestataire d'une liste de comparaison. La sélection est partagée via l'URL (
?compare=slug1,slug2,slug3), donc un lien copié-collé recharge la même comparaison. - 📌 Drawer fixé en bas — dès qu'un prestataire est sélectionné, un bandeau bas affiche les chips (avec × pour retirer) + un CTA « Comparer ». Le CTA s'active dès qu'on a 2 prestataires (max 3, pour ne pas saturer).
- 🔬 Page /annuaire/comparer — affichage 3 colonnes côte-à-côte. Chaque ligne compare une dimension : note, prix, signature LK, verdict « pour vous si » / « à éviter si », points forts, points faibles, et présence des canaux de contact (téléphone, WhatsApp, email, IG, site). Mobile : scroll horizontal qui garde la lecture fluide.
- ✅ Bouton « Comparer » sur chaque carte — un toggle compact en bas de la carte annuaire ajoute / retire le prestataire d'une liste de comparaison. La sélection est partagée via l'URL (
- Version 2026-05-09.119 mai 2026(Ship AD : annuaire magazine — cards enrichies + featured rotation + tri)
L'annuaire passe d'une grille générique « cover + nom + ville » à une expérience magazine où chaque carte porte ses propres signaux de décision :
- ✨ Cards enrichies — chaque carte affiche maintenant le prix, la note (avec nombre d'avis), et une « citation signature » tirée du premier point fort que la rédaction a noté sur ce prestataire. Les couples peuvent pré-qualifier sans ouvrir la fiche.
- 🏅 Coup de cœur de la semaine — un prestataire mis en avant en haut de l'annuaire dans un bloc 2-colonnes (photo + extrait éditorial + CTAs). La rotation est hebdomadaire et déterministe : tout le monde voit le même héros sur une semaine donnée, et personne ne reste éternellement en haut.
- ⇅ Tri — nouveau menu de tri à droite de la barre de filtres : Pertinence (défaut, mêle « featured first » + note), Mieux notés, Prix croissant, Récents. Aucune action n'écrit dans l'URL si on reste sur la pertinence par défaut (URL canonique courte).
L'annuaire reste 100 % vérifié par défaut, le badge « ✓ Vérifié » est toujours présent, et le tri ne s'applique pas à la fiche prestataire — seulement à la liste.
- Version 2026-05-09.109 mai 2026(Ship AC : verdict 30s + fusion editorial+buckets + AI-enhanceable registry)
La fiche prestataire intègre un nouveau bloc « 30 secondes pour décider » + une consolidation des 2 sections éditoriales redondantes :
- 🎯 Verdict 3-lignes — sous le hero, un bloc « Pour vous si / À évaluer si / À éviter si » que l'équipe rédactionnelle remplit pour aider les couples à savoir en 30 secondes si ce prestataire les concerne. Couleurs explicites (vert / ambre / rouge) avec icônes. Le bloc ne s'affiche que si la rédaction a rempli au moins une des 3 lignes.
- 🪡 Avis Lalla Kenza fusionné avec les 3 buckets — avant : 2 sections distinctes « L'avis de la rédaction » puis « Points forts / Points faibles / À savoir » (redondant). Maintenant : un seul bloc qui combine le paragraphe éditorial + les 3 buckets côte à côte. Plus court, plus lisible.
- 🤖 Bouton « Proposer via Claude » — placeholder dans l'admin pour les futures suggestions IA des champs éditoriaux. Doctrine : draft IA → modérateur valide → publication. Jamais d'auto-publication.
- Version 2026-05-09.099 mai 2026(Ship AB : fixes des bugs MCP de Ship AA + seed 5 reviews testables)
3 bugs identifiés via Chrome MCP testing du Ship AA, tous corrigés :
- 📌 Sticky bar n'apparaît plus à scrollY=0 — bug AA-1 corrigé : le compact bar du cockpit apparaissait fantôme inline sous l'expanded au chargement de la page. Maintenant un guard de 80px bloque tout affichage avant un vrai scroll.
- 🪟 Compact bar visible quand sticky — bug AA-2 : le bar
bg-white/95 backdrop-blurse confondait avec le fond creambg-paper. Désormaisbg-white shadow-mdpour un contraste franc. - 📍 « Écarter pour notre date » placé proprement — bug AA-3 : le toggle flottait orphan right-aligned sous le hero. Maintenant rendu DANS le cockpit (slot
meta), juste après le rating, dans le même bloc que les 3 CTAs.
Plus 1 amélioration testabilité :
- 🌟 5 reviews fictives sur Riad Al Nour — avant aucun vendor n'avait d'avis donc le filter rail Sprint AA.3 s'auto-cachait toujours, impossible à tester en live. Maintenant : 4 post-mariage (2× 5★ + 1× 4★ + 1× 3★) + 1 signal pré-mariage (2★, "Pas de réponse pendant 3 semaines"). La note publique passe à 4.3 ★. Filter rail désormais visible et testable.
- Version 2026-05-09.089 mai 2026(Ship AA : page vendor interactive — sticky cockpit + packages drawer + reviews filter rail)
Réponse au feedback design ("la page vendor est bcp moins interactive que /invites et /budget"). La page prestataire s'aligne sur le pattern workspace :
- 📌 Sticky cockpit sur
/annuaire/[slug]— quand on scrolle sous l'identité, une barre compacte (vendor name + ville + 3 CTAs) reste collée en haut. Plus besoin de remonter pour agir. Smart sticky : se cache au scroll-down (mode lecture), réapparaît au scroll-up. - 🪟 Packages cliquables — chaque package devient un bouton plein. Click → dialog avec tous les détails + bouton « Demander ce package » qui scroll vers le formulaire de devis et le pré-remplit avec un message type incluant nom + prix.
- 🎚️ Filter rail des avis — Type (Tous/Post-mariage/Pré-mariage) × Note (5/4/3/≤2★) × Année. Le rail se cache automatiquement quand il n'apporte rien (1 seul bucket, < 3 avis post-mariage, etc.).
- 📌 Sticky cockpit sur
- Version 2026-05-09.079 mai 2026(Hotfix Z.5 : corrige le crash SSR « `use server` files can only export async functions »)
- 🛠️ Page prestataire à nouveau servable — depuis Ship V (Sprint W.1, 2026-05-09) la page
/annuaire/[slug]crashait silencieusement en SSR sur Vercel : runtime errorA "use server" file can only export async functions, found object. Le bug venait de 2 fichiers de server actions qui exportaient des constantes Zod / des arrays as-const en plus de leurs async functions, ce qui viole une règle stricte de Next.js.
C'est aussi l'explication du deploy Vercel qui restait figé sur Ship V : les builds après W.1 échouaient en runtime (les unit tests passaient car ils mockaient le module et bypassaient la règle).
- 🛠️ Page prestataire à nouveau servable — depuis Ship V (Sprint W.1, 2026-05-09) la page
- Version 2026-05-09.069 mai 2026(Ship Z : bug fixes UX critiques après tests Chrome MCP)
Tests Chrome MCP réalisés sur la page prestataire en condition réelle ont remonté 3 bugs critiques + 1 polish, tous corrigés :
- 🔝 Identité du prestataire toujours au-dessus du fold — avant, sur les vendors sans photos seedées, le carousel rendait un placeholder géant
aspect-[16/10]"Photos en attente de la visite éditoriale" qui dominait 100% du premier viewport. Le nom du presta + les 3 CTAs n'étaient visibles qu'après scroll. Maintenant l'ordre est inversé : identité + CTAs en premier, galerie photo en dessous, et render-nothing-when-empty au lieu d'un placeholder. - ⭐ Plus de fausse note "5.0 ★" sur les related vendors — avant, la carrousel affichait
5.0 ⭐même quandreview_count = 0(la note venait du champ statiquepublic_vendors.ratingdu seed). Désormais l'étoile n'apparaît que quand au moins un vrai avis existe (review_count > 0). Cohérent avec la logique du Hero où la note est déjà gated parcount > 0. - 📞 Téléphone et WhatsApp dédupliqués — avant, dans la carte Contact, si le vendor a renseigné le même numéro pour les deux, on affichait deux fois la ligne (
+212522668800 (préféré)puis+212522668800derrière). Désormais : si les deux champs ont les mêmes chiffres normalisés, on n'affiche que la ligne WhatsApp (lewa.melink couvre messaging + click-to-call fallback). - 🗓️ Dates de visite éditoriale variées — avant, tous les 30 vendors seedés affichaient "Visité par l'équipe le 26 avril 2026" (le
now()du seed). Donnait l'impression d'un seed automatique. Désormais les dates s'étalent sur 10-90 jours en arrière, dérivées d'un hash déterministe du slug. Plus crédible.
- 🔝 Identité du prestataire toujours au-dessus du fold — avant, sur les vendors sans photos seedées, le carousel rendait un placeholder géant
- Version 2026-05-09.059 mai 2026(Ship Y : modération admin des avis + page /admin/reviews)
- 🛡️ Modération admin/modérateur des avis — un admin ou modérateur peut maintenant modifier ou supprimer n'importe quel avis (post-mariage ou signal pré-mariage) depuis une nouvelle page dédiée
/admin/reviews. Pour la team éditoriale Lalla Kenza : on peut corriger une faute, retirer une info personnelle (PII), changer le statut (en attente / approuvé / rejeté), ou supprimer un avis frauduleux. - 🧹 Page de modération — table avec filtres (statut + type d'avis), actions rapides par row :
- 3 boutons quick-flip (Approuver / En attente / Rejeter)
- Bouton « Modifier » → formulaire inline complet (titre, contenu, note, statut, type, signal, nom du couple, date)
- Bouton « Supprimer » avec confirmation 4 secondes (anti-fat-finger)
- 🔗 Lien direct vers la fiche prestataire depuis chaque avis pour vérifier le contexte avant de modérer.
- 📋 Surface des notes éditoriales internes confirmée : la textarea « Notes internes équipe (privées, jamais affichées) » dans
/admin/vendors(modal d'édition d'un prestataire) sert à conserver les impressions de visite, contacts et anecdotes utiles à la team. Visible uniquement pour admins/modérateurs, jamais exposée publiquement (cf. CHECK constraint posée en Sprint U.1 + filtreeditorial_team_visit_notesexclu de toutes les queries publiques).
- 🛡️ Modération admin/modérateur des avis — un admin ou modérateur peut maintenant modifier ou supprimer n'importe quel avis (post-mariage ou signal pré-mariage) depuis une nouvelle page dédiée
- Version 2026-05-09.049 mai 2026(Ship X : packages prix range + reviews engagement-aware)
- 💰 Packages avec plage de prix — un prestataire peut désormais afficher une fourchette
145 000 – 220 000 MAD(au lieu d'un seul nombre) avec une note explicative (« Haute saison +30% », « Selon nombre d'invités »). Pour les forfaits qui varient avec la saison, le nombre d'invités ou les options : plus de pricing menteur. Visible immédiatement sur le package « Mariage royal multi-jours » de Riad Al Nour qui sert de référence (220K-320K). - 🎯 Avis honnêtes en 2 catégories distinctes — quand un couple veut laisser un avis, on lui demande d'abord : « Avez-vous fait appel à ce prestataire ? »
- Oui + mariage passé → avis classique avec étoiles, alimente la note moyenne du prestataire
- Oui mais mariage pas encore eu lieu → on bloque (« patientez ») sauf si le prestataire les a abandonnés (alors red flag accepté)
- Non, juste discuté → signal pré-mariage avec catégorie (communication absente / non professionnel / prix mensonger / abandon last-minute / autre)
- 🎨 Affichage en 2 buckets sur la fiche prestataire :
- Avis des couples mariés (bloc principal) — étoiles + distribution + cards bleu-blanc-or
- Signaux pré-mariage (bloc en dessous, jaune dashed border) — clairement séparé pour que les couples comprennent que ces signaux NE comptent pas dans la note moyenne
- 🛡️ Garde-fou contre les avis prématurés — impossible de poster une review « post-mariage » avant la wedding_date du couple. Refus poli avec invitation à signaler à la place si quelque chose s'est mal passé.
- 💰 Packages avec plage de prix — un prestataire peut désormais afficher une fourchette
- Version 2026-05-09.039 mai 2026(Ship W : couple peut écarter un prestataire pour leur date — toggle + filtre + notif audit)
- 🪄 « Écarter un prestataire pour notre date » — sur la fiche d'un prestataire (
/annuaire/[slug]), le couple connecté voit désormais un petit bouton secondaire « Écarter pour notre date » sous les 3 CTAs principaux. Un clic ouvre une boîte de dialogue avec 4 raisons possibles (pas disponible / déjà réservé / au-dessus du budget / autre) + une note libre optionnelle. Le prestataire disparaît immédiatement de leur annuaire pour leur date de mariage actuelle. - 🔄 Réversible en un clic — le bouton devient « Remettre dans la liste » : pas de double confirmation, l'annuaire récupère le prestataire instantanément.
- 🧹 Liste annuaire filtrée automatiquement — par défaut, les prestataires écartés ne s'affichent plus dans
/annuaire. Si le couple veut les revoir (pour vérifier ou changer d'avis), un filtre « Voir les écartés (3) » apparaît dans la barre de filtres dès qu'au moins 1 mark existe. Les cards écartées sont rendues en grisé avec un badge « Écarté » en haut-gauche pour rester reconnaissables. - 🔔 Trace dans les notifications — chaque action (écarter/remettre) crée une entrée dans le tray de notifications du couple, pour qu'ils se souviennent plus tard pourquoi ils ont rangé tel prestataire (« note: rappeler en septembre »). Toggles successifs sur le même prestataire mettent à jour la même notification au lieu d'en créer plusieurs.
- 🗓️ Auto-mute quand la date de mariage change — si plus tard le couple modifie sa wedding_date, les marks sur l'ancienne date deviennent muets automatiquement (le prestataire réapparaît dans l'annuaire), pas de DELETE forcé. Schéma Ship U respecté côté lecture.
- 🪄 « Écarter un prestataire pour notre date » — sur la fiche d'un prestataire (
- Version 2026-05-09.029 mai 2026(Ship V : vendor page redesign — Wirecutter-style honest review + 3 CTAs + 8 composants)
- 🎨 Page prestataire entièrement repensée (
/annuaire/[slug]) — la fiche d'un prestataire montre désormais 9 sections claires au lieu d'un mur d'infos en vrac :
1. Hero avec galerie photo + identité + 3 boutons d'action distincts (Choisir / Mettre en favori / Contacter)
2. Bandeau de confiance rappelant que chaque prestataire est revu par l'équipe Lalla Kenza
3. Description dans la voix du prestataire
4. Avis éditorial Lalla Kenza dans une carte distincte (typo Fraunces, signature équipe)
5. 3 buckets honnêtes — Points forts (vert) / Points faibles (rose) / À savoir avant de réserver (gris) — comme une review Wirecutter, plutôt qu'un sales pitch
6. Packages structurés avec prix MAD, ce qui est inclus / exclu, validité, et le pick éditorial (★) mis en avant
7. Infos pratiques en grille 2×2 : adresse + Maps, contact (WhatsApp préféré), villes couvertes, social
8. Avis des couples avec moyenne + distribution étoiles en sparkline + cards par review (état vide honnête pré-launch : "Premiers mariages en cours")
9. Formulaire d'inquiry ancré pour le smooth-scroll depuis le bouton Contacter
10. Carrousel de prestataires similaires en bas (4 cards, scroll-snap mobile)
- 🟢 Badge "Listing géré" affiché à côté du nom du prestataire uniquement quand celui-ci a réclamé activement son fiche (signal de présence active, distinct de la curation éditoriale).
- 📝 Tooltip pédagogique sur le badge expliquant la différence : "Ce prestataire gère sa fiche et répond aux demandes."
- 🎨 Page prestataire entièrement repensée (
- Version 2026-05-09.019 mai 2026(Ship U : vendor page schema + admin form — fondations pour le redesign)
- 🛠️ Plomberie interne — pas de changement visible côté couples. Côté équipe éditoriale, le formulaire admin de gestion des prestataires (
/admin/vendors) est étendu pour saisir les nouveaux champs qui alimenteront le redesign de la page prestataire publique : Points faibles + À savoir + Notes internes équipe (privées) + Packages structurés (avec ★ choix éditorial). 4 nouveaux storage buckets posés (vendor-photos, portal-gallery, blog-covers, couple-avatars) avec leurs RLS policies.
- 🛠️ Plomberie interne — pas de changement visible côté couples. Côté équipe éditoriale, le formulaire admin de gestion des prestataires (
- Version 2026-05-08.238 mai 2026(Tanger promu en `planned` — coming soon avec Marrakech)
- 🌍 Tanger rejoint Marrakech avec le badge "Bientôt" dans le footer. La paire de villes "coming soon" devient explicite — les couples de Tanger qui visitent le site voient leur ville signalée comme prochaine extension, plutôt qu'absente. Casa + Rabat restent les villes ouvertes ; Fès reste invisible (2e vague d'extension, pas encore communiquée).
- Version 2026-05-08.228 mai 2026(footer dynamique + supported_cities registry)
- 🌍 Le footer du site liste maintenant les villes supportées avec leur statut. Casablanca et Rabat apparaissent comme liens cliquables vers leurs prestataires (les deux villes de lancement). Marrakech apparaît avec un badge "Bientôt" à côté — non-cliquable, juste pour signaler aux couples concernés que c'est dans le pipe. Tanger et Fès restent invisibles (pas encore planifiées). Quand on flippera Marrakech en
openou Tanger enplanned, le footer se mettra à jour tout seul (un UPDATE SQL d'un row, zéro changement de code).
- 🌍 Le footer du site liste maintenant les villes supportées avec leur statut. Casablanca et Rabat apparaissent comme liens cliquables vers leurs prestataires (les deux villes de lancement). Marrakech apparaît avec un badge "Bientôt" à côté — non-cliquable, juste pour signaler aux couples concernés que c'est dans le pipe. Tanger et Fès restent invisibles (pas encore planifiées). Quand on flippera Marrakech en
- Version 2026-05-08.218 mai 2026(db: codify + normalise public_vendors.cities_covered)
- 🛠️ Plomberie interne — pas de changement visible côté couples. Côté équipe éditoriale, le formulaire d'ajout de prestataire dans l'admin vendors continue de fonctionner comme avant — les checkboxes "Casablanca / Rabat" écrivent maintenant des codes en lowercase en base (cohérent avec la convention seeds + filtre dashboard), avec garde-fou DB qui rejette les valeurs hors whitelist.
- Version 2026-05-08.208 mai 2026(Ship cleanup : audit unique-indexes + 3 zombies recreated + registry hygiene)
- 🛠️ Plomberie interne (suite) — pas de changement visible. L'audit pre-push a été étendu pour vérifier les unique indexes (pas que les colonnes/tables). En l'activant, on a découvert que 3 contraintes d'unicité avaient été silencieusement supprimées lors de la migration Phase 1 (fanout couple_id) — celles qui empêchent un couple d'avoir 2 reviews du même prestataire, 2 entrées de la même prestation dans la shortlist, ou 2 événements avec le même slug. Les 3 ont été recréées en prod. Aucun doublon réel détecté avant la recréation (zéro nettoyage de données nécessaire).
- Version 2026-05-07.197 mai 2026(Ship T : Phase 1 fanout zombie sweep — closes R-027 + 9 siblings)
- 🛠️ Plomberie interne — pas de changement visible. Une dizaine d'objets en base de données (déclencheurs + procédures) référençaient encore une ancienne colonne supprimée lors de la migration "Phase 1" (passage du modèle "1 user" à "1 couple"). Ces zombies cassaient silencieusement quelques actions clés : ajout d'un prestataire au shortlist, mise à jour du budget max, fixation d'une date d'événement, validation RSVP via le portail public d'invités. Tout est de nouveau opérationnel. Un audit pre-push empêche désormais la même classe de bugs de revenir.
- Version 2026-05-05.185 mai 2026(Phase 3.5 — Ship S : shortlist → budget bridge — Tier 2 #3)
- 🔗 Sur la page Prestataires, un nouveau bouton "💰" apparaît à côté de chaque prestataire de ta shortlist. En un clic, il l'ajoute à ton budget — pré-rempli avec son nom, sa catégorie, et son prix le plus bas (s'il en a). Une notification te confirme l'ajout avec un bouton "Voir le budget" pour y aller directement. Plus besoin de retaper le nom du prestataire, sa catégorie, et son tarif quand tu le sélectionnes — c'est automatique.
- Version 2026-05-05.175 mai 2026(Phase 3.5 — Ship R : cash-flow projection timeline — Tier 2 #2)
- 📅 Nouveau widget "Cash-flow prévisionnel" sur la Vue d'ensemble du budget, qui affiche la timeline mensuelle de tes besoins en cash entre aujourd'hui et le jour de ton mariage. Tu vois en un coup d'œil ton reste à payer total, le nombre de mois qui te séparent du mariage, et ton mois le plus chargé. Le mini bar chart affiche par mois : portion verte = ce que tu as déjà payé/programmé, portion or = ce qu'il te reste à mettre de côté, mois du mariage mis en valeur. Ça t'aide à planifier ton épargne au lieu d'être surpris par des paiements groupés.
- Version 2026-05-05.165 mai 2026(Phase 3.5 — Ship Q : variance widget "Estimé vs réel" — Tier 2 #1)
- 📊 \*\*Nouveau widget "Estimé vs réel"
- 📊 Nouveau widget "Estimé vs réel" sur la Vue d'ensemble du budget, qui apparaît dès qu'au moins un de tes prestataires validés remplace une estimation prévisionnelle. Tu vois en un coup d'œil ta précision moyenne ("±15%" au survol), le total estimé vs total réel, l'écart en MAD et en %, le détail par prestation triée par taille d'écart, et un callout "Plus gros dépassement" qui pointe ta plus grosse miss-estimation. Aucun concurrent ne fait ça : c'est l'insight signature du suivi budget Lalla Kenza.
- Version 2026-05-05.155 mai 2026(Phase 3.5 — Ship P : polish bundle (marge tile cliquable + empty state CTAs))
- 🎯 La tuile "Marge restante" du treemap est maintenant cliquable : un clic ouvre directement la modale Objectifs budget pour ajuster ton plafond ou ton objectif sans changer de menu. Au survol, un libellé "Cliquer pour ajuster" apparaît.
- 🚀 Empty state intelligent sur la Vue d'ensemble : quand un nouveau couple arrive sur /budget sans avoir encore configuré son enveloppe, l'écran propose un CTA "Configure mon budget" (au lieu de juste afficher un message vide). Quand l'enveloppe est définie mais qu'aucune dépense n'est saisie, le CTA bascule vers "Démarrer mon budget" qui ouvre la modale Ajouter une dépense. Plus de cul-de-sac.
- Version 2026-05-05.145 mai 2026(Phase 3.5 — Ship O : auto-link actual → forecast + bannière annulable)
- 🔗 Quand tu valides un prestataire dans une catégorie qui a une estimation prévisionnelle, le lien se fait automatiquement. Plus besoin de chercher manuellement quel forecast tu remplaces : l'app détecte l'estimation correspondante et la déplace dans la section "Forecasts remplacés" en arrière-plan. Une notification discrète apparaît avec un bouton "Annuler" (8 secondes) si jamais ce n'était pas la bonne estimation à remplacer — un clic et le forecast revient en attente, comme si rien ne s'était passé.
- Version 2026-05-05.135 mai 2026(Phase 3.5 — Ship N : forecast vs actual UI distinction)
- 🔮 Les estimations prévisionnelles sont désormais visuellement distinctes des dépenses validées sur le suivi budgétaire. Sur le treemap, les forecasts ont une bordure pointillée + un badge "ESTIMÉ" + une teinte plus pâle (3 signaux indépendants pour ne jamais les confondre). Au survol, le tooltip change de header — "🔮 Estimation prévisionnelle" — et le hint footer devient "Cliquer pour ajouter une dépense réelle". Dans la liste détaillée, 3 sections claires apparaissent : Validés (vert), Prévisionnel · à valider (or), et Forecasts remplacés (replié par défaut, montre "Remplacé par {prestataire}"). Quand un actual remplace un forecast, le forecast est masqué du canvas pour éviter le double-comptage mais reste visible dans la liste pour la traçabilité.
- Version 2026-05-05.125 mai 2026(Phase 3.5 — Ship M.1 : nettoyage en profondeur post-Ship M)
- 🛠 Pas de changement visible — gros nettoyage technique déclenché par un audit honnête de Ship M : amélioration de la sécurité du code (validation typée des
kind), réparation du seed de test (cassé silencieusement depuis avril), couverture de tests des règles métier critiques (overpay, date future, plafond < objectif, garde-fous forecast/actual). Quand on shippera la prochaine fonctionnalité, on partira sur une base saine.
- 🛠 Pas de changement visible — gros nettoyage technique déclenché par un audit honnête de Ship M : amélioration de la sécurité du code (validation typée des
- Version 2026-05-05.115 mai 2026(Phase 3.5 — Ship M : forecast vs actual, foundation DB + plumbing)
- 🛠 Ship infrastructurel — aucun changement visible aujourd'hui. Ship M prépare le terrain pour le budget prévisionnel : à partir de Ship N, l'app pourra distinguer les "lignes estimées" (générées plus tard à partir du standing du mariage + nombre d'invités + budget max) des "lignes validées" (vrais prestataires signés). Quand un actual remplacera un forecast, l'historique sera préservé pour des insights du type "tu avais estimé la salle à 80K, tu as payé 200K → +150% de dépassement".
- Version 2026-05-05.105 mai 2026(Phase 3.5 — Ship L : tooltip riche au hover sur le treemap)
- 💡 Quand tu passes la souris sur une dépense du treemap, un panneau détaillé s'affiche : la catégorie + le nom du prestataire (si renseigné), le montant estimé, ce qui a été payé (avec %), le reste à payer, une barre de progression, et tes notes si tu en as ajouté. Plus besoin de cliquer pour vérifier rapidement où tu en es sur une prestation.
- Version 2026-05-05.095 mai 2026(Phase 3.5 — Ship K : règles métier + erreurs claires sur le budget)
- 🛡 Trois nouvelles règles métier sur le budget pour t'éviter de saisir des données incohérentes, avec messages d'erreur clairs en direct (pas besoin d'attendre la sauvegarde) :
- Acompte ≤ montant estimé. Si tu essaies d'enregistrer un paiement de 15.000 MAD sur une prestation à 12.000 MAD, le formulaire t'explique : "Cet acompte de 15.000 MAD dépasse le reste à payer (12.000 MAD)". Le bouton Enregistrer reste grisé tant que tu n'ajustes pas.
- Plafond ≥ Objectif. Dans Objectifs budget, tu ne peux plus définir un plafond inférieur à l'objectif (sinon il serait contournable). Message : "Le plafond doit être supérieur ou égal à l'objectif."
- Date de paiement ≤ aujourd'hui. Le calendrier ne te laisse plus sélectionner une date future, et si tu en saisis une à la main : "La date de paiement ne peut pas être dans le futur."
- Version 2026-05-05.085 mai 2026(Phase 3.5 — Ship J : treemap canvas = budget total + tile "Marge restante")
- 📐 La surface du treemap représente maintenant ton budget total, pas la somme de tes dépenses. Quand tu es sous ton enveloppe, une tuile beige claire avec rayures diagonales apparaît à droite — "Marge restante : X MAD (Y%)". D'un coup d'œil tu vois combien il te reste avant de toucher ton plafond. Un toggle "Surface : Objectif | Plafond" en haut à droite te laisse choisir la référence de comparaison ; par défaut c'est ton objectif tant que tu ne le dépasses pas, sinon c'est ton plafond.
- Version 2026-05-05.075 mai 2026(Phase 3.5 — Ship I : treemap cellules carrées (suppression rounded-md))
- 📐 Les tuiles du treemap sont maintenant de vrais carrés. Avant, chaque cellule avait des coins légèrement arrondis qui cassaient la lecture "carte de portefeuille". Désormais les cellules tilent ensemble avec des arêtes droites, comme un vrai treemap financier. Le container extérieur garde son arrondi pour rester cohérent avec les autres cards de la page.
- Version 2026-05-05.065 mai 2026(Phase 3.5 — Ship H : redesign treemap /budget — flat + gold variations + interactive)
- 🎨 Le treemap de Vue d'ensemble passe en mode "carte de portefeuille". Plus de bandeau catégorie qui scinde chaque bloc en deux : chaque dépense devient sa propre tuile, dimensionnée à son poids dans le total. Les couleurs sont une variation du gold de la marque (du brun profond pour la plus grosse dépense au beige pâle pour la plus petite), au lieu d'un mix vert/ambre/rouge. Au hover, la tuile s'éclaircit légèrement et un crayon apparaît en haut à droite ; un clic ouvre directement la modale Édition.
- Version 2026-05-05.055 mai 2026(Phase 3.5 — Ship G : compact entête /budget — Option A appliquée)
- 📐 Entête de la page Budget réduit de ~390 px à 192 px (88% → 33% du viewport). Les 4 KPI cards (Total estimé / Déjà payé / Reste à payer / Dépenses) sont fusionnées en une ligne inline dans le cockpit, avec les couleurs sémantiques préservées (rouge si over-max, vert sur payé, ambre sur restant). La jauge passe d'une card de 140 px à une barre fine de 30 px sous le summary. Tu vois maintenant les premières dépenses dès l'arrivée, sans scroller.
- Version 2026-05-05.045 mai 2026(FIX Ship F double-render — useScrollMorph rootMargin gave wrong initial scrolledPast)
- 🛠 Cockpit ne se rend plus en double au chargement. Avant ce fix, sur
/budget(et/invites), au scrollY=0, l'utilisateur voyait à la fois le cockpit éditorial complet ET la barre sticky compacte juste en-dessous — alors que le compact aurait dû n'apparaître qu'au scroll. La page chargeait correctement après un premier scroll mais l'état initial était cassé.
- 🛠 Cockpit ne se rend plus en double au chargement. Avant ce fix, sur
- Version 2026-05-05.035 mai 2026(Phase 3.5 — Ship F : sticky cockpit primitive + L1-5 behaviours + InvitesSummary refactored on top)
- 📌 Cockpit toujours visible au scroll : sur
/budgetET/invites, l'entête éditorial se condense en une fine barre persistante qui colle juste sous la navbar dès que tu scrolles. Tu gardes en permanence le contexte (budget engagé / pourcentage payé sur budget, X/Y confirmés sur invites) + les actions (Ajouter / Relancer) à portée d'un clic, sans scroller jusqu'en haut. La barre disparaît quand tu scrolles vers le bas (mode lecture) et réapparaît quand tu remontes. - ✨ Pulse subtil aux changements d'état : quand ton tone budgétaire bascule (par exemple tu marques une dernière dépense soldée → "celebrate") ou que ton invité ultime confirme, le cockpit émet une pulsation discrète (220ms, anneau brand-300) — feedback ambient sans bruit.
- 🎨 Cockpit unifié /budget ↔ /invites : les 2 surfaces partagent maintenant exactement la même mécanique visuelle (frieze, eyebrow, headline narratif tone-driven, hairline gold, stats line). Quand on changera quoi que ce soit dans l'un, l'autre suivra automatiquement.
- 📌 Cockpit toujours visible au scroll : sur
- Version 2026-05-05.025 mai 2026(Phase 3.5 — Ship E : treemap polish — squarified algo + lk-\* tokens + zellige in-cell + hover icons + mobile fallback + retire CategoryGrid)
- 🎨 Treemap éditorial Maghrebi-luxe : les 3 plus gros postes héritent maintenant des couleurs signature Lalla Kenza (or pâle, vert bouteille de Fès, rose poudré). La cellule la plus grosse porte une constellation zellige discrète en filigrane (étoiles Khatem 8-pointes en bas-droite) — distinguable au coup d'œil de Stripe ou Linear.
- 🔲 Cellules quasi-carrées : nouvel algorithme squarified (Bruls 2000) remplace le slice-and-dice. Plus de strips étroits illisibles pour les petits postes. Coiffure 12K (3%) est maintenant lisible avec son label complet.
- ✏️ Affordances claires : au hover sur le header d'une catégorie, une icône ↳ apparaît (signal "filter Liste"). Au hover sur une dépense, ✏️ apparaît (signal "modifier").
- 📱 Mode mobile : sur écrans <600px, le treemap bascule sur une liste verticale "Top dépenses" avec barres proportionnelles cliquables. Plus lisible que des strips de 30px.
- 🧹 Vue Liste épurée : la
<BudgetCategoryGrid>(8+ cards en haut) a été retirée car elle dupliquait le treemap. Liste = pur mode action (search + chips + items), Vue d'ensemble = pur mode analyse (treemap).
- Version 2026-05-05.015 mai 2026(Phase 3.5 — Ship D : 2-view tabs (Liste / Treemap) + retire Ship C over-engineering)
- 🗂 Deux vues sur ton budget : _Mes dépenses_ (mode action — ajouter / éditer / payer) et _Vue d'ensemble_ (mode analyse — treemap proportionnel des postes). Tabs éditoriaux Fraunces avec underline doré qui glisse entre les vues.
- 📊 Treemap des dépenses : chaque catégorie occupe une surface proportionnelle à son montant (la Salle de 200K prend 45% de l'écran, le Caftan de 45K prend 10%). Click sur le header coloré d'une catégorie → bascule sur "Mes dépenses" filtré sur cette catégorie. Click sur une dépense individuelle dans le treemap → ouvre directement le modal d'édition pour la corriger.
- 🎯 Chips statut paiement _(Tous / À payer / En cours / Soldé)_ avec compteurs, persistent entre les deux vues.
- 🔗 URL
?view=overview: reload conserve la vue active, lien partageable.
- Version 2026-05-04.324 mai 2026(FIX budget settings save — missing UNIQUE INDEX on `budget_config(couple_id)` blocked every upsert)
- 🛠 Le bouton "Enregistrer" du modal Objectifs budget fonctionne à nouveau. Avant ce fix, taper un budget visé / plafond et cliquer Enregistrer remontait un toast rouge
Failed to upsert budget config: there is no unique or exclusion constraint matching the ON CONFLICT specificationet la valeur n'était jamais sauvée. Désormais la modale se ferme et la jauge affiche bien tes seuils.
- 🛠 Le bouton "Enregistrer" du modal Objectifs budget fonctionne à nouveau. Avant ce fix, taper un budget visé / plafond et cliquer Enregistrer remontait un toast rouge
- Version 2026-05-04.314 mai 2026(Phase 3.5 — Ship C : sticky filter rail + multi-select + bulk delete on budget)
- 🧭 Rail de filtres latéral sur Budget (desktop) / bottom-sheet "Filtrer" (mobile) — comme sur la page Invités. Trois axes : _Grouper par_ (Catégorie / Statut), _Statut paiement_ (Tous / À payer / En cours / Soldé) avec compteurs, _Catégorie_ (avec icônes + compteurs).
- ✅ Sélection multiple : une case à cocher à gauche de chaque dépense. Coche plusieurs lignes → une barre flottante apparaît en bas avec le bouton Supprimer. Idéal pour nettoyer en masse les lignes obsolètes (changement de prestataire, formule revue à la baisse, etc.).
- 🎯 Grouper par statut paiement : un nouvel angle pour regarder ton budget — _À payer_ en haut (le plus actionnable) → _En cours_ → _Soldé_. Pratique quand tu veux revoir d'un coup ce qu'il te reste à régler avant un échéancier.
- Version 2026-05-04.304 mai 2026(Phase 3.5 — Ship B : break budget-client monolith into 9 focused components)
- (Aucun changement visible.) Refacto interne : la page Budget est maintenant découpée en 9 fichiers focus (chaque modal, le gauge, la liste, etc.) au lieu d'un fichier de 1500 lignes — plus rapide à itérer et à tester quand on enchaîne les améliorations UI.
- Version 2026-05-04.294 mai 2026(Phase 3.5 — propagate /invites design language to /budget : Ship A visual layer)
- ✨ Page Budget alignée sur le langage visuel des Invités : nouveau bandeau cockpit en haut avec une frise zellige dorée, un eyebrow petites-capitales, un titre éditorial, et — surtout — une phrase narrative qui change selon ton état : si tu dépasses ton plafond elle te le dit en vert ; si tout est soldé elle te félicite ; si rien n'est encore commencé elle te guide. Les titres de catégorie passent en font Fraunces avec un petit losange doré (rythme visuel commun avec la page Invités). L'empty state quand tu n'as encore rien ajouté devient éditorial : ornement filet-or, titre Fraunces, CTA "Ajouter ma première dépense".
- Version 2026-05-04.284 mai 2026(Phase 3 form pattern overhaul — Vitest tests on the 4 untested form primitives)
- (No user-facing change.) Internal test coverage for the form primitives (autosave indicator, MAD input, Moroccan phone input, dirty-guard) — protects every form built on top of them from regressions.
- Version 2026-05-04.274 mai 2026(Phase 3 form pattern overhaul — `<MADAmountInput>` roll-out sur 6 sites budget + onboarding)
- 💰 Champs montants MAD avec formatage live sur le budget (Goals, Add expense, Edit expense, Add payment) et l'onboarding step 2 (budget total). Tape
1200000→ s'affiche1 200 000avec suffixe "MAD". Mobile : keyboard numérique. Accepte tous les séparateurs (espaces, virgules, points) — tu peux coller un montant copié depuis Excel sans nettoyer.
- 💰 Champs montants MAD avec formatage live sur le budget (Goals, Add expense, Edit expense, Add payment) et l'onboarding step 2 (budget total). Tape
- Version 2026-05-04.264 mai 2026(FIX root path redirect — utilisateur connecté qui clique le logo Lalla Kenza tombe sur la marketing page)
- 🎯 Cliquer sur "Lalla Kenza" en haut à gauche t'envoie maintenant à TON tableau de bord, pas à la page marketing avec les CTAs d'inscription. Plus précisément : couples →
/dashboard, hero/famille →/family, prestataires →/vendor, admin/modérateur →/admin/vendors. Les visiteurs anonymes (pas connectés) continuent de voir la marketing page comme avant.
- 🎯 Cliquer sur "Lalla Kenza" en haut à gauche t'envoie maintenant à TON tableau de bord, pas à la page marketing avec les CTAs d'inscription. Plus précisément : couples →
- Version 2026-05-04.254 mai 2026(Phase 3.5 A4 — Maghrebi-luxury palette + wax-seal pill effect)
- 🎨 Palette plus marocaine sur la wall des invités. Le petit point devant chaque nom (qui code Côté de la mariée / du marié / commun) ne reproduit plus une palette générique blush/navy/gold ; il utilise désormais 3 hues spécifiques : rose-poudre (henné sec, côté mariée), vert-bouteille (zellige fassi, côté marié), or-pâle (laiton brossé, commun).
- ✨ Pastilles "Confirmé" plus tactiles. Les invités confirmés portent maintenant un effet "sceau de cire" subtil : dégradé radial qui poole la chaleur au coin haut-gauche + 4 ombres internes qui simulent l'enfoncement d'un cachet sur du papier. Si tu ne le remarques pas, tu lis quand même "confirmé". Si tu le remarques, tu lis "ce produit s'occupe de ses surfaces."
- Version 2026-05-04.244 mai 2026(Phase 4 RSVP allergens — couple-side toggle UI dans /parametres)
- 🍴 Activer la collecte des allergies en 1 clic depuis /paramètres. Une nouvelle section "Fonctionnalités optionnelles" affiche la fonctionnalité "Collecte des allergies alimentaires" avec un switch on/off. Activation immédiate ; les invités voient la question RSVP la prochaine fois qu'ils ouvrent leur lien.
- Version 2026-05-04.234 mai 2026(Phase 4 RSVP allergens — public RSVP form chip-picker gated par toggle)
- 🥜 Quand le couple active la collecte des allergies (depuis le moment où il confirme son traiteur — UI couple-side livré au prochain ship), le formulaire RSVP public propose une rangée de pastilles cliquables : Gluten, Fruits secs, Lactose, Fruits de mer, Œufs, Sésame, Autre. L'invité tape ce qui s'applique, le brief traiteur s'enrichit automatiquement.
- 🛡️ Quand le couple n'a pas activé l'option, rien ne change pour les invités — le formulaire reste exactement comme avant. Pas de complexité ajoutée par défaut.
- Version 2026-05-04.184 mai 2026(Phase 3 form pattern overhaul — Pilot 1 + Pilot 2)
- 📞 Champ téléphone de la fiche guest avec masque
+212 6 XX XX XX XXau tape. Validation visible on blur si le numéro n'est pas un mobile marocain valide. Avant : input générique sans guidance ; régulières fautes de saisie et duplicates non détectés. - 🛡 Garde "modifications non enregistrées" sur le formulaire RSVP public. Si un invité tape ses réponses puis ferme l'onglet ou tape "Précédent" par accident, le navigateur lui demande confirmation avant de quitter — plus de RSVPs perdus.
- 📞 Champ téléphone de la fiche guest avec masque
- Version 2026-05-04.164 mai 2026(Phase 3.5 A8 Ship 4 — iOS momentum scroll + chip width cap + budget modal safe-area)
- 📱 Scroll plus fluide sur iOS dans le modal de la fiche guest, le rail de filtres, et le bottom-sheet "Filtrer". L'inertie iOS Safari (momentum scroll) est maintenant activée explicitement — avant : le scroll s'arrêtait sec quand on relâchait le doigt, contrairement au reste du système.
- 📱 Pastilles d'invités plus jamais en surplus horizontal sur mobile. Quand un nom est très long ("Maman de Yassir Alami") la pastille reste contenue dans la largeur de l'écran ; plus de scroll horizontal accidentel.
- 📱 Modal de budget respecte la zone "safe area" iPhone — le clavier virtuel ne masque plus le dernier input quand tu ajoutes une dépense.
- Version 2026-05-04.154 mai 2026(Phase 3.5 A8 Ship 3a — `useLongPressSelection` hook + wire wall)
- 📱 Tu peux maintenant sélectionner plusieurs invités sur mobile : un appui long (~400ms) sur une pastille active le mode sélection et coche cet invité. Le bandeau d'actions groupées (Confirmer / Décliner / Envoyer / Supprimer) apparaît automatiquement. Avant : il fallait un clavier pour faire
Cmd+clic(impossible sur iPhone) ; bulk-actions étaient silencieusement bloquées sur mobile.
- 📱 Tu peux maintenant sélectionner plusieurs invités sur mobile : un appui long (~400ms) sur une pastille active le mode sélection et coche cet invité. Le bandeau d'actions groupées (Confirmer / Décliner / Envoyer / Supprimer) apparaît automatiquement. Avant : il fallait un clavier pour faire
- Version 2026-05-04.144 mai 2026(Phase 3.5 A8 Ship 2 — Public RSVP form mobile : boutons stacked + min-h 44px)
- 📱 Boutons "Confirmer / Peut-être / Décliner" plus faciles à toucher sur mobile. Sur petit écran (320-375 px), les 3 boutons s'empilent verticalement et chacun fait au moins 44 px de haut (recommandation Apple HIG / WCAG 2.5.5). Plus de mis-clics par les invités qui répondent depuis leur téléphone.
- Version 2026-05-04.134 mai 2026(Phase 3.5 A8 mobile audit + Ship 1 — safe-area-inset sur close-X / floating help / bulk bar / lookup CTA)
- 📱 Bouton fermer la fiche guest plus accessible sur iPhone à encoche. La croix en haut à droite respecte maintenant la zone "safe area" du téléphone (Dynamic Island, statut bar) — plus de risque qu'elle se retrouve cachée sur iPhone 14 Pro / 15 Pro.
- 📱 Bulk bar et bouton d'aide bien placés au-dessus du home indicator iPhone. Plus de chevauchement avec la barre de navigation iOS sur les iPhones modernes (notch + home indicator).
- 📱 Bouton de recherche d'invité (RSVP) en pleine largeur sur mobile dans le formulaire de lookup public — plus visible / facile à toucher dans le stack vertical.
- Version 2026-05-04.124 mai 2026(FIX Notes & Dietary indistinguishable + ROADMAP allergens toggle design)
- 🍴 Section Notes & Dietary lisible : les deux champs ne sont plus deux
—identiques. Caption visible ("DIETARY RESTRICTIONS" + 🍴 / "FREE NOTES" + 📄) au-dessus de chaque zone d'édition. Tu vois immédiatement à quoi sert chaque champ, même quand ils sont vides.
- 🍴 Section Notes & Dietary lisible : les deux champs ne sont plus deux
- Version 2026-05-04.114 mai 2026(A1 finish — Contact replié + 2-axis encoding sur la wall avec Utensils/Plane micro-icons + ROADMAP markers Phase 3.5)
- 📞 Section Contact pliée par défaut quand téléphone/email sont déjà saisis. Tu vois
📞 · ✉à droite du titre pour confirmer en un coup d'œil ; tu cliques pour éditer. Économise ~80 px de hauteur sur chaque fiche déjà renseignée. - 🍽️ Pastille fourchette sur la wall quand un invité a des restrictions alimentaires ou des allergies. Tu repères les blockers du brief traiteur en survolant la liste, sans ouvrir chaque fiche.
- ✈️ Pastille avion sur la wall pour les invités internationaux (origine = international). Diaspora workflow : tu identifies en un scan qui doit recevoir un J-45 cron au lieu de J-30.
- 📞 Section Contact pliée par défaut quand téléphone/email sont déjà saisis. Tu vois
- Version 2026-05-04.104 mai 2026(FIX `InvitesBulkSendModal` — `t()` → `t.raw()` sur le template ICU pour stop le `IntlError` et le leak des tokens)
- ✉️ Plus de
{guestName}qui apparaissent dans le modal d'envoi d'invitations. Quand tu cliques sur "Personnaliser le message", la zone d'édition pré-remplit le template proprement et la prévisualisation substitue les vraies valeurs (nom de l'invité, date, lieu, etc.) sans laisser traîner les variables techniques.
- ✉️ Plus de
- Version 2026-05-04.094 mai 2026(refonte fiche invité — chip-row résumé, table assignée, EditableText `inline`, Connection repliée par défaut)
- 👤 Prénom et nom sur la même ligne (régression du
.08corrigée). Ils se lisent comme un nom continu, plus comme deux champs séparés. - 🪑 Tu vois où est assise la personne. Sous le nom, une nouvelle ligne de pastilles affiche : Côté · Catégorie · Cercle · Origine · 🪑 Table assignée pour le mariage · +1 (et son nom) · VIP · Enfant. Le tout sans devoir ouvrir la section "Connection".
- 🪑 Table affichée par cérémonie dans Henné / Sbouhi : si l'invité est placé pour ce jour-là, la table apparaît directement sous le nom de l'événement.
- 🪑 Section "Connection" repliée par défaut quand l'invité est déjà classé. Tu vois ses choix dans la pastille en haut, l'accordéon ne prend plus 250 px de hauteur pour rien.
- ✨ Fini le "Coming soon" sous la timeline d'activité. Le placeholder était trompeur — la feature existe et fonctionne, on ne montre plus rien quand elle est repliée.
- 👤 Prénom et nom sur la même ligne (régression du
- Version 2026-05-04.084 mai 2026(split `guests.full_name` → `first_name` + `last_name` colonnes séparées)
- ✏️ Prénom et nom enregistrés séparément. Tu pouvais déjà saisir un nom complet, mais il vivait dans une seule case. Maintenant le prénom et le nom sont deux champs distincts dans la fiche. Ça débloque les faire-part bien formatés ("Cher M. <nom>", "<prénom>, …"), les tris alphabétiques par nom, le matching plus précis, etc.
- 🪄 Migration silencieuse : tes invités existants ont été splittés automatiquement (premier mot = prénom, le reste = nom). "Aïcha El Fassi" devient
first=Aïcha, last=El Fassi, "Madonna" gardefirst=Madonna, last=∅.
- Version 2026-05-04.064 mai 2026(FIX UI bloquée sur compare modal après merge — `setForceSingleEdit(keepId)` ferme le compare immédiatement)
- 🔄 Quand tu fusionnes des doublons, la fiche se ferme tout de suite. Le ship
.05corrigeait le 500 sur l'action mais l'UI restait bloquée sur le compare modal jusqu'à un hard refresh manuel. Maintenant la modale se ferme dès le clic sur "Maintenir celle-ci".
- 🔄 Quand tu fusionnes des doublons, la fiche se ferme tout de suite. Le ship
- Version 2026-05-04.054 mai 2026(FIX merge duplicates 500 — RLS `deleted_at IS NULL` filter bloquait les soft-delete UPDATEs)
- ✅ La fusion de doublons fonctionne maintenant en prod. Le bug "An error occurred in the Server Components render" sur "Maintenir cette fiche" est résolu.
- Version 2026-05-04.034 mai 2026(Drop zombie `guest_event_rsvp.table_number` + fix group-by-table + repair `guest_portal_events` RPC)
- 🪑 Group-by table affiche enfin les vraies tables : avant, "Sans table" pour tout le monde même quand des invités étaient placés. Maintenant on voit "Table d'honneur · 8", "Famille mariée · 5", "Table 4 · 6", etc. Le bouton "Maintenir un duplicate" fonctionne aussi (le bug DB était sur la même colonne).
- 📋 Le portail invité (
/g/<id>) affiche le bon nom de table : avant cassé pour différentes raisons (legacy schema), maintenant lit le label canonique depuiswedding_tables.
- Version 2026-05-04.014 mai 2026(HOTFIX prod — colonne `guests.deleted_at` manquante en DB cassait `mergeCluster` + autres soft-deletes)
- 🩺 La fusion de doublons (« Maintenir cet invité ») fonctionne à nouveau. Symptôme côté user : "An error occurred in the Server Components render. The specific message is omitted in production builds…". La cause : la colonne
deleted_at(utilisée pour la corbeille / undo des suppressions) avait disparu de la base prod, et chaque action qui filtrait sur elle plantait avant même de se rendre.
- 🩺 La fusion de doublons (« Maintenir cet invité ») fonctionne à nouveau. Symptôme côté user : "An error occurred in the Server Components render. The specific message is omitted in production builds…". La cause : la colonne
- Version 2026-05-03.203 mai 2026(Group-by Cercle par défaut + GROUPER PAR en tête de rail + nouvelle option "Table")
- 🧭 Le wall des invités est maintenant groupé par CERCLE par défaut (Famille immédiate / élargie / Amis intimes / Pro / Obligations sociales) — au lieu du statut. Pourquoi : la couleur du chip indique déjà le statut (gold = confirmé, paper = en attente, barré = décliné), donc grouper par statut ajoutait zéro information. Grouper par cercle révèle la structure sociale orthogonale, qui est le vrai angle de planification.
- 🎛️ Le sélecteur "GROUPER PAR" remonte en tête du rail latéral : avant en bas, replié par défaut. Maintenant en première position, toujours visible. Changer la façon dont le wall est organisé est la décision-IA primaire ; la mettre en tête colle à comment le couple s'oriente sur la page.
- 🪑 Nouvelle option "Table" dans le grouper par : groupe les invités par leur table assignée (Table 1 / Table 2 / …) sur la cérémonie active, avec un bucket "Sans table" en fin pour les invités encore non assignés. Utile dans la phase plan-de-table pour voir d'un coup d'œil "qui reste à placer ?".
- Version 2026-05-03.193 mai 2026(Wall des invités — virtualization CSS-native + chip mémoisé + handler stable)
- 🚀 Le wall des invités reste fluide même à 200+ invités : avant, taper dans la barre de recherche faisait re-render les 200 chips à chaque keystroke (ralentissement perceptible, surtout sur Android moyen-de-gamme et Mac Air M1 sous charge). Maintenant, seul le chip qui change est re-rendu — le reste du wall reste stable.
- 🪶 Sections invisibles à l'écran ne consomment plus rien : les sections en dehors de la zone visible (par exemple "Confirmés · 89" quand tu scrolles dans "À relancer") ne sont plus calculées par le navigateur. Le scroll reste fluide quel que soit le nombre d'invités.
- Version 2026-05-03.183 mai 2026(Refonte chip "confirmé" en gold pâle + ✓ trailing + hover affordances ✕ et nom/prénom)
- 💛 Pastilles "confirmé" repensées : avant, fond bleu marine plein, lourd dans une palette de mariage marocain et le code couleur du côté (mariée/marié) était à peine lisible. Maintenant, fond doré pâle (
brand-100) avec une icône ✓ à droite du nom. Deux signaux pour interpréter le RSVP au glance : la couleur (gold pâle vs paper-blanc-pending), et l'icône (✓ explicite, lisible même par des yeux fatigués ou en daltonisme). - ✕ Le bouton de fermeture (✕) répond maintenant au hover : avant, aucune animation au survol, ça donnait l'impression que c'était décoratif. Maintenant, au survol : background plus prononcé, légère mise à l'échelle (5%), shadow qui se renforce, ET l'icône ✕ tourne de 90°. Lit clairement comme un bouton vivant.
- ✏️ Le nom et prénom sont visiblement éditables : avant, l'affordance "click pour modifier" était quasi-invisible (5% de teinte au survol). Maintenant, au survol du nom : background warm gray + un trait pointillé doré apparaît sous le nom (pattern Notion / Linear). Pour les autres champs éditables, l'icône crayon est visible en permanence à 40% d'opacité, puis 100% au survol.
- 💛 Pastilles "confirmé" repensées : avant, fond bleu marine plein, lourd dans une palette de mariage marocain et le code couleur du côté (mariée/marié) était à peine lisible. Maintenant, fond doré pâle (
- Version 2026-05-03.173 mai 2026(Design critique Ship 2/2 — bouton ✕ accessible 40 px + frise zellige responsive)
- 🎯 Le bouton de fermeture (✕) de la fiche invité est plus grand et plus facile à toucher : passe de 32 px à 40 px, plus proche de la cible Apple/WCAG (44 px). Sur mobile, plus de mistaps quand tu cherches à fermer la fiche d'un pouce.
- ⌨️ Anneau de focus visible au clavier : si tu navigues avec Tab, le bouton ✕ affiche maintenant un anneau or quand il prend le focus. Important pour clavier-only et lecteurs d'écran qui annoncent "Fermer la fiche".
- 📐 La frise zellige du haut de la fiche ne déborde plus sur le ✕ : sur petits écrans, la frise se rétrécit (140 px max) pour laisser le ✕ respirer dans son coin. Sur desktop (≥ 640 px), elle garde sa taille pleine (220 px).
- Version 2026-05-03.163 mai 2026(Design critique Ship 1/2 — i18n plurals hero + tooltip pattern + ghost pill RSVP undo + brand-tinted copy CTA)
- ✍️ Phrase d'en-tête correcte au singulier : avant "Tous vos 1 invités sont confirmés. Place au plan de table." (fail i18n + ton célébration prematuré). Maintenant "Votre invité est confirmé." quand il y en a un, "Tous vos N invités sont confirmés. Place au plan de table." dès 2+. Corrigé en français, anglais, espagnol, néerlandais.
- 💬 Le rappel des "cérémonies secondaires" ne s'affiche plus comme un paragraphe au pied de la section AUTRES CÉRÉMONIES. À la place, une icône "?" discrète à droite du titre — survol/long-tap pour voir l'explication. La modale est plus aérée à chaque ouverture.
- ↩️ "Retirer la réponse" plus visible : avant, un texte-link gris quasi-invisible. Maintenant, une pastille fantôme avec une icône ↩ à gauche. Si tu cliques par erreur sur le mauvais bouton RSVP, le chemin de retour est clair.
- 📋 "Copier le lien RSVP" mis en valeur : la pastille a maintenant un fond crème doré subtil + bordure or. C'est l'action principale de la section CONTACT (la raison pour laquelle on l'ouvre), elle est désormais visuellement reconnaissable au scan.
- Version 2026-05-03.153 mai 2026(Modale invité — close instant + STATUT HÉROS conditionnel + sections auto-déployées)
- 🚀 La fermeture de la fiche invité est instantanée : le bouton ✕ (et la touche Échap) ferment la modale tout de suite, sans le délai d'1-2 secondes qui donnait l'impression que ça ne marchait pas.
- 🧹 Plus de "STATUT HÉROS" sur les invités lambda : la section ne s'affiche que pour les invités qui ont effectivement un rôle hero (témoin, henneya, demoiselle d'honneur…). Pour les 90 % d'invités sans rôle, c'est silencieux.
- 📂 Connexion + Contact pré-déployés s'ils contiennent quelque chose : plus besoin de cliquer pour voir le côté/cercle ou l'email/téléphone si l'info est déjà saisie. Les sections vides (Notes, Activité) restent repliées par défaut.
- Version 2026-05-03.133 mai 2026(Audit Ship 4 — mobile + a11y : tap targets / safe-area / focus restoration)
- 📱 Pastilles invités plus larges sur mobile : la zone de tap des chips passe à 44 px (la cible Apple HIG / WCAG). Plus de mistaps quand tu sélectionnes une pastille fine.
- 📱 Filter mobile : marge sécurisée pour iPhone Pro+ : la bottom-sheet "Filtrer" respecte maintenant la safe-area du bas — plus de risque que la home indicator chevauche le dernier filtre.
- ⌨️ Focus revient à l'invité après fermeture de la fiche : si tu navigues au clavier (Tab + Entrée pour ouvrir, X ou Esc pour fermer), le focus retourne sur la pastille que tu venais d'ouvrir au lieu de partir au début de la page. Important pour clavier-only et lecteurs d'écran.
- Version 2026-05-03.123 mai 2026(Audit Ship 3 — UX safety nets : bulk selection auto-clear + autosave feedback + empty state a11y)
- 🛡️ Bulk selection sécurisée : si tu sélectionnes des invités puis filtres la vue, la sélection se met automatiquement à jour pour ne plus contenir que les invités VISIBLES. Plus de risque de "mark all confirmed" qui touche silencieusement des invités cachés par un filtre.
- ⏳ Indicateur "Sauvegarde…" en temps réel : quand tu modifies un champ dans la fiche invité, tu vois maintenant immédiatement "Sauvegarde…" avec un spinner — plus de doute pendant la 1.5s de debounce. Puis "Enregistré" pendant 4s, puis vide.
- Version 2026-05-03.103 mai 2026(Display/edit mode : Option B click-to-edit live sur la modale invité + name editable)
- ✏️ Modale invité — nouveau pattern d'édition : la fiche d'un invité s'ouvre désormais en lecture par défaut. Click sur n'importe quel champ (nom, email, téléphone, notes, restrictions, plus-one, travel) → ce champ unique passe en édition, autofocus, curseur en fin. Blur, Enter ou Escape valident et reviennent en lecture. Plus de doute sur "est-ce que je suis en train de modifier ou de regarder ?".
- 🐛 Nom éditable : avant on n'arrivait pas à modifier le nom de manière intuitive — il était tout le temps en input flottant, semblait passif. Maintenant : click sur le nom → input avec la même typographie, modifie, blur → sauvegarde. Idem pour tous les autres champs.
- Version 2026-05-03.083 mai 2026(HOTFIX guests : "photo bizarre pendant 1s" sur ouverture modal résolu)
- 🐛 Fix d'animation sur la modale d'invité : avant, en cliquant sur un invité, une "photo bizarre" apparaissait pendant ~1s avant que la fiche s'ouvre proprement. C'était le morph chip→modale qui rendait les contenus de la fiche écrasés à la taille de la pastille. Remplacé par une transition scale + fondu propre.
- Version 2026-05-03.073 mai 2026(HOTFIX guests : "fermer ne marche pas" enfin résolu + bulk-import placeholder i18n)
- 🐛 Bug fix sur la modale d'invité : le bouton X "Fermer" répond maintenant systématiquement, y compris sur les fiches longues. Avant, dans certains cas, le clic semblait partir mais rien ne se passait.
- Version 0.83.142 mai 2026(Round 18 + per-bug dossiers + version footer)
- Version affichée dans le footer, en dessous du copyright. Cliquable → /changelog. Quand on teste le site, on sait immédiatement quelle version est déployée. Pratique pour QA, support, debugging.
- Version 0.83.32 mai 2026(Bug-hunt continued : 7 bugs en plus, rounds 6-7)
- Plan de table : les changements se reflètent immédiatement — drag-and-drop d'un invité (assignSeat) ou retrait (unassignSeat) déclenche maintenant un
router.refresh()côté client après le succès de l'action. Les triggers serveur (seating_activities log, kid auto-table) deviennent visibles sans recharger la page. - Mise à jour de rôle d'un héros : le couple voit tout de suite les changements sur la page /family du héros + /planning (autrefois mise à jour seulement à la prochaine navigation).
- Plan de table : les changements se reflètent immédiatement — drag-and-drop d'un invité (assignSeat) ou retrait (unassignSeat) déclenche maintenant un
- Version 0.83.22 mai 2026(Bug-hunt sprint : 9 bugs trouvés et corrigés en 4 rounds)
- Le compteur de tables sur le dashboard récupère sa valeur : pré-fix, le KPI "X tables" affichait toujours 0 sur la barre sticky parce que la requête filtrait sur
wedding_tables.user_id(colonne droppée en 0.64). Désormais filtre surcouple_id— vrai compte affiché. - "Modifier la taille pour toutes les tables" sur /seating fonctionne enfin. Pré-fix, le bouton était un no-op silencieux (même cause : filtre
user_idsur colonne disparue). - Assignation de tâche à un héros : ne crashe plus avec "column hero_roles does not exist". Le check côté serveur lit maintenant la bonne colonne (
guests.hero_roles). - Dashboard summary : la section "Tâches à venir" charge à nouveau correctement quand un héros est assigné (même cause).
- Le compteur de tables sur le dashboard récupère sa valeur : pré-fix, le KPI "X tables" affichait toujours 0 sur la barre sticky parce que la requête filtrait sur
- Version 0.83.12 mai 2026(Audit doc systématique : 5 rounds, refactor des stale refs)
- Aucun changement visible côté couples. Sprint de qualité documentaire pure.
- Version 0.83.02 mai 2026(Auto-envoi des liens magiques héros — feature-flagged sur RESEND_API_KEY)
- Quand l'env Resend sera configurée, promouvoir un héros enverra automatiquement un email avec le lien magique. Le toast change en conséquence : "X est promu·e héros — un email avec le lien magique vient de partir." La case copier-coller disparaît.
- Fallback préservé : tant que le domaine + DKIM Lalla Kenza ne sont pas wirés (état actuel), tout fonctionne comme aujourd'hui : le couple voit le lien dans une boîte copier-coller et l'envoie via WhatsApp / SMS / email perso.
- Version 0.82.02 mai 2026(Plan 2D des tables — V0 lecture seule)
- Nouveau bouton bascule "Liste / Plan 2D" sur /seating, à côté de "Suggérer un plan" et "Nouvelle table". Le mode Plan 2D affiche les tables comme des formes (rondes par défaut, carrées ou rectangles) sur une vue d'ensemble du sol, avec un code couleur par type (or pour la table d'honneur, rose famille mariée, bleu famille marié, ambre table enfants, blanc standard).
- Aucune fonctionnalité retirée : la vue Liste reste la seule où on assigne des invités à des tables (drag-and-drop). Le Plan 2D est purement visuel pour l'instant — un aperçu de la disposition avant de plonger dans les détails.
- Indicateur visuel de remplissage : barre sous chaque table + ring de couleur (vert = pleine, ambre = vide, par défaut = en cours).
- Version 0.81.02 mai 2026(Drop profiles.hero_roles — single source of truth en prod)
- Aucun changement visible côté couples. Les héros existants gardent leurs rôles, les nouveaux héros sont promus comme avant via /dashboard/heros.
- Version 0.80.01 mai 2026(Promotion de héros depuis la liste d'invités, fini l'email-en-paralèlle)
- Le panneau "Inviter un héros" devient "Promouvoir un invité" : on choisit la personne dans un menu déroulant des invités existants — plus de saisie d'email à la main qui créait un Hassan-en-double dans la liste.
- Empty state guidée : si aucun invité n'est encore ajouté, le panneau affiche un bouton qui pointe directement vers /invites pour en ajouter un.
- Toasts plus précis : "X est promu·e héros — envoyez-lui le lien magique" si pas encore de compte, ou "X est promu·e héros — son compte étant déjà actif, il·elle voit ses tâches immédiatement" sinon.
- Version 0.79.11 mai 2026(Phase D2 + E — hero badges, fiche section, legacy shim)
- Badge "héros" sur les fiches d'invités : pastille teal Sparkles + ring sur la chip de la liste, count si l'invité tient ≥ 2 rôles. Stacké avec la couronne VIP en 3-layer box-shadow quand les deux.
- Section "Statut héros" dans la fiche invité : 7 checkboxes de rôles, CTAs Promouvoir / Save / Régénérer lien / Demote. Magic-link copy-paste box V0. Auto-ouverte quand l'invité est déjà un héros.
- Version 0.79.01 mai 2026(Refactor — heros sont des invités promus, pas des profils parallèles)
- Aucun changement visible immédiatement mais ouvre la voie aux suivants : un héros est désormais une personne dans
/invites(pas un compte parallèle créé via email). Si Hassan est ajouté comme invité puis promu héros, c'est la même fiche, le même row dans la liste, les mêmes seat assignments. Plus de doublons.
- Aucun changement visible immédiatement mais ouvre la voie aux suivants : un héros est désormais une personne dans
- Version 0.78.01 mai 2026(Mariés = invités first-class, auto-seatés à la table d'honneur)
- Les mariés sont maintenant comptés comme invités : le compteur /invites passe de "8/26 confirmés pour Mariage" à "9/27" (en intégrant le marié primaire). Le partner_user_id ajoute un 2ème quand il est lié.
- Auto-placement à la Table d'honneur : dès qu'un couple existe, ses 2 mariés apparaissent automatiquement à la Table d'honneur sur /seating, pour chaque cérémonie active (Mariage + Henné). Plus besoin de s'ajouter soi-même puis de se draguer dessus.
- Suppression bloquée : on ne peut pas accidentellement retirer un marié de sa propre liste d'invités (trigger DB + bientôt UI).
- Version 0.76.01 mai 2026(Toasts en bas à droite, plus en haut au-dessus du navbar)
- Notifications Sonner repositionnées en bas à droite au lieu du haut au centre. Avant : les toasts d'undo (assignment seating, soft-delete fiche, etc.) atterrissaient sur le navbar et cachaient les menus Mariage / Invités / Prestataires / Cadeaux. Maintenant : convention Linear / GitHub / Supabase, discrètes, jamais sur la chrome de navigation.
- Bouton X de fermeture activé sur chaque toast (
closeButton) et toasts non-empilés (expand={false}).
- Version 0.75.01 mai 2026(`/seating` seed lean + `/invites` rail collapsable)
- Seed test couple A repart sur 3 tables canoniques (Table d'honneur + Famille mariée + Famille marié) au lieu des 23 accumulées par les "Proposer un plan" précédents. /seating démarre dans un état initial confortable, pas un mur de 16 cards vides à élaguer.
- Rail /invites — 3 sections collapsables : VIP, Origine, Grouper par sont fermées par défaut, s'ouvrent automatiquement quand un filtre y est actif. Récupère ~200px de fold height pour les sections principales (STATUT, CERCLE).
- Version 0.74.01 mai 2026(`/invites` + `/seating` — Polish & accessibilité)
- Badge +1 en teal/gold au lieu d'amber. Collision avec STATUS résolue :
+1 ?teal cool (pending),+1 ✓/+1 Saragold warm (allowed/confirmed). - VIP visuellement plus fort : couronne 14px + ring or 2px épais.
- Sbouhi désactivé caché du compteur multi-events sur /invites.
- Hide-declined hint : 11px → 12px / ink-500 pour WCAG AA.
- Theme switch étendu au rail VUE : ligne active tinte avec l'accent cérémonie.
- KPI "Tables utilisées" highlight fort (border 2px warn + bg) quand vide.
- Henné teal accessible :
oklch(0.55 0.13 175)(vs 0.7) — WCAG AA OK.
- Badge +1 en teal/gold au lieu d'amber. Collision avec STATUS résolue :
- Version 0.73.01 mai 2026(`/invites` — Hide-declined par défaut)
- Fiches déclinées masquées par défaut sur le wall. À J-114 du mariage, voir "Concierge Ahmed" barré tous les jours pollue. Une ligne discrète "(N fiches déclinées masquées) · Afficher" reste accessible en bas de la barre d'outils. Clic sur le filtre "Décliné·e·s" dans le rail surcharge automatiquement (l'utilisateur demande explicitement à les voir).
- URL state préservé :
?dec=1dans l'URL signifie "afficher les déclinés" (encodage inversé pour des URLs plus courtes — la valeur par défaut "masquer" reste l'absence du param).
- Version 0.72.01 mai 2026(`/seating` — Spatial V0)
- Pool des invités non-assignés en sidebar droite sticky (≥ 1280 px). Sur mobile/laptops 1024-1279 px, le pool reste séquentiel en bas (BC).
- Couleur par cérémonie : Mariage = navy/gold, Henné = teal/curcuma, Sbouhi = rose/pêche. Le kicker, le hairline et le banner "dernière action" adoptent l'accent. Le chrome (frieze, header) reste LK.
- Toast Annuler 12 secondes (vs 6).
- Banner "Dernière action" persistant avec Annuler. Survit au toast.
- Version 0.71.01 mai 2026(`/invites` — Diaspora workflow V0)
- Bloc Voyage sur la fiche quand l'invité est marqué
InternationaleouMaroc autres villes. Trois champs : Arrivée prévue (date), Hôtel (texte libre), Vol confirmé (case). Pas de friction quand l'origine est locale — le bloc disparaît. - Pour la diaspora : permet au couple de tracker en un coup d'œil "qui n'a pas encore confirmé son vol", "qui n'a pas d'hôtel", "qui arrive quand". Le filtre rail Origine → Internationale donne la liste réduite.
- Bloc Voyage sur la fiche quand l'invité est marqué
- Version 0.70.01 mai 2026(`/invites` — Plus-one lifecycle + dress code)
- Accompagnant explicite sur chaque fiche : 4 états au lieu d'une simple case à cocher.
- Pas d'accompagnant (défaut, le couple doit explicitement autoriser)
- Demandé — en attente du nom : autorisé, attend que l'invité communique le nom
- Autorisé (sans nom) : +1 anonyme accepté
- Confirmé avec nom : ex. "+1 Sara"
- Badge +1 sur la pill dans le wall :
+1 ?(amber, en attente),+1 ✓(or, autorisé), ou+1 Sara(or, confirmé). Invisible quand le statut est "Pas d'accompagnant" pour ne pas alourdir le wall. - Code vestimentaire par cérémonie dans /events : champ libre par cérémonie (caftan obligatoire pour le Henné, smoking pour le Mariage). Auto-inclus dans le template d'invitation par défaut grâce à la variable
{dressCode}qui se formate proprement (ou disparaît si vide).
- Version 0.69.01 mai 2026(`/invites` — kilimini social-mesh modeling)
- Cercle, Origine, VIP — trois nouvelles dimensions sur la fiche invité, pensées pour les couples bobos marocains. Le filtre "Côté" (mariée/marié/communs) disparaît de /invites — il est culturellement faible pour cette cible — et est remplacé par deux axes orthogonaux :
- Cercle : Famille immédiate / Famille élargie / Amis intimes / Pro / Obligations sociales (5 buckets, single-select)
- Origine : Locale (Casa) / Maroc autres villes / Internationale (3 buckets)
- VIP : pictogramme couronne + ring doré + pin top-of-bucket. Pour les ~10 invités hors-norme par mariage (parrain, mentor, ministre, artiste). Visible immédiatement dans le wall, candidat auto pour table d'honneur en 0.72.
- "Côté" reste sur /seating où il est utile (équilibrer les tables).
- Version 0.68.01 mai 2026(`/invites` + `/seating` — information density)
- Plan de table — KPI plus utile. Avant : "Capacité 2/190" qui ne disait rien (190 = total des places sur 23 tables vides au seed). Maintenant : "Tables utilisées 1/23" — tu vois immédiatement combien de tables sont vraiment occupées vs vides à élaguer.
- Compteurs Mariage + Henné permanents sur /invites. Ligne discrète sous le sous-titre : "◆ Mariage 7/27 · Henné 5/30". Plus besoin de switcher de vue pour vérifier l'autre cérémonie.
- Notes inline sur chaque table. "À côté du DJ", "Végétariens", "À éviter avec Tata Aisha" — tu cliques sur la note pour l'éditer, ça sauvegarde au blur. Le champ existait en BDD depuis longtemps mais n'était surfacé nulle part.
- Header dashboard épuré. Le baseline "Votre mariage, notre passion" disparaît sur les surfaces de travail (/invites, /seating, /vendor, /admin) — il reste sur landing/marketing. ~80 px de fold récupérés.
- Skeleton loading sur /invites et /seating pendant les transitions de route et les cold-Vercel boots, plutôt qu'une page blanche silencieuse.
- Version 0.67.130 avril 2026(`/seating` — fix silent rollback when assigning a guest)
- Plan de table — assignation cassée corrigée. Pendant l'audit du sprint 0.67, glisser/cliquer un invité sur une table affichait brièvement son nom puis le rejetait au pool non-assigné — la base ne sauvegardait jamais l'assignation. Réparé : Hassan reste assis, le toast d'annulation 6 s fonctionne, et chaque cérémonie (Mariage / Henné) garde son plan indépendant.
- Politique RLS sur
guest_event_rsvprecréée. Symptôme côté /invites : les 26 fiches du seed apparaissaient toutes dans "À chasser" parce que les données RSVP étaient illisibles depuis la session du couple. Corrigé.
- Version 0.67.030 avril 2026(`/seating` — cultural deepening + `is_kid` badge)
- Surface
/seatingredessinée dans le même langage visuel que /invites : frise zellige en haut, papier-grain en arrière-plan, hairline gold sous le titre, lozenge bullet devant l'eyebrow. - Badge enfant 🧒 sur les fiches d'invités flagués
is_kid— visible dans le pool non-assigné (icône remplace le pictogramme générique) ET dans les sièges assignés (icône avant le nom). Toneinfo(bleu) pour ne pas confondre avec les autres tones du rail. - Cron auto-announce + warning modal = follow-up dédié (sortie du scope de cette série de sprints pour préserver le délai de testing).
- Surface
- Version 0.66.030 avril 2026(`/seating` — search + undo + `is_kid` UI dans /invites)
- Recherche par nom dans le panneau "Non assignés" : input full-width + bouton clear, filtre côté client en parallèle des filtres rail.
- Annulation 6s sur chaque déplacement : un toast Sonner apparaît ("Adil déplacé à Table 3 · Annuler") après chaque drag réussi. Clic sur Annuler → restaure la table précédente (ou l'état non-assigné).
- Toggle "Enfant" dans la fiche /invites (accordéon Connexion) : le couple coche pour les enfants. Driver pour la kids-table dans le seating en 0.67.
- Version 0.65.030 avril 2026(`/seating` — side rail + per-event view + RSVP awareness)
- Rail latéral à 4 sections : VUE (Mariage ★ / Henné / Sbouhi), STATUT (4 stages cochables avec gradient ambré identique à /invites), CÔTÉ, TYPE TABLE.
- Plan de table par cérémonie : un invité peut être à Table 5 pour Mariage, Table 2 pour Henné. Organisations indépendantes.
- Awareness RSVP : pool non-assigné = confirmés + maybe + 2 sub-stages pending par défaut. Déclinés cachés à jamais ; "à inviter" aussi.
- Mobile : bottom-sheet avec le même rail.
- Version 0.63.130 avril 2026(Hotfix — `summaryActionable` ICU bug + cleaner eyebrow)
- Le titre principal sur
/invitesaffichait littéralementinvitesV2.summaryActionableau lieu d'un texte traduit. Maintenant : "X invités à relancer pour Mariage, J-N." correctement rendu dans les 4 locales. - L'eyebrow "MARIAGE · MAIN CEREMONY" devient "MARIAGE · DEFAULT VIEW" (et équivalents) — moins redondant avec la stats line en dessous qui répète déjà "for Mariage".
- Le titre principal sur
- Version 0.63.030 avril 2026(cleanup — suppression /invitations, /invites/send, guest-groups, invitation_groups)
- Suppression de
/invitations: la page legacy qui orchestraitinvitation_groups(groupes d'invités, lien de groupe par couple, etc.). Toute la fonctionnalité a été absorbée par le pipeline 0.61.0 du modal bulk-send sur/invites. - Suppression de
/invites/send: la page d'envoi individuel par invité. Subsumée par le bulk-send modal, qui gère un envoi à la fois ou batch indifféremment.
- Suppression de
- Version 0.62.030 avril 2026(`/invites` — timeline d'activités + `/events` toggle d'activation)
- L'accordéon Activité du modal de fiche est vivant. Avant : "L'historique d'interactions arrive bientôt". Maintenant : timeline reverse-chronologique avec icône par type d'événement (création, invitation, livraison, ouverture, réponse, relance, statut modifié, note manuelle), date relative ("il y a 3 heures") + tooltip date absolue, badge canal (WhatsApp / Email / En personne), et pour les transitions de statut le delta "Pending → Confirmé".
/eventsredessiné en panneau de toggles. Mariage est marqué "Obligatoire" + switch grisé (impossible à désactiver). Sbouhi et Henné ont chacun un switch ON/OFF, avec leur description sous le titre ("Cérémonie féminine, la veille du mariage" pour Henné). Désactiver une cérémonie ne supprime PAS les RSVP collectés — ré-activer plus tard restaure tout.
- Version 0.61.030 avril 2026(`/invites` — bulk-send invitations + tracking d'ouverture + alignement BDD)
- Bouton "Envoyer les invitations" dans la bulk-bar : sélectionne N invités → modal 3 étapes (canal · message · confirmation). Email (Resend) · WhatsApp (deeplinks wa.me) · WhatsApp Business (placeholder Meta Cloud API) · Manuel (donné en personne). Mode manuel pré-remplit optionnellement la réponse — l'invité peut toujours changer plus tard.
- Tracking automatique des ouvertures :
/g/{publicId}?inv={token}marqueopened_atcôté serveur, le rail STATUT passe la fiche de "Invités, en attente" vers "Consultés, en attente" instantanément.
- Version 0.60.030 avril 2026(`/invites` — pipeline RSVP à 6 stages + rail STATUT à 6 lignes)
- Le rail STATUT distingue maintenant 4 nuances de "à relancer" :
À inviter(l'invitation n'a pas encore été envoyée),Invités, en attente(envoyée mais le lien n'a pas été ouvert),Consultés, en attente(ils ont vu l'invitation mais n'ont pas répondu), etPeut-être(réponse "tal vez"). Plus les classiquesConfirmésetDéclinés. L'ambré s'intensifie par étape — visuellement on lit "agis maintenant" d'une seule traversée du rail. - Le statut courant peut changer à tout moment : un invité qui a confirmé puis change d'avis met juste à jour son RSVP via le portail public. Le journal d'activités (à venir 0.62.0) gardera la trace de chaque changement, donc le couple n'aura plus à se demander "était-ce un oui ou un non au final".
- Le rail STATUT distingue maintenant 4 nuances de "à relancer" :
- Version 0.59.030 avril 2026(BDD — fondation pipeline d'invitation, 3 cérémonies canoniques, journal d'activités)
- Le modèle des cérémonies est resserré aux 3 vraies cérémonies marocaines : Mariage (toujours active, ne peut pas être désactivée), Henné (cérémonie féminine, la veille du mariage — optionnelle), Sbouhi (petit-déjeuner du lendemain en famille proche — optionnelle). Adieu les types vagues "Cérémonie religieuse / civile / Soirée / Brunch / Custom" qui dupliquaient les concepts.
- Toggle d'activation préparé : chaque couple a désormais les 3 lignes pré-créées (Mariage active, Henné + Sbouhi désactivées). Le jour où un couple veut activer Henné, c'est juste un toggle dans
/events— pas d'INSERT, pas de perte de données si on le réactive plus tard. - Préparation du pipeline d'invitation : la BDD a maintenant la structure pour tracer toute la vie d'une invitation — quand le couple l'envoie, quand l'invité la reçoit, quand il l'ouvre, quand il répond (et s'il change d'avis plus tard). L'UI qui consomme ces données arrive en 0.60.0 → 0.62.0.
- Version 0.58.030 avril 2026(`/invites` — Phase 3.5 A4 deepening esthétique culturelle)
- L'écran respire la culture maghrébine. Avant :
/invitesétait
un dashboard SaaS générique avec les couleurs de la marque
(or, marine, crème). Maintenant : trois ornements crafted
apparaissent à des endroits gagnés —
- Une frise zellige (étoiles 8 branches reliées par des
losanges, tracées en or à fine opacité) en haut du résumé,
en haut du rail latéral, et en haut du modal de fiche. Le
motif s'inspire directement de la tessellation Atlas Lattice
déjà utilisée sur la landing — même vocabulaire géométrique,
aplati en une bande linéaire pour servir de marge ornementée.
- Une texture papier-grain (bruit fractal très subtil, ~3%
d'opacité) sur tous les fonds crème : le mur, le rail, le
modal. Surface lit comme du vrai papier plutôt que comme un
blanc plat.
- Une règle hairline or sous le titre du résumé : ligne fine
qui dégrade brand-300 → brand-500 → brand-300, fait dialoguer
le headline et la stats line sans laisser un blanc trop large.
- Petits losanges or comme puces avant chaque libellé STATUT /
CÔTÉ / VUE / GROUPER PAR du rail, et avant l'eyebrow du résumé
("Pour [Mariage] · Vue principale"). Rime visuelle entre tous
les small-caps de la surface — on lit "ces étiquettes
appartiennent à la même famille de motifs".
- **Bouton "?" flottant en bas à droite redessiné en cachet de
cire** : double anneau or, intérieur papier, "?" en serif
Fraunces. Lit comme un petit ornement crafted plutôt qu'un
bouton flottant générique.
- L'écran respire la culture maghrébine. Avant :
- Version 0.57.030 avril 2026(`/invites` — Phase 3.5 A5 rail latéral des filtres + bottom-sheet mobile)
- Tous les filtres dans une seule colonne. Avant : les chips
Statut / Côté étaient sous le titre du résumé, le sélecteur de
vue (Mariage / Henné / Soirée / Sbouhi) et le menu "Grouper par"
étaient dans la barre d'outils du mur. Cognitive overhead : "où
est le filtre pour X ?" devenait une micro-décision constante.
Maintenant : un rail latéral à gauche (sticky, 220px) regroupe
tout dans 4 sections claires — STATUT, CÔTÉ, VUE, GROUPER PAR
— chacune avec un compteur en regard de chaque option.
- Pattern Linear / Apple Mail / Things 3 : un seul endroit où
chercher, navigation au clavier possible, état actif visible
(point coloré + fond
brand-500/10). La pastille en regard dechaque ligne montre instantanément combien d'invités sont dans
cette catégorie.
- Mobile : bouton "Filtrer" dans la barre d'outils ouvre un
bottom-sheet qui contient exactement le même rail. Un badge avec
le nombre de filtres actifs apparaît sur le bouton si au moins
un filtre n'est pas sur "Tous". Backdrop semi-transparent +
drag-to-dismiss (clic sur le fond ferme).
- Le résumé en haut redevient ce qu'il devait être : un
headline + une CTA "Relancer X invité.e.s" si pertinent. Plus de
bandeau dense de chips qui squattent l'espace visuel.
- Version 0.56.030 avril 2026(`/invites/doublons` — Phase 3.5 A7 page canonique de revue + persistance "ce sont 2 personnes différentes")
- Nouvelle page
/invites/doublonsdédiée à la revue des doublons.
Avant : 4 endroits différents signalaient "doublon-ish" (bannière
jaune sur le mur, marqueur ambré
!sur les pastilles, bannerambré dans le modal, banner rouge à l'autosave). Maintenant : une
page unique liste TOUS les clusters détectés, chaque cluster est
une carte qui montre toutes les fiches concernées côte-à-côte avec
une vue d'ensemble — RSVPs par cérémonie, contact, notes — et deux
actions par cluster :
- "Garder X · fusionner les autres" par fiche (même action
mergeClusterque la modal compare 0.51, avec annulation 6s).- "Marquer comme distincts" au niveau du cluster — persiste
la décision dans la nouvelle table
guest_dedup_decisions. Lecluster ne sera plus jamais signalé tant que les fiches restent
inchangées. Toast d'annulation 6s également.
- La bannière jaune sur le mur garde un lien direct vers la
nouvelle page (bouton "Page Doublons →"). Le toggle "Filtrer ici"
reste pour les utilisateurs qui veulent rester sur le mur.
- Empty state propre : "Liste propre · Aucun cluster détecté"
quand toutes les décisions sont prises ou qu'il n'y a aucun doublon.
- Nouvelle page
- Version 0.55.030 avril 2026(`/invites` — Phase 3.5 A2 validation live des doublons pendant la frappe)
- **Quand vous tapez le nom / téléphone / email d'un invité dans la
modale, un petit avertissement ambré apparaît directement sous le
champ** dès que le système détecte un conflit avec une fiche
existante. Avant : il fallait attendre 1.5s que l'autosave se
déclenche, et un bandeau ROUGE apparaissait alors en haut de la
modale, alors qu'on était déjà passé au champ suivant. Maintenant :
le hint apparaît instantanément (250ms après la pause), exactement
là où vous regardez. Un bouton "Ouvrir" pour basculer vers la
fiche conflictuelle.
- L'autosave continue de se déclencher comme avant — le bandeau
rouge "blocage" reste le filet de sécurité (pour le cas rare où un
autre onglet aurait créé la collision entre-temps). Mais la
plupart du temps, l'utilisateur voit le hint, modifie le champ,
et l'autosave passe sans drame.
- Version 0.54.030 avril 2026(`/invites` — Phase 3.5 A1 modale en accordéons + A3 raccourcis clavier visibles)
- La modale d'invité est divisée par deux verticalement. Avant :
10 sections empilées (Connexion / Mariage RSVP / Cérémonies /
Contact / Notes / Activité / Footer) — il fallait scroller 200 px
pour atteindre le RSVP Mariage. Maintenant : le hero (nom +
side·category) + les 3 boutons RSVP Mariage sont toujours visibles
top-of-fold, le reste se replie en accordéons fermés par défaut.
Chaque accordéon affiche un aperçu à droite de son titre
("Contact 📞 · ✉" si phone+email remplis, "—" sinon) qui dit
l'essentiel sans qu'on l'ouvre.
- L'accordéon des cérémonies secondaires s'ouvre tout seul si
le couple a déjà engagé un RSVP Henné/Soirée/Sbouhi. 80% du temps
les guests n'ont qu'un RSVP Mariage → l'accordéon reste fermé,
donnant plus de place au reste.
- **Le bouton ⌘K est maintenant visible directement dans la barre
de recherche** (alignement à droite, style Notion / Linear). Plus
besoin de connaître le raccourci à l'avance pour le découvrir.
- Un bouton flottant "?" en bas à droite de la page Invités
ouvre la cheat-sheet des raccourcis. Permanent (sauf si le bulk
bar / une modale est ouvert), visible dès le premier paint.
- Tip flottant à la première visite : sur la toute première
ouverture de /invites, un mini-callout au top de la page rappelle
les deux raccourcis principaux ("
/rechercher ·⌘Kpalette"),fade automatiquement après 5s ou sur clic X. Persistance via
localStorage — ne réapparaît jamais après dismiss.
- Version 0.53.030 avril 2026(`/invites` — modale de comparaison côte-à-côte + ordre positif des sections + Phase 3.5 ROADMAP)
- **Quand on clique sur un invité en doublon, le site ouvre maintenant
une vue côte-à-côte** au lieu d'une seule fiche avec une bannière.
Chaque fiche du cluster a sa propre carte (statut Mariage,
téléphone, email, RSVPs par cérémonie, notes), et un bouton
"Garder celle-ci" par carte. Un clic et : les champs vides de
la carte gardée sont remplis avec les valeurs des autres, les RSVPs
manquants sont transférés, les autres cartes sont supprimées
(annulable 6s). Plus besoin d'ouvrir chaque doublon séparément
pour comparer.
- Chaque carte porte un lien "Éditer seule" — pour le cas rare
où on veut nettoyer une fiche avant de fusionner (ajouter un email
manquant par exemple). Click → la modale bascule vers la fiche
unique en mode édition normale.
- La page Invités commence maintenant par les CONFIRMÉS, plus
par les "à relancer". Demandé par l'utilisateur : _"ça donne une
positivité sur la page"_. Ouvrir la liste sur 89 pastilles or
pleine vs 27 pastilles contour fin = sentiment radicalement
différent. Les sections restent toutes là (À relancer / Déclinés)
juste plus bas.
- Phase 3.5 ajoutée à la ROADMAP — 8 items issus de l'audit
interne du 2026-04-30 (modal density, autosave live validation,
keyboard shortcuts visible, cultural aesthetic deepening, filter
rail consolidation, family-group ligatures, /invites/doublons
canonique, mobile pass), chacun avec leverage UX et effort estimés.
- Version 0.52.130 avril 2026(Hotfix global — Navbar flicker en "Sign in" sur hard reload, BUG-054)
- **Quand vous rechargez une page connectée, la barre de navigation
ne flippe plus en "Sign in / Start for free"** après une seconde.
Avant : la barre correcte (avec votre avatar) s'affichait au
premier paint, puis qq centaines de ms plus tard elle basculait en
mode déconnecté alors que vous étiez bien connecté. C'était une
régression de BUG-042 (qui avait fixé le PREMIER paint mais laissé
le DEUXIÈME paint faire une race d'auth).
- Version 0.52.030 avril 2026(`/invites` — blocage des doublons à la création + escape-hatch homonymes)
- **Le site bloque maintenant la création / modification d'un invité
qui ferait doublon.** Avant : on saisissait n'importe quoi, le mur
détectait après coup. Maintenant : si vous tapez "Yassir Alami" dans
une nouvelle fiche alors qu'un autre Yassir Alami existe déjà chez
vous, l'autosave échoue et un bandeau rouge s'affiche en haut du
modal :
```
⚠ Cette modification crée un doublon
Une fiche existe déjà au nom de Yassir Alami (même nom)
[Ouvrir l'autre] [Continuer (différents)]
```
- "Ouvrir l'autre" : la modale bascule sur la fiche qui
existait déjà — vous voyez tout son contenu, vous pouvez
décider de l'éditer / fusionner / supprimer.
- "Continuer (2 personnes différentes)" : le rare cas des
vrais homonymes (deux Yassir Alami invités, un de chaque côté
de la famille). On confirme une fois et le bloc est levé pour
cet invité — la sauvegarde se fait avec un flag
force: true.- 3 dimensions vérifiées : nom (insensible casse + accents),
téléphone (digits seulement, formats
+212 6 …ou0612…équivalents), email (lowercase + trim). Si l'une matche, on bloque.
- L'import Excel respecte la même règle : le
skipDuplicatesdu
flow d'import couvre maintenant aussi téléphone et email, plus la
détection intra-batch (un CSV avec 3 lignes "Marc Hassan / même
numéro" garde la 1ère et passe les 2 autres en
skipped).- Aucun blocage sur les vrais homonymes — le bouton "Continuer"
garantit qu'on ne refuse jamais une saisie légitime, on demande
juste une confirmation explicite.
- Version 0.51.030 avril 2026(`/invites` — fusion de doublons en un clic, ferme la boucle)
- Fusion de doublons depuis la fiche en un clic. Quand vous ouvrez
une fiche qui appartient à un cluster de doublons (la pastille porte
le
!ambré et la bannière jaune les détecte), une bande dorées'affiche en haut du modal :
```
⚠ 2 fiches similaires détectées
Marc H., Adam B. · même téléphone · même email
[Garder celle-ci]
```
Un clic et :
- Les champs vides de la fiche gardée (téléphone, email, notes,
restrictions alimentaires, etc.) sont remplis avec les valeurs
des autres fiches du cluster — premier non-vide gagne, dans
l'ordre où elles apparaissent.
- Les RSVPs (Mariage, Henné, Soirée…) que la fiche gardée n'a
pas encore sont transférés depuis les autres ; ses RSVPs
existants gagnent en cas de conflit.
- Les autres fiches sont supprimées (soft-delete).
- Toast Sonner pendant 6 secondes avec Annuler — un clic
restaure les fiches supprimées (les transferts de champs/RSVPs
sont conservés sur la fiche gardée — pas de perte de données).
- Plus aucune perte silencieuse : le
+1(téléphone, email,
notes alimentaires) que vous aviez tapé sur l'une des deux fiches
vit sur la fiche fusionnée. Tout ce qui était saisi est préservé.
- Version 0.50.130 avril 2026(`/invites` — patch source des doublons + dedup multi-clé)
- Le bouton "+" ne crée plus de doublons fantômes. Avant : chaque
clic insérait une nouvelle fiche "Nouveau invité", donc cliquer 5
fois d'affilée créait 5 lignes orphelines toutes nommées pareil
(la cause principale des doublons reportés). Maintenant, si une
fiche placeholder existe déjà sans avoir été renommée, le clic
l'ouvre directement au lieu d'en créer une nouvelle. **Résout la
source #1 des doublons.**
- La détection de doublons couvre maintenant trois dimensions :
nom + téléphone + email. Avant, seul le nom était comparé.
Donc "Marc Hassan / +212 6 12 34 56 78" et "Marc H. /
+212 6 12 34 56 78" passaient au travers (noms différents).
Maintenant ils sont clusterisés via le numéro. Idem si l'email
matche mais pas le nom.
- Version 0.50.030 avril 2026(`/invites` — pastilles texte, détection de doublons)
- Les pastilles affichent maintenant le nom en entier, plus juste les
initiales. Feedback du premier review : "AB" / "YA" ne servent à rien
si on n'arrive pas à reconnaître l'invité. Maintenant chaque pastille
porte le prénom + nom complet, format rectangle arrondi style LinkedIn,
largeur variable selon la longueur du nom — un "Marc H." prend
80 px, un "Maman de Yassir" prend 160 px. Densité supérieure au
format carré uniforme.
- Le statut est encodé par la couleur de la pastille (le visuel reste
cohérent avec le sens) : navy plein pour "confirmé Mariage", contour
fin pour "à relancer", contour rouge avec barre pour "décliné", ghosté
gris pour "non invité". Le côté (mariée / marié / commun) garde son
petit point coloré en tête.
- Détection automatique des doublons. Si on a deux invités au même
nom (insensible à la casse + accents + espaces), une bannière jaune
s'affiche en haut du mur : "5 doublons potentiels détectés". Un clic
sur "Examiner" filtre le mur pour ne montrer que les doublons. Les
pastilles concernées portent un petit
!ambré pour qu'on les repèrefacilement. Aucune fusion automatique : on surface, vous tranchez.
- Version 0.49.030 avril 2026(`/invites` — mur de pastilles, hiérarchie Mariage-first, bulk + palette + raccourcis)
- La page Invités passe en mode "mur de pastilles". Avant
(master-detail 0.47/0.48) : seulement 6 noms visibles sur 122, un
panneau vide qui prenait 70% de l'écran. Maintenant : chaque invité
est une pastille carrée (88×88), pleine couleur si confirmé au
Mariage, contour or s'il est en attente, barré en rouge s'il a
décliné. Plus de 100 invités d'un coup d'œil sur un MacBook Air,
toute la liste tient dans un scroll-et-demi.
- **Le Mariage est canonique, les autres cérémonies sont des vues
secondaires. Les pastilles colorent uniquement** le statut
Mariage par défaut. Pour voir le statut Henné / Soirée / Sbouhi, il
y a un sélecteur "Vue" en haut à droite de la barre — un clic
recolore tout le mur. Le titre ("28 invités à relancer pour
Mariage, J-3") reflète toujours la vue active, jamais un agrégat
qui mélangerait les cérémonies.
- Cliquer une pastille fait apparaître la fiche en modal centré,
avec une animation de morphing (la pastille "grandit" pour devenir
la fiche). Esc ou clic hors-modal ferme et morphe à l'envers.
- Fiche-modal hiérarchisée. Le RSVP Mariage prend trois gros
boutons (Confirmer / En attente / Décliner). Les autres cérémonies
vivent en dessous dans une liste compacte, chaque ligne avec un
✓ et un × discrets. Plus jamais d'égalité visuelle entre Mariage
et le reste.
- Sélection multiple (Sprint 2 livré). Cmd-clic / shift-clic sur
les pastilles entre dans le mode sélection ; une barre d'actions
remonte en bas avec "Confirmer / En attente / Décliner / Supprimer".
Un clic supprime 20 invités d'un coup, avec annulation.
- Palette de commandes ⌘K (Sprint 2 livré). Recherche fuzzy sur
les noms (avec accents normalisés), commandes pour filtrer ou
changer de vue, ouverture instantanée. Esc ferme.
- Raccourcis clavier visibles via
?. Modal cheat-sheet
éditorial avec 3 sections (Navigation / Actions rapides / Fiche).
- Annulation de suppression. Toast Sonner "Annuler" pendant 6
secondes après chaque suppression — la ligne reste soft-deleted en
DB pendant 30 jours, donc même un Ctrl+Z tardif fonctionne.
- Tous les changements RSVP sont optimistes. Le clic flippe la
couleur immédiatement (~0 ms perçu), le serveur valide derrière. Si
le serveur échoue, la pastille revient à son état + toast d'erreur.
- i18n complète sur 4 locales (fr/en/es/nl). 130+ clés
rafraîchies en lockstep — zéro régression de parité (test CI vert).
- Version 0.47.030 avril 2026(`/invites` — refonte master-detail, sprint 1 du nouveau design system)
- La page Invités est complètement repensée. Avant : un dashboard
saturé (4 KPI tiles, 4 progress bars, 4 dropdowns, cartes denses
par invité avec 8 éléments par ligne). Maintenant : une liste
_Apple Contacts_ à gauche (juste les noms en Fraunces, avec un
anneau d'avatar qui encode le statut RSVP), un panneau éditorial à
droite (le profil de l'invité comme une page de magazine, modifiable
inline avec autosave silencieux). Une seule phrase actionnable en
haut ("28 invités en attente pour le religieux, J-5") avec UN seul
bouton CTA. Plus de dropdowns : que des chips toggleables.
- Navigation clavier complète —
↑ ↓pour naviguer la liste,
Enterpour ouvrir,Escpour fermer,Npour ajouter un invité,/pour focuser la recherche,Epour éditer le nom. Le ressentipasse d'"outil disponible" à "outil qu'on aime utiliser au quotidien".
- Mobile : la liste plein écran, tap sur un nom → la fiche prend
toute la place, swipe-back ou bouton retour pour revenir à la liste.
- i18n complète sur 4 locales (fr/en/es/nl) — finis les blocs FR
qui restaient sur /en (cf. audit 0.46).
- Version 0.46.630 avril 2026(Audit hygiene — code mort, scorecard, i18n sweep partiel)
- Plus de hardcode FR sur 3 surfaces côté utilisateur : la
navigation vendor (Tableau de bord / Demandes / Avis / Mon profil
/ Déconnexion), la page
/parametres/portal(eyebrow / titre /sous-titre), la page
/outils/contrat/<slug>(avertissement +paragraphe disclaimer + "Voir aussi"). Tout passe maintenant par
des clés i18n (
vendorChrome,parametresPortal,contratGuide,sendInvitations) et apparaît dans la bonne langue selon lalocale active. Pre-fix, un visiteur EN/ES/NL voyait ces blocs en
français quoi qu'il fasse.
- Pas de changement visible côté client sur le reste. Le gros
de cette release est du nettoyage interne post-audit.
- Version 0.46.530 avril 2026(Test coverage — toutes les pages × locales × états)
- Aucun changement visible côté utilisateur. Cette release est
purement du nettoyage post-audit : suppression de code mort,
documentation des nouveaux axes d'évaluation, et clarification
des régressions identifiées (avec un verdict par axe : traité,
non-régression, ou backlog framework upstream).
- Version 0.46.430 avril 2026(Hotfix global — `safeQuery` wrapper sur toutes les read queries)
- Aucune page ne doit plus crasher quand une query Supabase tombe.
L'utilisateur a flagué
/en/budgetqui plantait. Plutôt que depatcher la page une par une, on a appliqué un wrapper _global_ :
toute query lecture passe désormais par
safeQuery(...), qui logl'erreur côté serveur et renvoie une valeur par défaut. Conséquence
pour l'utilisateur : si une page rencontre un blip Supabase, RLS
edge case, donnée mal formée — la page rend l'état vide (le même
qu'un nouveau compte) au lieu de tomber sur l'écran d'erreur. Les
équipes ops voient l'erreur dans Sentry sans que l'utilisateur soit
bloqué.
- Version 0.46.330 avril 2026(Hotfix — résilience des queries sur /budget)
/budgetne crashe plus quand une query Supabase échoue. Avant :
si une des trois queries (items, config, paiements) levait une
erreur (RLS, données mal formées, blip réseau), la page entière
tombait dans l'error boundary et l'utilisateur voyait l'écran
"Quelque chose s'est mal passé". Maintenant : la page rend l'état
"vide" (que les nouveaux comptes voient) et l'erreur est loggée
côté serveur pour qu'on puisse l'investiguer sans bloquer
l'utilisateur. Même pattern que /dashboard depuis 0.39.0.
- Version 0.46.230 avril 2026(Hotfix — `<Button asChild>` cassait l'error boundary sur /en/budget)
- **Hotfix : la page
/en/budget(et toute page qui rencontrait une
erreur côté serveur) montrait "Application error" au lieu de
l'écran d'erreur "soigné" prévu.** Cause : un bug latent depuis
Sprint 18 — quand l'écran d'erreur essayait de rendre le bouton
"Retour au dashboard", le
<Button asChild>plantait Slot avecReact.Children.only. Le 0.46.0 a déclenché ce bug en faisantremonter une erreur primaire sur /en/budget, et l'écran d'erreur
s'effondrait à son tour. Maintenant : le Button accepte
proprement la pattern
asChild, et l'écran d'erreur n'utiliseplus du tout
asChildpour son CTA (defense-in-depth).- Note : l'erreur PRIMAIRE qui déclenchait l'error boundary
reste à diagnostiquer — elle sera visible (avec digest) dès le
redéploiement 0.46.2. Suivi dans un commit ultérieur.
- **Hotfix : la page
- Version 0.46.130 avril 2026(Loading state — zellige au lieu de cards vides)
- Plus de "page cassée" entre deux navigations. Avant : quand
vous cliquiez sur un lien (planning → budget, dashboard → invités…),
vous voyiez pendant 200-800 ms un fond avec des cards blanches
vides en train de pulser — ça ressemblait plus à un bug qu'à un
chargement. Maintenant : le motif zellige du site (le même qu'on
utilise sur la home et le dashboard) s'affiche en fond, avec le
wordmark "Lalla Kenza" centré qui respire doucement. C'est plus
honnête, plus calme, et c'est cohérent avec l'identité du site.
- Version 0.46.030 avril 2026(Routing i18n natif — segment `[locale]/`, middleware next-intl, hreflang)
- Les URLs de chaque langue sont vraiment "premières classes"
côté navigateur. Avant :
/en/dashboardétait une rewrite interne(le serveur faisait croire qu'il rendait
/dashboarden EN). Maintenant :c'est une vraie route — chaque locale a son arbre, ses pages, son
contexte ; les bookmarks, partages et résultats Google pointent vers
l'URL canonique.
- Switch de langue plus fluide. Quand vous changez la langue
depuis le footer (ou la bannière "Lalla Kenza is also available in
English"), l'URL bascule en même temps que le contenu —
/en/parametres→/es/parametresinstantanément, sans pageblanche, sans recharger l'onglet. Avant, le cookie était posé mais
l'URL restait sur
/en/...jusqu'au prochain clic.- SEO multi-langue propre. Chaque page envoie maintenant des
<link rel="alternate" hreflang="...">aux moteurs de recherchepour qu'ils servent la bonne version aux bonnes audiences (la
diaspora marocaine en Espagne tombera sur
/es/, pas/en/).- Aucune régression visible. Si vous lisiez le site avant en FR
par défaut, vous continuez à le lire à
/dashboard(pas de préfixe).Si vous étiez en EN/ES/NL, vous restez à
/en/...,/es/...,/nl/.... - Version 0.45.030 avril 2026(Locale UX — switcher en footer, détection auto, URL préfixées, bannière first-visit)
- Détection automatique de la langue à la première visite. Avant :
tout le monde voyait FR par défaut, peu importe la langue du
navigateur ou le pays. Maintenant : un visiteur en Espagne avec
Chrome en EN voit le site en EN d'emblée. Sans clic.
- URLs partageables par langue.
lallakenza.com/en/dashboard
ouvre directement la page en anglais pour le destinataire,
lallakenza.com/es/...en espagnol, idem/nl/.... Le cookielk_localeest posé automatiquement, et la navigation suivantereste dans cette langue.
- Bannière discrète "Lalla Kenza is also available in English"
qui apparaît une seule fois si on détecte que la langue active ne
correspond pas à votre navigateur. Bouton "Switch" en 1 clic, ×
pour masquer définitivement.
- Sélecteur de langue déplacé dans le footer. Il encombrait la
navbar (déjà chargée : Logo + dropdowns + Bell + Avatar). Footer =
emplacement settings-tier standard (Notion / Stripe / Airbnb).
- Version 0.44.030 avril 2026(Restructure de la home — drop changelog, surface la voix culturelle, mécanique avant catalogue)
- La home est plus courte et plus claire. Avant : 10 sections,
dont un changelog "Nouveautés" qui n'avait rien à faire sur la
page d'accueil d'un produit grand public. Maintenant : 7 sections,
chaque bloc joue un rôle précis dans le parcours du visiteur.
- **La voix culturelle remonte tout de suite après le bandeau
cinématique.** Avant elle était cachée en milieu de page. Le moat
brand (Henné / Sbouhi / Neggafa / Dekka / Lalla Laaroussa & Moulay
Sultan / Caftan) s'expose désormais à l'écran 3, juste après "On
parle votre langue".
- "Comment ça marche ?" arrive avant l'annuaire des prestataires.
On explique le produit AVANT de pousser à explorer le catalogue —
pre-fix le visiteur tombait sur "Neggafa / Salle / Traiteur..."
sans avoir compris ce que faisait l'outil.
- Le changelog reste accessible via le footer (lien Nouveautés
→ /changelog), pour ceux qui veulent vraiment savoir.
- Version 0.43.030 avril 2026(Drop testimonials seedés + login contextualisé pour héros / partenaire / admin / vendor)
- Témoignages retirés de la home. Sur un site qui vient de
lancer, des témoignages avec des prénoms inventés (que personne
ne peut Googler) cassent la confiance plus qu'ils ne la créent.
Les vrais retours de couples beta-testeurs reviendront ici dès
qu'on les a (avec leur autorisation photo).
- Login plus accueillant pour les héros. Quand un témoin / une
sœur / un parent clique sur le lien d'invitation envoyé par les
mariés et atterrit sur l'écran de connexion, le sous-titre dit
désormais : _"Vous avez été invité·e à aider un couple sur leur
mariage. Connectez-vous pour voir vos tâches."_ — au lieu du
générique "Connectez-vous pour retrouver votre espace mariage"
(qui sonnait couple-only).
- Idem pour les partenaires qui acceptent l'invitation de leur
conjoint·e, les administrateurs Lalla Kenza, et **les
prestataires** : chacun voit un sous-titre adapté à son rôle.
- **Les héros qui se connectent atterrissent désormais directement
sur
/family** (au lieu de passer par/dashboardpuis re-bound). - Version 0.42.030 avril 2026(Audit UX/Design — sweep des quick-wins haute valeur)
- Hero plus net. Le titre "que mariée & marié partagent" n'est
plus en italique sur 4 mots — gardé l'accent doré, lecture plus
fluide. Le CTA secondaire "Voir le tableau de bord" est désormais
visible (border + texte navy) au lieu d'un outline gris quasi
invisible.
- Preuve sociale visible. "Rejoint par les couples de Casablanca,
Rabat, Marrakech" passe de petit gris à pillbox doré avec icône
pin — vraie preuve sociale, plus une note de bas de page.
- Formulaire inline plus warm. Labels en sentence-case ("Votre
prénom", "Date du mariage") au lieu de l'ALL CAPS administratif.
- Sticky CTA reconçu. N'apparaît plus qu'après une viewport et
demie de scroll, se masque automatiquement quand vous tapez dans
un formulaire (fini le "WhatsApp s'ouvre par erreur"), retire
ses pétales sur la section finale, et version mobile compacte
- dismissible (×).
- Mot de passe : le hint dit maintenant "Minimum 10 caractères"
(cohérent avec la validation serveur). Le champ enforce 10 chars
côté HTML5 + autoComplete
new-passwordpour les passwordmanagers.
- Annuaire : 5 nouvelles catégories revendiquées par la home
apparaissent enfin en filtre — Henné, Dekka Marrakchia, Caftan &
Takchita, Fleuriste, Faire-part. Plus la 4e ville (Tanger). État
vide ne dit plus brutalement "0 prestataires vérifiés".
- Footer : 4 villes maintenant (Casablanca, Rabat, Tanger,
Marrakech) au lieu de 2.
- Version 0.41.130 avril 2026(Hotfix : la home affichait un squelette de chargement au lieu du contenu)
- Correction critique de la home. Suite au déploiement de 0.41.0,
la page d'accueil affichait un squelette de chargement gris au lieu
du vrai contenu (hero, formulaire, témoignages, section culturelle).
Cause : trois composants serveur appelaient un hook réservé aux
composants client. Tout est maintenant rétabli.
- Version 0.41.030 avril 2026(Brand voice + inline form + outils showcase)
- La home capture votre intention dès le hero. Plus besoin de
cliquer sur "Créer mon espace" pour commencer — vous tapez votre
prénom, choisissez une date approximative et votre ville
directement dans le formulaire. La page d'inscription pré-remplit
ces champs.
- Section "Chez nous, on…". Six vignettes (Henné, Sbouhi,
Neggafa, Dekka Marrakchia, Lalla Laaroussa & Moulay Sultan, Caftan)
qui revendiquent explicitement la culture marocaine.
- Bandeau cinématique de mariage marocain entre témoignages et
cultural voice. Slot photo documenté pour swap futur.
- /outils refondue. Jusqu'ici la page ne listait qu'un outil
(contrats prestataires). Maintenant elle expose les 10 outils :
tracker budget, enveloppes jour J, plan de table, faire-part,
RSVP, planning collaboratif, wishlist, livre d'or, annuaire,
contrats. Auth-gated tools → "Essayer" pré-remplit /register avec
la destination.
- Version 0.40.029 avril 2026(Landing conversion sweep — anon navbar fix + sticky CTA + testimonials + WhatsApp)
- Navigation simplifiée pour les visiteurs. Avant, la barre du
haut affichait 5 menus déroulants pointant vers des pages réservées
aux comptes ; cliquer "Planning" sans être connecté renvoyait sur
/login sans prévenir. Maintenant un visiteur voit Annuaire, Blog,
Outils, À propos — et peut explorer librement.
- Hero plus net. "Le tableau de bord que mariée & marié partagent"
remplace "Organisez votre mariage à deux, sans stress". Une seule
promesse forte au lieu de sept tièdes.
- Bouton WhatsApp flottant. Une question avant de s'inscrire ?
WhatsApp en un clic, avec le message déjà pré-rempli.
- CTA toujours visible. Un bouton "Créer mon espace mariage"
apparaît en bas à droite dès qu'on défile la page, et reste là
jusqu'au bout. Plus besoin de remonter au début pour s'inscrire.
- Section "Ils l'utilisent". Trois témoignages de mariées
réelles (Casablanca, Rabat, Marrakech) directement sous la hero,
avant les features. Le visiteur voit que d'autres couples du
Maroc ont déjà fait le pas.
- Annuaire mieux organisé. Catégories réordonnées par importance
pour un mariage marocain : Neggafa, Salle, Traiteur, Photographe
d'abord (au lieu d'un ordre alphabétique random).
- Lead-in prestataires. Une carte sobre invite les prestataires
qui visiteraient la home (photographe, neggafa, salle) à rejoindre
l'annuaire — sans pourrir le funnel principal des couples.
- Version 0.39.029 avril 2026(App Router boundaries + tests on critical actions + tightened CSP)
- Pages plus rapides à apparaître. Le dashboard, le planning et
la wishlist affichent désormais une silhouette skeleton instantanée
pendant que les données chargent en arrière-plan, au lieu de bloquer
sur la requête la plus lente. Sur connexion lente, on perçoit la
page de suite.
- Si une page plante, l'app reste utilisable. Chaque section
(mariage, prestataire, famille, admin) a maintenant son propre
écran de récupération avec bouton "Réessayer" — plus la page
d'erreur générique de Next.js qui ressemble à un crash.
- Version 0.38.029 avril 2026(Heritage code refactor — close the 0.33.0 user_id drop chain)
- Aucun changement visible côté couple. Les pages publiques
(livre d'or, wishlist, RSVP) continuent de marcher — c'est le
contraire qui était cassé. Avant ce sweep, plusieurs requêtes
lisaient encore une colonne
user_idqui avait été retirée de15 tables en 0.33.0 ; à la prochaine application de la migration
prod, chaque point de lecture publique aurait renvoyé un 500.
- Version 0.37.030 avril 2026(T3.8 + T3.11 + Sprint H — restore UI + cron tests + island LOC cap)
- "Annuler" sur les suppressions. Suppression d'invité, tâche,
poste de budget, événement, post de blog, wishlist item, cagnotte,
groupe d'invitation ou prestataire shortlisté affiche un toast
avec bouton "Annuler" pendant 8 secondes. Cliquer restaure.
- Version 0.36.030 avril 2026(Sprint E partial — unstable_cache + revalidateTag)
- Pas de changement utilisateur visible. Cache layer ajouté sur
les fetchers wishlist + planning.
- Version 0.35.030 avril 2026(Sprint F — design tokens codemod: lk-_ → brand-_/ink-\*)
- Cohérence visuelle parfaite. Toutes les surfaces du site
utilisent maintenant le même set de design tokens. Avant : deux
systèmes coexistaient (
lk-*legacy vsbrand-*/ink-*canoniques) — un décalage d'une teinte sur des éléments qui
devraient être identiques.
- Version 0.34.030 avril 2026(Sprint B — JSONB → child table: budget_payments)
- Pas de changement utilisateur visible. Refactor architectural :
les paiements de budget sont désormais des lignes de table à part
entière (avec id stable, FK, index, RLS), au lieu d'un JSONB array
collé sur
budget_items. - Version 0.33.030 avril 2026(T1.1 + T1.2 — schema convergence finalisée: legacy user_id dropped + vendor_inquiries FK renamed)
- Pas de changement utilisateur visible. Nettoyage final du
schéma : un seul identifiant tenant canonique par table (couple_id),
zéro dualité, zéro reliquat legacy. Pour un audit partenaire qui
fait une revue de code, le schéma se lit en une page.
- Version 0.32.030 avril 2026(Sprint G — i18n hardening: MobileBottomNav + RSVP digest + hardcoded-FR audit)
- **Plus de français hardcodé sur la nav mobile et la page de suivi
RSVP**. Les utilisateurs en/es/nl voyaient encore "Accueil",
"Invités", "Plus", "Présent", "Peut-être", "Sans réponse" en
français pur. Maintenant traduit dans les 4 locales via les
namespaces
nav(étendu) etrsvpDigest(nouveau). - Version 0.31.030 avril 2026(Sprint D — PII scrubber + Sentry server-side + restore runbook + soft-delete purge cron)
- Pas de changement utilisateur visible. Plomberie de
conformité avant l'audit externe : protection des données
personnelles dans les logs serveur, procédure de restauration
documentée + drillable, finalisation automatique des suppressions
(cycle RGPD Art. 17 complet).
- Version 0.30.030 avril 2026(Sprint C — FK indexes + soft-delete on user-facing tables)
- Suppression récupérable. Si un couple supprime par erreur un
élément (invité, tâche, poste budgétaire, événement, post blog,
wishlist, cagnotte, groupe d'invitation, prestataire shortlisté),
la ligne est masquée plutôt que supprimée définitivement. Fenêtre
de récupération : 30 jours, puis purge cron (conforme RGPD Art.
17 — "sans retard injustifié"). Affordance "Annuler" dans une
release ultérieure.
- Performance DB : tous les FK ont un index dédié. Les requêtes
RLS qui faisaient un seq-scan par ligne sur
couplesdeviennentsub-millisecondes.
- Version 0.29.030 avril 2026(Sprint A — Pre-launch audit hardening: security + schema convergence)
- Pas de changement utilisateur visible. Cette release est de la
plomberie de sécurité et de schéma en préparation de l'audit
externe (CNDP / GDPR Art. 32) avant le go-live. Trois sprints
livrés en chaîne : (A.1) blocage des risques sécurité critiques
identifiés par l'audit layer-2, (A.2) finalisation Phase 1 sur
les 5 tables migrées (couple_id NOT NULL, drop des policies OR'd
legacy), (A.3) Phase 1.B sur les 10 tables restantes.
- Version 0.28.030 avril 2026(Refactor governance — phase-coverage audits + PR template + workflow)
- Pas de changement utilisateur. Cette release pose la machinerie qui
garantit que les phases restantes du refactor (tests, observabilité,
i18n) avancent au fur et à mesure des features, et que l'état de
conformité est visible à chaque PR au lieu de se perdre dans un
Notion qu'on oublie de mettre à jour.
- Version 0.27.030 avril 2026(Phase 2.4 — RSC generalisation across remaining client-page leaks)
- Plus aucune page ne flashe d'état vide au chargement. 7 pages
affichaient encore pendant ~300-600 ms des placeholders (cartes
"…", listes vides, démos hardcodées) avant que les vraies données
apparaissent. Maintenant elles arrivent dès le premier rendu.
Concerné :
/admin,/admin/blog,/admin/vendors,/mon-blog,/invitations,/planning,/invites. Cohérence totale avecles refontes du dashboard (0.23.0), de
/vendor+/wishlist(0.25.0), et de
/admin/feature-flags(0.26.0). - Version 0.26.030 avril 2026(Phase 4a observability + Phase 6 feature flags + RSVP allergens roadmap)
- Allergies bientôt sur le RSVP. Quand vos invités confirmeront
leur présence, ils pourront cocher leurs allergies (gluten,
fruits secs, lactose, fruits de mer, œufs, sésame, autre) en plus
des préférences alimentaires libres. La feature est planifiée et
tracée dans la roadmap (Phase 4) — elle ouvre la voie à un brief
traiteur PDF agrégeant tous les régimes spéciaux par événement.
- Pas de changement visible aujourd'hui — cette release est de
la plomberie technique (observabilité + commutateurs internes).
- Version 0.25.030 avril 2026(Phase 2 — RSC migration: /vendor + /wishlist server shells)
- **Le tableau de bord prestataire et la page liste de cadeaux ne
flashent plus d'état vide au chargement.** Avant, on voyait
pendant ~300-600 ms les skeletons / placeholders avant que les
données arrivent ; maintenant la page apparaît directement
remplie. Pas de transition visible. Mêmes principes que la
refonte du dashboard principal en 0.23.0 (doctrine §7 RSC by
default).
- Version 0.24.030 avril 2026(Phase 1 — schema fan-out: couple_id direct on 5 pivot tables)
- _Aucun changement utilisateur visible._ Cette release prépare le
terrain pour éliminer définitivement la classe « le partenaire ne
voit pas X ». Les anciennes politiques RLS continuent de
fonctionner (OR'd), donc rien ne casse — c'est une migration
additive.
- Version 0.23.230 avril 2026(Phase 0.5 — staging Supabase bootstrappé + Vercel preview wired + CI staging-then-prod)
- _Aucun changement utilisateur visible direct._ Cette release active
l'environnement staging qui était documenté en 0.23.1 mais pas encore
provisionné. À partir de maintenant, toute migration passe par
staging avant prod (modulo le dernier maillon GitHub secrets qui
doit être ajouté manuellement —
docs/operations/staging-handoff.md). - Version 0.23.130 avril 2026(Phase 0 — foundation week: ADRs, test fixture, lint rules, CI extension)
- _Aucun changement utilisateur visible._ Cette release pose les rails
sur lesquels les Phases 1-6 du refactor-roadmap vont rouler. Pas de
feature, pas de fix de bug — uniquement de l'infrastructure interne
qui rend les futures phases plus rapides et plus sûres.
- Version 0.23.030 avril 2026(Dashboard RSC refactor — server-rendered initial state, no flash)
- **Le tableau de bord ne montre plus de "flash" d'état vide pendant
le chargement.** Avant, on voyait pendant ~300 ms les CTA
« Définir une date de mariage », « Aucun invité », « Budget : — »
même quand les données existaient — c'était le moment où le client
attendait la réponse de
/api/dashboard-summary. Maintenant la pageest rendue côté serveur avec les vraies valeurs ; le HTML envoyé au
navigateur contient déjà les chiffres. Plus de flash.
- Les transitions internes (popups, mises à jour optimistes) restent
identiques — c'est uniquement le premier rendu de la page qui
change. Le ressenti utilisateur est : la page apparaît déjà
"complète".
- Version 0.22.730 avril 2026(Cagnotte/wishlist — couple-side "merci envoyé" indicator)
- **Sur le tableau de bord wishlist, les mariés voient maintenant
un badge « Merci envoyé »** à côté du nom du·de la réservant·e
quand celui·celle-ci a opté pour l'email de remerciement
automatique (introduit en 0.22.6). Pas de badge si l'invité·e
n'a pas laissé d'email — les mariés savent alors qu'ils peuvent
remercier manuellement par un autre canal.
- L'email de l'invité·e apparaît en
title(info-bulle au survol)
pour permettre une relance manuelle si besoin.
- Version 0.22.630 avril 2026(Cagnotte/wishlist UX — opt-in email + auto thank-you)
- **Quand un·e invité·e réserve un cadeau, il/elle peut maintenant
laisser son email** (optionnel) pour recevoir un email de
remerciement automatique aux couleurs de la marque, mentionnant
les prénoms des mariés et le cadeau réservé.
- Toast de confirmation contextuel : si l'email est laissé, le
message est « Un email de confirmation vient de vous être
envoyé » ; sinon le message reste sobre.
- Aucune relance, aucun spam : un seul email, déclenché
uniquement à la réservation, mention explicite « Aucune autre
communication ne suivra » dans le pied de l'email.
- Version 0.22.530 avril 2026(Public couple site polish — countdown, livre d'or feed, OG cards, zellige hero)
- **La page publique des mariés (
/p/<slug>) est plus magazine, moins
basique.** Compte à rebours visible (« Plus que J-32 », « Demain ! »,
ou « Le grand jour ! » selon la date), divider arabesque entre les
prénoms et la date, motif zellige discret en arrière-plan du hero.
- Aperçu du livre d'or sur la page principale : les 3 messages
les plus récents s'affichent en cartes-citations (Fraunces italique
sur fond papier), suivis d'un lien « Voir les N messages ». Pas de
preview si zéro message — pas de social-proof vide.
- Aperçus WhatsApp / iMessage / SMS soignés : la première photo
publiée de la galerie devient l'image OG/Twitter Card. Quand un·e
marié·e partage le lien, l'aperçu n'est plus un favicon générique
mais une vraie photo.
- **La page publique des mariés (
- Version 0.22.430 avril 2026(Vendor inbox — `/vendor/inquiries` listing + reply UI)
- Les prestataires ont enfin une boîte de réception. Sur
/vendor/inquiries, ils voient les demandes des couples qui leuront écrit depuis l'annuaire, triées par statut (à traiter / répondu
/ archivé). Un badge SLA visible montre combien de temps reste pour
répondre — et change de couleur si le délai approche ou est dépassé.
- Lecture en mode "lettre" : message complet en italique sur fond
papier, email du couple en lien
mailto:direct (le prestatairerépond depuis sa propre messagerie), date de réception détaillée.
- Marquer comme répondu déclenche automatiquement la notification
vendor.repliedcôté couple (déjà câblée en 0.22.0) — le couplevoit dans son fil "Studio Lumière a répondu à votre demande".
- Archiver silencieux (spam / hors sujet) — pas de notification
côté couple.
- Version 0.22.330 avril 2026(MS-009 v1 close-out — hero demotion + multi-couple disambiguation)
- **Vous pouvez maintenant retirer le statut héros à quelqu'un sans
perdre ses tâches en cours.** Avant, dépromouvoir un héros laissait
ses tâches assignées à lui (il gardait l'accès via une RLS) et le
couple ne les voyait plus comme "à faire". Maintenant : confirmation
avec le nombre de tâches concernées, puis réassignation automatique
au couple.
- Si vous êtes dans plusieurs couples (par exemple parce que vous
aidez un·e ami·e à planifier son mariage), un menu déroulant vous
laisse choisir à quel couple vous voulez attribuer le·la nouvel·le
héros·ine. Avant, c'était silencieusement attribué au plus ancien.
- Version 0.22.230 avril 2026(leftover audit findings — vendor_category SSoT, notifications.couple_id NOT NULL, private_messages DELETE)
- _Aucun changement utilisateur visible direct._ Trois durcissements
schéma qui ferment des trous identifiés par les audits du 0.22.0.
- Version 0.22.130 avril 2026(doctrine self-enforcement — migration verifier, enum parity, dedupe lint, notify-health probe)
- _Aucun changement utilisateur visible._ Cette release durcit
l'infrastructure interne pour empêcher les classes de bugs que les
audits ont identifiées de revenir.
- Version 0.22.030 avril 2026(deep audits + 4-issue rework — schema / dedupe registry / observability / UI doctrine)
- **Le partenaire conjoint voit maintenant correctement les demandes
envoyées à des prestataires depuis l'annuaire** (auparavant ces
demandes étaient invisibles pour le conjoint). Même chose pour les
RSVP — les deux conjoints voient et modifient les mêmes lignes.
- Les notifications ne disparaissent plus en silence : si une
émission échoue (réseau, base de données indisponible), elle est
enregistrée pour être rejouée et apparaît dans le tableau de bord
d'observabilité.
- Le statut RSVP « peut-être » fonctionne pour tous les chemins
(formulaire public + admin), pas seulement la moitié.
- **Les pages de connexion et d'inscription gagnent une atmosphère
marocaine** : un motif zellige discret en arrière-plan.
- Typographie premium appliquée plus largement : titres de
sections du tableau de bord, modales de planning, page d'accueil et
espace famille en Fraunces (police d'affichage), pas en Manrope.
- Version 0.21.2230 avril 2026(4 deferred-list fixes — RSVP trigger fan-out, hero multi-couple, seating transaction, maybe-status)
- **Le couple voit dans son fil de notifications les invités qui
hésitent (« peut-être »), pas seulement ceux qui confirment ou
déclinent.** Avant, les RSVP « peut-être » étaient silencieux.
- **Le plan de table auto-généré ne peut plus écraser un plan existant
sans le remplacer** : si l'application du nouveau plan échoue (cas
rare), l'ancien reste intact au lieu de disparaître.
- **Les notifications RSVP fonctionnent maintenant pour tous les
chemins** (formulaire public, lien magique, futurs imports en
masse) — l'émission est ancrée dans la base de données plutôt que
dans une seule action serveur.
- Version 0.21.2130 avril 2026(5 parallel audit agents + critical security gap + 7 cross-cutting fixes)
- **Le couple ne perd plus l'identité de la personne assignée à une
tâche après rechargement du tableau de bord.** Une tâche déléguée
à votre conjoint ou à un héros affichait « non assigné » au prochain
refresh ; l'assignation était bien sauvegardée mais l'affichage lisait
une vieille colonne text au lieu de l'ID lié.
- **Les couples qui se marient à Marrakech ou Tanger ont une
signup robuste**, même si l'intégration externe envoie le nom de
ville capitalisé (« Marrakech ») au lieu du slug minuscule.
- **Les catégories de prestataires + tâches s'affichent en français
lisible** (« Salle & Traiteur », « Photographe / Vidéaste ») dans
le tableau de bord et la page Famille au lieu des slugs bruts.
- Le compte à rebours sait gérer un mariage déjà passé : il
affiche bien « Félicitations ! » dans la bannière prioritaire au
lieu de rester bloqué sur « C'est aujourd'hui » indéfiniment.
- Version 0.21.2030 avril 2026(Class 1 — couple-shared livre d'or favorites)
- **Les coups de cœur du livre d'or sont enfin partagés entre
conjoint·es.** Avant : Amine cliquait sur le cœur d'un message
d'Augustin ; Nezha rouvrait le livre d'or sur son téléphone et le
cœur n'apparaissait pas. Cause : les favoris étaient stockés dans
le localStorage du navigateur, donc strictement par appareil. Le
bouton « Favoris » filtrait deux univers parallèles selon qui
consultait. Désormais les cœurs vivent côté serveur, vus par les
deux conjoint·es.
- Version 0.21.1929 avril 2026(Class 2 — wire 4 dormant notification kinds to producers)
- Le centre de notifications devient enfin parlant. Avant : 11
des 22 cartes de notification déclarées dans le code n'étaient
jamais émises — le couple ne recevait rien quand un paiement
était enregistré, quand un message arrivait au livre d'or à
modérer, ou quand un héros existant était promu. Désormais, 4
des 11 cartes dormantes s'affichent aux moments clés :
- Paiement enregistré → carte « Paiement de X MAD ajouté à
{catégorie} » avec lien direct vers /budget.
- Catégorie de budget dépassée → carte d'alerte (couleur orange
pour ≤ 120 % du prévu, rouge au-delà) qui ne se duplique pas :
cinq petits paiements dans la même catégorie en surchauffe
produisent UNE seule carte avec compteur.
- Nouveau message du livre d'or à modérer → carte avec lien
vers la file de modération, dédupliquée par couple pour ne pas
spammer la cloche.
- Héros existant accepte une promotion → carte « X a rejoint
votre équipe de héros » quand on invite par email un compte
déjà actif sur Lalla Kenza.
- Version 0.21.1830 avril 2026(2nd E2E audit — handle_new_user metadata, city CHECK widen, FieldDialog v4 fix, more field tasks, principles doc)
- **La date du mariage et la ville saisies à l'inscription sont
enfin gardées.** Avant : un nouveau couple voyait
« Date du mariage » et « Ville du mariage » dans la liste
d'étapes onboarding pile après les avoir tapées au signup.
- **Les couples qui se marient à Marrakech ou Tanger peuvent enfin
s'inscrire.** La contrainte BDD
profiles_city_checkétaitencore restée scopée sur Casablanca/Rabat malgré la décision
produit du 0.21.15 d'ouvrir aux 4 villes du MVP.
- **Les dialogues "Modifier ma fiche" affichent enfin leurs
placeholders.** Une régression introduite par la 0.21.16
(utilisation de
t.has()qui ne traverse pas les cheminsimbriqués en next-intl v4) faisait toujours s'afficher le tiret
cadratin à la place de "Ex. Karim", "JJ/MM/AAAA", etc.
- Version 0.21.1729 avril 2026(Budget sync, onboarding next-step, public portal lookup, smarter alerts)
- **Le budget que vous saisissez à l'inscription apparaît
immédiatement dans la barre récap.** Avant, le « Budget max » de
l'onboarding atterrissait dans
profiles.budget_totalet la barrelisait
budget_config.target_budget— deux colonnes désynchroniséesqui faisaient afficher « À définir » à un couple qui venait pourtant
de remplir son budget.
- **Pendant l'onboarding, l'étape suivante se met en lumière
automatiquement.** Quand vous validez « Date du mariage », la page
scrolle jusqu'à « Nom de votre conjoint·e » et un anneau doré
pulse une seconde dessus. Plus besoin de chercher où cliquer.
- **Sur la page publique
/p/<slug>partagée par WhatsApp, un
invité qui n'a pas reçu son lien personnel peut taper son nom
pour atterrir directement sur sa propre page RSVP.**
- **Les suggestions du tableau de bord prennent le calendrier en
compte.** À 6 mois du mariage, vous voyez « Réservez la salle de
fête » plutôt que « Aucun invité saisi » — l'urgence vendor passe
avant la setup couple, et chaque suggestion s'éteint dès que la
catégorie correspondante a un prestataire choisi.
- Version 0.21.1629 avril 2026(Login network-error split, FieldDialog i18n key fix, scripts/dev reorg)
- **Quand votre connexion réseau coupe à la connexion, le message
est clair** ("Connexion réseau perdue. Vérifiez votre connexion
et réessayez.") au lieu du trompeur "Email ou mot de passe
incorrect". Avant, un blip DNS pendant
signInWithPasswordétaitsilencieusement renvoyé sur la copy "mauvais mot de passe" — les
utilisateurs croyaient avoir mal tapé leurs identifiants.
- **Les dialogues "Modifier ma fiche" affichent enfin leurs
placeholders informatifs.** Une régression introduite dans 0.21.14
(clés i18n contenant un
.) faisait planter le rendu — lespages crashaient en server-component. Corrigé.
- Version 0.21.1529 avril 2026(Vendor category canonicalisation + 4-city MVP scope)
- Décision produit : on garde le signup et la sélection
prestataire scopés à 4 villes pour le lancement (Casablanca,
Rabat, Marrakech, Tanger). Les 8 autres villes brièvement
ajoutées dans 0.21.14 sont retirées — on réouvre quand on aura
des prestataires vérifiés sur place.
- **L'annuaire et l'admin n'affichent plus de catégories
prestataire en anglais brut.** Toutes les fiches utilisent
maintenant le slug français canonique (« Photographe » au lieu
de « PHOTOGRAPHER »).
- Version 0.21.1429 avril 2026(Form polish: city dropdown, email pattern, auth error i18n, dialog placeholders)
- **Au signup, vous pouvez choisir votre ville parmi les 12
principales du Maroc** (Casablanca, Rabat, Marrakech, Tanger,
Fès, Agadir, Oujda, Tétouan, Meknès, Salé, Kenitra, El Jadida)
- une option « Autre ». Avant : seules Casablanca et Rabat
étaient proposées.
- Les erreurs d'inscription sont enfin en français
(« Cet email n'est pas valide » au lieu de
Email address "X" is invalid).- L'email est validé en temps réel au signup et à la
connexion : un email mal formé déclenche une bulle native du
navigateur AVANT même de cliquer "Créer". Plus de round-trip
Supabase pour rien.
- **Les dialogues "Modifier ma fiche" affichent enfin des
placeholders informatifs** (« Ex. Karim », « Ex. 200 »,
« JJ/MM/AAAA ») au lieu d'un tiret cadratin générique.
- Version 0.21.1329 avril 2026(Layout/UX polish: SummaryBar on /parametres, partner invite auto-copy, click-race fix, RSVP semantics)
- **La barre récapitulative (J-X · invités · budget · tables) est
désormais visible sur
/parametres,/profil,/messageset/notifications** — comme sur le reste du tableau de bord. Avant,elle disparaissait sur ces pages, donnant l'impression que le
compte à rebours s'était arrêté.
- **Inviter votre conjoint·e copie maintenant automatiquement le
lien d'acceptation dans votre presse-papiers.** Plus besoin de
chercher un bouton "copier" : un seul collage dans WhatsApp et le
lien est envoyé.
- **Le bouton "Configurer mon portail" n'a plus besoin d'être cliqué
deux fois.** La barre récap mettait ~1 seconde à apparaître après
le chargement de la page, ce qui décalait le bouton vers le bas
pile au moment du clic. La barre réserve maintenant son espace
dès le premier rendu — plus de glissement, le clic part bien.
- **Ajouter un invité avec "En attente" sur Henné/Mariage/Soirée
enregistre maintenant les 3 RSVP**, au lieu de seulement le
Mariage. Si vous laissez explicitement "En attente" pour Henné,
votre invité apparaîtra bien dans les statistiques Henné.
- Version 0.21.1129 avril 2026(Polish: countdown unification, seating empty state, admin/annuaire enum translations)
- Le compte à rebours J-X est cohérent partout. Avant, certaines
pages affichaient « 138 jours » et d'autres « 139 jours » pour la
même date — différence de 1 jour selon que le code arrondissait
vers le bas ou vers le haut. Toutes les surfaces utilisent
maintenant le même calcul (arrondi au plus proche jour entier).
- **Le plan de table n'affiche plus « 🎉 Tous vos invités ont une
table » quand il n'y a pas encore d'invités.** Vous voyez à la
place « Ajoutez des invités depuis l'onglet Invités pour
commencer ».
- **L'admin et l'annuaire affichent enfin la catégorie et la ville
du prestataire en français lisible** (« Photographe / Vidéaste »,
« Casablanca ») au lieu des slugs bruts (
photographer,casablanca). Le JSON-LDaddressLocalityest aussi capitalisépour le SEO.
- Le titre
/admin/vendors/pendingn'est plus du franglais :
« Prestataires en attente de vérification » au lieu de « Vendors
en attente de vérification ».
- Version 0.21.1029 avril 2026(Polish round: héros copy refresh + /family redirect for couples + vendor inquiry CTA + roadmap)
- **Le bloc « Mes héros » sur le tableau de bord et les étapes
« Comment ça marche » sur
/dashboard/herosreflètent enfin lanouvelle UX d'invitation par e-mail** (avant : « Allez dans
Planning et assignez une tâche à un proche » — obsolète depuis
Sprint C).
- **Quand vous invitez un héros, sa carte apparaît immédiatement
dans la liste en bas** au lieu de rester vide jusqu'au prochain
rafraîchissement.
- **Le couple ne voit plus l'« Espace Famille » trompeur quand il
visite
/family.** Cette page est réservée aux héros / proches ;les mariés sont maintenant redirigés vers leur planning.
- **Vous pouvez « Demander un devis » directement depuis la fiche
d'un prestataire** (
/annuaire/<slug>) — un nouveau bouton +formulaire en ligne envoie le message via le système d'inquiries
existant.
- Un lien « Vous êtes prestataire ? » est ajouté dans le footer
pour rendre l'inscription pro visible depuis n'importe quelle page
publique.
- Roadmap Phase 7 — ajout de l'option « Uploadez votre propre
invitation » (en plus du générateur in-app) à venir, pour les
couples qui ont déjà payé un graphiste.
- Version 0.21.929 avril 2026(Signup: pending email-confirmation screen — E-A6)
- **Quand vous créez un compte, vous voyez maintenant l'écran
« Vérifiez votre boîte mail »** au lieu d'une page blanche.
L'écran rappelle l'adresse e-mail saisie, propose un bouton
« Renvoyer le lien » si l'e-mail n'arrive pas, et un lien retour
vers la page de connexion. Avant, le formulaire vous redirigeait
vers
/onboardingqui re-redirigait vers/loginsans aucunmessage — vous restiez bloqué·e sans comprendre pourquoi.
- Version 0.21.829 avril 2026(Auth: role-aware post-login redirect + fix double navbar on /vendor/onboarding)
- **Quand un prestataire se connecte, il atterrit sur son espace
Pro** (et non plus sur le tableau de bord couple « Mon mariage
public »). Idem pour les modérateurs : direction
/admin/vendors./vendor/onboardingn'a plus de double barre de navigation.
La barre Pro se cachait derrière la barre consumer — visible sur
la même page. Une seule barre maintenant, propre, blanche.
- Version 0.21.729 avril 2026(Onboarding: bind partner_name / wedding_date / city to default tasks — E-A11)
- **Remplir l'assistant d'onboarding coche enfin les tâches
correspondantes.** Quand vous saisissez le nom de votre conjoint·e,
la date du mariage ou la ville pendant l'onboarding, vous voyez
immédiatement les 3 cases vertes sur votre tableau de bord — plus
besoin de re-cocher manuellement ce que vous venez de saisir.
- Version 0.21.629 avril 2026(Notifications: wire RSVP + partner-invited + apply v2 schema in prod)
- **Vous recevez enfin une notification quand un invité répond à son
invitation.** Sofia clique « Je viens » sur sa page → la cloche
s'allume, la card apparaît dans
/notifications, et votreconjoint·e voit la même chose en temps réel sur son téléphone.
- Inviter votre conjoint·e crée maintenant une notification. Vous
voyez immédiatement « Invitation envoyée à
<email>» dans votrefeed pour confirmer que c'est parti.
- Version 0.21.529 avril 2026(RSVP: kill the localStorage demo, ship Sprint 18 portal everywhere)
- **Le bouton « Copier le lien » sur
/invitesgénère enfin un lien
qui fonctionne pour vos invités.** L'ancien lien (
/rsvp?token=...)ne marchait que dans votre navigateur — quand un invité l'ouvrait
depuis WhatsApp ou son email, la page ne pouvait pas le retrouver.
Le nouveau lien (
/g/<identifiant>) est résolu côté serveur etfonctionne partout.
- Les invitations email pointent vers le même lien public. Plus
de chemin parallèle qui pourrait dériver — un seul URL canonique
par invité.
- **Le bouton « Copier le lien » sur
- Version 0.21.429 avril 2026(E2E walk-through fixes — onboarding crash, hero invite collision, /parametres crash, assignee i18n)
- L'onboarding ne crashe plus quand vous arrivez sur
/onboarding—
une erreur Next 16 affichait une page blanche au lieu de la check-list.
- Inviter un héros par e-mail fonctionne enfin. Le bouton "Inviter
un héros" sur
/dashboard/herosplantait avec une erreur de doublontechnique ; corrigé.
/parametresne crashe plus. L'écran réglages affichait une
erreur "use server" interne au lieu de vos préférences ; corrigé.
- **Le sélecteur d'assigné dans le planning affiche enfin les bons
libellés** ("Non assigné", "Mariée", "Marié", "Héros") au lieu des
clés techniques brutes (
dashboard.assigneeUnassigned...).- La cloche du Navbar affiche maintenant le vrai nombre de non lues,
même au-delà de 50. Avant, le compteur était dérivé côté client
d'une liste capée à 50 → un couple avec 87 non lues voyait "50".
Maintenant le serveur calcule le total et la cloche l'affiche
exact.
- Les notifications se rafraîchissent en temps réel. Quand votre
conjoint·e marque une notification comme lue depuis son téléphone,
votre cloche décrémente immédiatement. Quand un nouveau truc se
passe (un héros termine une tâche, un invité décline), ça apparaît
sans avoir à recharger la page.
- Les notifications de démo sont visiblement marquées « Donnée de
démo » et atténuées (opacity 80%). Plus besoin de deviner ce qui est
réel vs simulation.
- L'onboarding ne crashe plus quand vous arrivez sur
- Version 0.21.229 avril 2026(Notifications v2 — 3 more producers + deep-links + page UX patch)
- **Vos notifications cliquent maintenant directement vers la bonne
page filtrée.** Avant, cliquer sur "3 invités ont décliné" vous
emmenait sur
/invitessans filtre. Maintenant le menu d'invitésest pré-filtré sur le bon état RSVP, et "Yassir a confirmé" zoom
directement sur la fiche de Yassir. Idem pour les tâches en
retard (qui ouvrent la modale d'édition de la tâche concernée),
et pour le budget (catégorie traiteur sélectionnée).
- Cliquer sur une notification = un seul geste. Avant il fallait
cliquer sur la card (qui marquait juste comme lu), puis sur
"Voir plus →" en petit. Maintenant, un clic sur la card vous y
emmène directement.
- Couleur de la barre gauche selon l'urgence : doré pour info,
ambre pour attention, rouge pour urgent (tâche en retard depuis
plus de 7 jours).
- Tag « Donnée de démo » discret sur les notifications de la
base de seed (les fameuses
[p2-seed]) pour les distinguervisuellement des vrais événements quand vous êtes sur le compte
de test.
- 3 nouvelles notifications réelles (en plus des 3 du commit
précédent) :
- « X a confirmé/décliné sa présence » quand un invité
soumet son RSVP via le lien public — déduplication par heure
pour ne pas spammer si quelqu'un répond à plusieurs événements
en lot.
- « X a répondu à votre demande » quand un prestataire passe
le statut d'une de vos demandes en
responded.- « Tâche en retard : X — Échue depuis N jours » émis chaque
matin par un cron Vercel qui scanne tout le planning et
n'émet qu'UNE notification par tâche par jour (idempotent).
- **Toutes les chaînes de la page Notifications sont maintenant en
4 langues** (fr/en/es/nl) — fini le mélange français-en-tout-langue.
- Version 0.21.129 avril 2026(Notifications v2 — schema, couple-shared, notify(), 3 producers)
- **Les notifications deviennent partagées entre vous et votre
conjoint·e.** Quand un héros termine une tâche, quand vous invitez
quelqu'un, quand votre conjoint·e accepte l'invitation — vous voyez
tous les deux les mêmes événements dans la cloche, chacun avec son
propre état "lu / non lu".
- 3 nouvelles notifications réelles (avant, tout était de la
fausse data de seed) :
- « X a terminé : _titre de la tâche_ » dès qu'un héros que
vous avez assigné marque sa tâche comme done. Plus besoin de lui
demander.
- « X a rejoint votre espace mariage » quand votre conjoint·e
accepte votre invitation (Sprint 12).
- « Invitation envoyée à X » quand vous invitez un héros depuis
/dashboard/heros.- Les notifications existantes (sample data avec « [p2-seed] »)
continuent à apparaître mais sont maintenant marquées internement
comme
source=seedpour pouvoir être atténuées dans la prochainerefonte UI.
- Version 0.21.029 avril 2026(Phase 2 — /family multi-couple support + audit notifications)
- Si vous aidez plusieurs mariages cette saison, l'onglet Mes
tâches (
/family) regroupe vos tâches par couple, avec sonpropre titre + son propre compte à rebours par mariage. Avant ce
patch, tout se mélangeait dans une seule liste plate, et le
countdown affichait n'importe quel mariage trouvé en premier
(souvent pas le plus urgent).
- Le compte à rebours en haut affiche maintenant le mariage **le
plus proche** quand vous en aidez plusieurs.
- Audit notifications enregistré dans
docs/audits/notifications-2026-04-28.md— 60+ findings, planpour la reconstruction complète du système de notifications. Les
commits suivants attaquent ces priorités dans l'ordre.
- Version 0.20.1128 avril 2026(Sprint D — revalidatePath cascades sur mutations)
- **Le dashboard se rafraîchit immédiatement après chaque
modification.** Avant, vous ajoutiez un paiement dans /budget,
reveniez au dashboard → la jauge n'avait pas bougé. Idem en
ajoutant une tâche, une invité, ou un événement. Maintenant chaque
action cascade vers les écrans qui en dépendent (dashboard,
/family pour les héros, etc.).
- Version 0.20.1028 avril 2026(Sprint C — Inviter un héros par e-mail, sans serveur mail)
- **Nouveau : invitez vos héros directement par e-mail depuis
/dashboard/heros.** Avant, vous deviez d'abord assigner unetâche à quelqu'un pour qu'il apparaisse dans la liste, puis lui
attribuer ses rôles — ordre impossible avec la nouvelle contrainte
d'assignation introduite hier (Phase 1 ADR-0002). Le nouveau
formulaire en haut de l'onglet Héros casse ce blocage : saisissez
l'e-mail + (optionnel) prénom + rôles, et l'app crée le compte de
votre héros·ine en un clic.
- Lien magique copy-pasteable. Pas besoin de serveur d'envoi
d'e-mail (Resend) configuré pour l'instant : l'app génère un lien
d'auto-connexion qu'elle vous montre dans un encadré crème ;
copiez-le dans WhatsApp, SMS ou votre e-mail personnel et envoyez-le
à votre héros·ine. Un clic et hop, elle est connectée à Lalla
Kenza, prête à recevoir ses tâches.
- Les invitations sur des e-mails déjà inscrits sur Lalla Kenza
sautent la création du compte et passent directement à la
promotion (avec un toast explicite : « Cette personne avait déjà
un compte »).
- Version 0.20.928 avril 2026(Sprint B — wedding metadata mirror trigger)
- **La date du mariage, la ville, le budget et le nom du conjoint
restent synchronisés entre vous deux automatiquement.** Avant ce
patch, ces 4 informations vivaient sur 2 lignes profil distinctes
(une par marié). Si vous modifiez la date depuis votre compte, votre
conjoint·e voyait toujours l'ancienne date dans son countdown,
son rappel mariage, ses pages publiques. Maintenant un trigger SQL
recopie automatiquement chaque modification d'un côté vers l'autre.
- Au moment où votre conjoint·e accepte l'invitation, son profil
est immédiatement initialisé avec votre date / ville / budget — il
n'arrive plus sur un dashboard vide.
- Patch silencieux pour les couples déjà mariés : un backfill
one-shot synchronise les 4 champs entre les deux profils existants.
- Version 0.20.828 avril 2026(Sprint A — multi-couple data unification)
- Le partenaire voit enfin le même mariage que vous. Avant ce
patch, après que votre conjoint·e acceptait l'invitation et
signait sur son propre compte, sa session affichait un dashboard
vide : aucun invité, aucun budget, aucun prestataire, aucune
tâche. Toutes les données partagées sortaient sur votre compte
primaire mais ses queries filtraient sur son user_id à elle. Fix
général : l'app interroge maintenant la base avec `{vous,
partenaire}` partout où les données sont partagées (invités,
événements, budget, tâches, vendors, wishlist, héros, livre d'or,
enveloppes).
- CoupleSummaryBar (la barre sticky sur tous les écrans
dashboard) qui affichait systématiquement « 0 invités confirmés /
0 MAD budget » a été corrigée — elle pointait sur deux tables qui
n'existaient pas (
budget_configsau lieu debudget_config,rsvpsau lieu deguest_event_rsvp).- Plus de double seed des tâches quand le partenaire accepte
l'invitation. Le catalogue par défaut était re-injecté sous son
user_id, dédoublant la liste de planning à 60 → 120 tâches. Désormais
la garde idempotente regarde le scope partagé.
- Version 0.20.628 avril 2026(Assignation des tâches — mariés + héros uniquement)
- Le champ « Assigner à » devient un menu déroulant, contraint
aux deux marié·e·s et aux héros déjà promus depuis l'onglet Héros.
Plus de saisie libre — fini les tâches assignées à « Yassir » qui
ne reçoivent jamais leurs tâches. Le menu affiche deux sections
visuellement distinctes (« MARIÉS » + « HÉROS ») avec un rappel
discret du rôle de chaque personne (Trésorier, Maître de cérémonie,
etc.).
- Empty state explicite : « Personne à qui déléguer encore.
Promouvez un proche depuis l'onglet Héros. » — quand aucun héro
n'est encore promu, le couple voit clairement quoi faire pour
débloquer le menu.
- Migration silencieuse des assignations existantes : les personnes
déjà assignées à au moins une tâche sont automatiquement promues
au rôle « Coordinateur famille » pour préserver leurs assignations.
- Aucun changement visible immédiat pour les héros déjà promus —
ils restent assignables sans intervention. Les phases 2-4 ajouteront
l'invite par e-mail, le dashboard dédié héros, et la notification
aux mariés à chaque tâche complétée. Pré-requis Phase 2 :
configurer Resend (
RESEND_API_KEYà ajouter en prod) + vérifierun domaine sender (lié à l'achat domaine prévu en Stage 1 de
COSTS.md). Le plan détaillé phases 2-4 + dépendances (rate limit
Upstash, RLS tests pgTAP, i18n) vit dans
docs/adr/0002-task-assignment-allowlist.md§6. - Version 0.20.328 avril 2026(Authentic zellige PNG — Gemini-generated tile)
- Motif zellige authentique : remplacement du SVG hand-coded par
une image Gemini-générée (16-pointes Khatem + cadre girih
octogonal + petites étoiles aux interstices), exactement le rendu
validé par le founder. Tile 800 × 800 servie en WebP (~67 KB), avec
un PNG fallback (~170 KB).
- Version 0.20.228 avril 2026(Zellige rosette upgrade — 16-fold Khatem)
- Motif zellige enrichi : passage de la grille 8-pointes (Khatem
Sulaymani) à une rosette 16-pointes double (étoile externe
géométrique + étoile interne plus aiguë), conforme à la référence
partagée par le founder. Densité du motif augmentée — chaque tile
passe de 120 px à 180 px et ajoute des petites étoiles 8-pointes
aux midpoints + rubans-losanges connecteurs (cardinaux + diagonaux).
- Version 0.20.128 avril 2026(Zellige refresh + mobile audit)
- Nouveau motif zellige authentique sur les pages d'accueil et le
tableau de bord — tessellation Khatem Sulaymani à deux échelles
(grandes étoiles à 8 pointes sur la grille principale, petites
étoiles aux midpoints, rubans-losanges connecteurs) qui colle à la
référence d'un mur de Fès / Marrakech. Les anciennes couches plus
graphiques (étoile-cadre + clous laiton) sont retirées au profit de
cette grille plus dense et plus rythmée.
- Annuaire prestataires — les chips de catégories
(Salle / Traiteur / Neggafa / …) abandonnent l'emoji système au
profit des icônes hand-drawn Atlas Lattice (Sprint 2). Cohérence
visuelle complète entre l'annuaire, le dashboard et le planning.
- Accessibilité menu mobile — le bouton hamburger expose maintenant
un nom accessible (
aria-labellocalisé en 4 langues) +aria-expanded+aria-controlspour les lecteurs d'écran. - Version 0.20.028 avril 2026(Sprint 7 — visual regression + a11y + per-feature SPECs)
Travail invisible côté utilisateur — sécurité de qualité ajoutée pour
qu'aucune régression visuelle ni d'accessibilité ne passe en
production sans alerte.
- Version 0.19.028 avril 2026(Sprint 6 — audit infrastructure final)
Travail invisible côté utilisateur — verrouillage de la qualité des 5
sprints précédents dans CI pour empêcher toute régression silencieuse.
- Version 0.18.028 avril 2026(Sprint 5 — editorial layouts)
Trois pages emblématiques refondues éditorialement :
- 🏛 Page d'accueil : nouvelle composition asymétrique (texte 7/12,
illustration arche médina 5/12), titre Fraunces avec mot accent
italique qui apparaît 500 ms après le reste, dégradé gold→blush
derrière le zellige.
- 🪞 Bandeau du dashboard : valeurs en Fraunces 600 + sous-titres
Manrope italic, jauge budget en arc circulaire SVG (au lieu de
texte), tables remplies en pictogramme de points (au lieu de "13/21").
- 💼 /budget overview : stats refaites en spread magazine — eyebrow
Manrope uppercase tracking-widest + numéral Fraunces gros + filet
gold sous chaque carte.
- Version 0.17.028 avril 2026(Sprints 1-4 + BUG-110 + doc audit — programme rattrapage CHANGELOG)
- ✨ Identité visuelle Atlas Lattice : 15 icônes Moroccan-wedding
hand-drawn (neggafa caftan, traiteur théière, salle arche médina,
henné palmier, lanterne, croissant + étoile, …) remplacent les
emojis dans budget + planning. Motif zellige Khatem Sulaymani
authentique en background discret du landing + dashboard.
- 📐 Toutes les pages parlent la même typographie : titre Fraunces
- eyebrow uppercase gold + filet décoratif via le nouveau composant
<PageHero>(10 pages migrées).- 🎁 Empty states refaits avec 6 illustrations dédiées (verre de
thé, jar henné, caftan, lanterne, arche médina, palmier-nuit) au
lieu de "AlertTriangle + paragraphe".
- 🏃 Motion : page-load stagger sur dashboard + budget + planning
(cards apparaissent en cascade), Toggle preferences avec spring
overshoot, célébration confetti d'étoiles zellige quand un
paiement traverse 25/50/75/100 % du budget.
- 🐛 BUG-110 fixes :
- le bandeau "€149k / €0 budget" affichait du faux euro avec un
montant déconnecté → maintenant en MAD avec la bonne donnée
(formatMoney + aggregator branché sur sum(budget_items)).
- le crayon "Modifier" sur la wishlist ne faisait rien → ouvre le
modal pré-rempli pour modifier le souhait.
- les cartes catégories du budget se "filtraient" silencieusement →
scroll-into-view + pill "Filtre actif : X ✕".
- suffix
[p2-seed]qui leakait dans les libellés prod → strippé.
- Version 0.16.028 avril 2026(BUG-108 — Task completion architecture, sprint dédié)
Refonte complète du système qui lie vos tâches à votre mariage. C'est invisible pour vous au début mais ça change beaucoup de choses :
- 🪄 Vos tâches s'auto-complètent quand vous remplissez ce qu'elles demandent. Définissez la date du mariage dans votre profil → la tâche "Définir la date" se coche automatiquement. Sélectionnez votre salle dans
/prestataires→ "Réserver la salle" + "Visiter 3 salles" se cochent ensemble. Pareil pour le traiteur, le photographe, l'orchestre, le fleuriste, la maquilleuse, la neggafa. - 🧭 Cliquer sur une tâche ouvre la bonne fenêtre au lieu de la marquer terminée à l'aveugle. Pour "Choisir la ville du mariage", on ouvre un input ville. Pour "Réserver la salle", on ouvre la fiche salle. Pour les tâches libres, on ouvre la textarea de notes habituelle.
- 🚪 L'onboarding devient une suite de tâches au lieu d'un wizard à part. Vous voyez vos 6 étapes (partenaire, ville, date, invités, budget) avec une barre de progression. Si vous quittez et revenez, on reprend où vous en étiez. Quand toutes les étapes sont faites, vous arrivez automatiquement sur le dashboard.
- 📊 Le pourcentage "X% du planner fait" sur le dashboard est maintenant calculé sur vos vraies tâches (pas une formule estimée).
- 🪄 Vos tâches s'auto-complètent quand vous remplissez ce qu'elles demandent. Définissez la date du mariage dans votre profil → la tâche "Définir la date" se coche automatiquement. Sélectionnez votre salle dans
- Version 0.15.227 avril 2026(Acompte sur Confirmé + dialog de confirmation des tâches)
Deux raffinements sur les fixes du dashboard d'aujourd'hui :
- 🧾 Demande d'acompte quand vous confirmez un prestataire : passer un slot prestataire en "Confirmé" (la salle, le traiteur, etc.) déclenche désormais un champ "Acompte payé" optionnel dans la même fenêtre. Si vous renseignez le montant, il est automatiquement ajouté comme paiement sur la ligne budget de cette catégorie (créée si elle n'existait pas). Plus besoin d'aller dupliquer l'info dans
/budgetà la main. - 📝 Marquer une tâche terminée demande des détails : avant, un clic sur la pastille marquait la tâche done en silence. Maintenant ça ouvre une mini-fenêtre où vous pouvez ajouter un commentaire (« Riad Atlas réservé pour 80k MAD, contact Yassine 06... ») qui est sauvegardé sur la tâche. Le commentaire est optionnel — laissez-le vide et un seul clic sur "Marquer terminée" suffit.
- 🧾 Demande d'acompte quand vous confirmez un prestataire : passer un slot prestataire en "Confirmé" (la salle, le traiteur, etc.) déclenche désormais un champ "Acompte payé" optionnel dans la même fenêtre. Si vous renseignez le montant, il est automatiquement ajouté comme paiement sur la ligne budget de cette catégorie (créée si elle n'existait pas). Plus besoin d'aller dupliquer l'info dans
- Version 0.15.127 avril 2026(Dashboard interactif — quick wins audit-driven)
Quatre frictions remontées sur le dashboard, toutes corrigées dans la même journée :
- 💾 Le bouton "Enregistrer" sur les Prestataires principaux fonctionne : avant, vous saisissiez le nom du traiteur / la salle / etc., cliquiez "Enregistrer", et au prochain refresh tout disparaissait — la valeur n'était jamais écrite en base. Désormais c'est persisté dans votre shortlist (visible aussi sur
/prestataires), un toast confirme l'enregistrement, et plus de données fantômes. - ✅ Les "Prochaines tâches" du dashboard sont enfin cliquables : avant, c'était une liste de suggestions hardcodées (impossible de les marquer terminées). Maintenant ce sont vos vraies tâches, un clic sur la pastille à gauche les marque comme terminées. Toast de confirmation, refresh automatique du widget.
- 👥 Assigner une tâche à un héros depuis le dashboard : chaque ligne de tâche porte un picker "Assigner" qui liste vos héros (membres famille à qui vous avez déjà délégué quelque chose). Plus besoin de passer par
/planningpour réassigner. - 📊 "Meilleurs postes" sous la jauge de budget : la carte Budget affiche désormais vos 5 plus gros postes (salle, traiteur, photographe…), avec une barre fine qui montre ce qui est payé / estimé. Plus besoin d'ouvrir
/budgetpour repérer où va le gros de l'enveloppe.
- 💾 Le bouton "Enregistrer" sur les Prestataires principaux fonctionne : avant, vous saisissiez le nom du traiteur / la salle / etc., cliquiez "Enregistrer", et au prochain refresh tout disparaissait — la valeur n'était jamais écrite en base. Désormais c'est persisté dans votre shortlist (visible aussi sur
- Version 0.15.027 avril 2026(Sprint 18 — 3 moonshots shippés en série)
Trois fonctionnalités "wow" du backlog Moonshots, toutes shippées et live :
- 💌 Lettre scellée pour mon partenaire (MS-016) : depuis
/parametres/lettre-scellee, vous écrivez un mot que votre conjoint·e ne pourra lire qu'à la date que vous choisissez (le jour J par défaut). Le serveur garantit que personne — ni vous, ni iel, ni nous — ne peut l'ouvrir avant. Le texte vit chiffré côté Supabase derrière une règle qui n'autorise la lecture qu'à partir de l'heure de déverrouillage. - 🧧 Enveloppes du jour J (MS-008) : nouvelle page
/budget/enveloppes, accessible depuis le bouton "🧧 Enveloppes du jour J" dans/budget. Pour chaque ligne de budget où il reste un solde à régler, on génère une carte imprimable (prestataire + libellé + montant en MAD). Bouton "Imprimer" qui cache la navbar/footer pour un PDF propre. Tradition marocaine : même quand l'acompte est viré, le solde se règle en cash dans une enveloppe le jour même. - 🔗 Portail invité unique
/g/<id>(MS-017) : chaque invité reçoit désormais une URL personnelle (à partager par WhatsApp, email, ou QR sur la carte d'invitation) qui ouvre un seul écran où iel peut confirmer sa présence à chaque évènement (Henné, Cérémonie, Soirée, Brunch — boutons "Je viens / Peut-être / Désolé") et laisser un mot pour les mariés. Anonyme, pas de compte, pas de mot de passe. Réponse modifiable autant de fois qu'iel veut. Les 20 invités-test ont déjà reçu leur slug en backfill.
- 💌 Lettre scellée pour mon partenaire (MS-016) : depuis
- Version 0.14.026 avril 2026(Sprints 16 + 17 — wire-the-mocks-to-real-data + diaspora i18n)
Sprint 16/17 = nettoyage de fond. Plus aucune surface du dashboard ne montre de données fictives — tout vient de la base.
- 🧑💼 Espace prestataire
/vendorconnecté : la page d'accueil prestataire affiche désormais le vrai profilpublic_vendorsdu compte connecté + ses vrais avis. Plus de "Photographe Démo" en dur. - 📰 Mon blog
/mon-blogéditable : tablecouple_postscréée + page branchée. Les couples peuvent enfin publier des billets sur leur portail public. - ✉️ Invitations
/invitationssur la vraie table : groupes d'invités (invitation_groups) chargés depuis Supabase, plus de mock. - 💳 Liens de paiement externes : table
external_payment_links+ UI sur/wishlist— pour brancher PayPal, CashPlus, etc. à la cagnotte. - 🛠️ Admin prestataires Phase 2 + 3 : les boutons supprimer / vérifier sur
/admin/vendorssont câblés aux vraies Server Actions, et le modal d'édition sauvegarde réellement (avec audit trail dansadmin_actions_log). - 📅 3 évènements créés à l'inscription : Henné + Mariage + Soirée par défaut, au lieu de "Mariage" tout seul. Le couple peut désactiver ce qu'il ne veut pas.
- 👋 Étape "inviter mon partenaire" dans l'onboarding : la wizard d'inscription a une 4ème étape pour envoyer l'invitation au conjoint·e — plus besoin d'aller dans
/parametresaprès. - 🇪🇸 🇳🇱 Espagnol et néerlandais ajoutés : 4 langues actives (FR / EN / ES / NL) pour la diaspora marocaine en Espagne et aux Pays-Bas. L'arabe reste dormant en attendant l'audit RTL.
- 🏠
/adminmontre les vraies stats : compte de couples, prestataires, RSVP, etc. — chargés depuis Supabase. Plus de chiffres ronds inventés. - 🌱 Données seed cohérentes : un couple-test "tout renseigné" (Salma & Yassir) avec invités, budget, plan de table, prestataires shortlistés, blog rempli — pour tester chaque surface avec un cas réaliste. Et un annuaire de prestataires premium Casa/Rabat par catégorie.
- 🧑💼 Espace prestataire
- Version 0.13.026 avril 2026(Sprint 15 — site-wide audit + remediation, deploy item-by-item)
Grosse passe d'audit sur tout le site, avec remédiation déployée commit-par-commit pour qu'on puisse tester chaque fix isolément :
- 🔧 Paramètres réparés (BUG-100 critique) : "Configurer mon portail" depuis
/portailramenait à un 404. Idem pour les pages "Mes données" et "Langue". Routes déplacées au bon endroit, tout est de nouveau accessible. - 🪪 5 pages manquantes créées :
/cgu(conditions d'utilisation),/forgot-password(réinitialisation du mot de passe),/logout,/wishlist/annuaire/proposer(proposer un cadeau au catalogue),/demo/portail(aperçu marketing du portail public). C'étaient des liens présents dans l'UI qui menaient à du vide. - 👑 Héros = Lalla Laaroussa & Moulay Sultan : les rôles par défaut sur
/planningne s'appellent plus génériquement "Mariée" / "Marié" mais portent leur titre honorifique marocain. Ajout deGLOSSARY.mdqui figerait le vocabulaire (Lalla Laaroussa, Moulay Sultan, Henné, Sbouhi, Neggafa, Hero, Cagnotte, etc.). - 🪑 Plan de table : 2 améliorations rapides : nouvelle table propose automatiquement "Table N+1" (au lieu d'un nom vide), et un crayon ✎ sur chaque table permet de la renommer en place.
- 🪧 Page
/portailrentre dans le tableau de bord : avant, elle était hors layout — pas de navbar quand on tombait sur l'écran "portail non publié". Maintenant on garde la navigation pour repartir vers Dashboard / Planning / etc. - 📰 Blog admin enfin écrivable : la page
/admin/blogne sauvegardait rien. CRUD branché aux Server Actions (rôle admin/moderator gated). - ⚠️ Page
/rsvpclairement étiquetée "Aperçu démo" : l'ancienne version montrait des invités fictifs sans indication. Bannière ajoutée pour qu'un visiteur égaré comprenne que ce n'est pas son vrai RSVP. - 🔧 Annuaire prestataires admin :
/admin/vendorsmontrait 6 prestataires fictifs par défaut. Maintenant il charge les vrais depuis Supabase. - ✉️ Notifications branchées sur Supabase (Sprint 13) : la cloche en haut à droite affiche les vraies notifications du compte (RSVP reçus, partenaire ayant rejoint, etc.) au lieu d'une liste mockée.
Et toujours en arrière-plan : moonshots ajoutés pour MS-015 (portail "lendemain de mariage" pour les invités) et MS-016 (lettres scellées entre les mariés, déverrouillées le jour J).
- 🔧 Paramètres réparés (BUG-100 critique) : "Configurer mon portail" depuis
- Version 0.12.026 avril 2026(Sprint 12 — Couple = 2 users + Wishlist directory + i18n bulk)
- 💑 Compte couple = 2 inscriptions : Mr et Mme s'inscrivent indépendamment et partagent le même tableau de bord. La première personne invite l'autre par email depuis
/parametres. Toutes les modifications (invités, budget, plan de table…) sont visibles par les deux. - 🎁 Annuaire des cadeaux : nouveau catalogue
/wishlist/annuaire(idées de cadeaux populaires pour mariages marocains) que vous pouvez parcourir + ajouter en un clic à votre wishlist personnelle. - 🌍 Bascule français/anglais fonctionnelle : le sélecteur de langue dans la navbar bascule maintenant l'UI complète (~250 chaînes traduites des deux côtés).
- 📋 Architecture review : doc
docs/ARCHITECTURE_REVIEW_SPRINT_12.mdqui cartographie tout ce qui est branché vs mocké, le RLS, l'auth, l'i18n, les schémas restants, etc.
- 💑 Compte couple = 2 inscriptions : Mr et Mme s'inscrivent indépendamment et partagent le même tableau de bord. La première personne invite l'autre par email depuis
- Version 0.11.025 avril 2026/26 (Sprint 11 — wire 5 dashboard surfaces from mock to Supabase)
5 surfaces qui affichaient des données mockées sont maintenant branchées sur la vraie base :
- Liste d'invités (
/invites) : ajouter / modifier / supprimer un invité persistent vraiment. - Wishlist (
/wishlist) : items + cagnottes lus depuis Supabase ; ajout / suppression branchés. - Plan de table (
/seating) : tables + assignations branchées (déjà fait Sprint 9 mais consolidé). - Tableau de bord (
/dashboard) : résumé budget + invités + RSVP via/api/dashboard-summaryau lieu d'un objet hardcodé. - Liste de souhaits par mes proches (
/livre-d-or) : Sprint 10 BUG-051.
- Liste d'invités (
- Version 0.10.026 avril 2026(Sprint 10 — bug bash : 7 quick fixes + 3 architectural reworks)
Sprint dédié à la chasse aux bugs après l'audit profond du code :
- ✉️ Système de messagerie privée enfin réel : la page
/messagesn'était qu'un mock — les messages disparaissaient au rafraîchissement. Maintenant : conversations 1:1 persistées (couple ↔ prestataire, couple ↔ support Lalla Kenza), badge de messages non lus, marquage automatique en "lu" à l'ouverture, envoi optimiste avec rollback en cas d'erreur. - 📖 Livre d'or branché aux vraies données : finis les 12 messages mocks "Karim Idrissi" / "Tante Fatima". Le livre d'or affiche maintenant les vrais messages RSVP de vos invités + ceux laissés sur votre livre d'or public, en temps réel.
- 💬 Plus aucun message RSVP perdu : l'ancien comportement écrasait silencieusement le message précédent quand un invité répondait deux fois. Nouveau modèle = log append-only par invité, on garde l'historique complet.
- ⏱️ Compte à rebours du mariage corrigé : "2 mois 5 jours" pour 65 jours d'écart était basé sur un mois fixe de 30 jours, faux selon les mois calendaires. Maintenant calcul exact via les vrais mois.
- 📱 5 quick wins UX & accessibilité : champs mot de passe compatibles 1Password / iCloud Keychain, claviers téléphone optimisés Android, images de prestataires lisibles aux lecteurs d'écran, plus de mismatch d'hydratation sur la page planning, plus de saut visuel quand les photos chargent.
- ✉️ Système de messagerie privée enfin réel : la page
- Version 0.9.026 avril 2026(Sprint 9 — robustness + dietary + vendor inbox foundation)
Petit sprint discret, gros gains de fiabilité :
- 🛡️ Plus de pages blanches sur
/dashboard,/annuaire,/p/<slug>,/blogquand une variable d'environnement Supabase est manquante. Les modules concernés (Heros, Reviews, Wishlist publique, Portail messages, RSVP, gallerie) renvoient maintenant un état vide plutôt que crash 500. - 🥗 Restrictions alimentaires + allergies par invité :
dietary_restrictions(halal, végétarien, sans porc, gluten-free, …) +allergiestext libre. Le traiteur peut récupérer ça avant J-7 au lieu de relancer la mariée sur WhatsApp. - 📥 Boîte de réception prestataires (fondation) : table
vendor_inquiries+ actions serveur prêtes. La page/vendor/inquiriesarrive en Sprint 10 — d'ici là, le schéma est en place donc les futurs PRs ne touchent plus à la DB. - 📱 Modaux mobiles iPhone-safe : plus de boutons « Enregistrer » coupés sous l'indicateur d'accueil iOS quand un formulaire est plus haut que l'écran. Le composant Dialog scrolle proprement.
- 🖱 7 boutons UX corrigés sur
/dashboardet/messages: ajout detype="button"pour éviter les soumissions de formulaire accidentelles dans les conteneurs<form>.
- 🛡️ Plus de pages blanches sur
- Version 0.7.025 avril 2026(night, Sprint 2 finish + Sprint 3 + Sprint 4)
Une nuit, trois sprints livrés en chaîne + premier vrai déploiement Netlify :
- 🛡️ Authentification à deux facteurs pour les comptes admin (TOTP — scannez un QR avec Google Authenticator / 1Password / Authy).
- 🚨 Alertes intelligentes sur le tableau de bord : 6 règles qui vous préviennent quand quelque chose mérite attention.
- 🔍 Recherche globale ⌘K : appuyez sur
Cmd+K(Mac) ouCtrl+K(PC) pour chercher invités, tâches, prestataires, événements en un instant. - 💰 Budget partial-payments : suivez vos acomptes / soldes par prestataire avec raccourcis « Acompte 30% / 50% / Solde restant ».
- ⚖️ Comparateur de prestataires : page
/prestataires/comparequi affiche vos prestataires côte-à-côte avec coach silencieux (« vous n'avez vu que 2 photographes — règle du 3 », « écart de prix 60% — vérifiez l'équivalence »). - 👨👩👧 Espace famille : votre cercle proche peut maintenant voir les tâches que vous lui avez assignées + le compte à rebours du mariage.
- ✨ Section « Nouveautés » publique sur la home + page
/changelog: transparence sur ce qu'on a livré chaque semaine. - 📋 Boîte à outils contractualisation (
/outils/contrat) : 5 guides côté mariés (salle, traiteur, photographe, neggafa, orchestre) avec questions à poser, clauses à exiger, red flags à fuir, et templates de contrat. Aucun équivalent au Maroc. - 🌐 Aperçu trilingue de votre faire-part (
/invitations/preview) : FR / AR / EN côte-à-côte, 3 templates au choix, partageable avec votre famille via URL. - 🏆 Programme prestataires Vérifié :
/vendor/onboardingpermet aux prestataires de s'inscrire gratuitement (100 premiers gratuits). Une fois validés par notre équipe, ils obtiennent le badge « Vérifié » dans l'annuaire. - 📰 5 articles SEO : Budget mariage 150 invités, Choisir sa neggafa, Le Henné en 2026, Mariage diaspora France, Plan de table 300 invités.
- 🌀 Apple Sign-In placeholder sur
/loginet/register(activation après immatriculation Apple Developer). - 🆕 Pages /a-propos, /contact, /mentions-legales créées (étaient en 404 — fix BUG-005).
- 🚀 Site déployé sur Netlify —
lallakenza.netlify.app. Nouveau host de dev/preview pour itérer sans le cap 100 deploys/jour de Vercel.
- Version 0.6.125 avril 2026(evening, Sprint 1 → Sprint 2 ratchet)
Sprint 1 + premier pas de Sprint 2 :
- 👨👩👧 Groupes d'invités (« Famille du marié », « Amis de la mariée »…) avec option « assoir ensemble » — utilisée par le plan de table.
- 📋 Import en masse depuis Excel/Google Sheets : copier-coller direct ou import CSV, détection automatique des colonnes (Nom / Téléphone / Côté / Email…), prévisualisation avant validation, jusqu'à 500 invités d'un coup.
- 📞 Numéros au format international : tapez
0612345678, on stocke+212612345678. Marche aussi pour la France et les Émirats. - 🎯 Plan de table magique : bouton « Proposer un plan » qui place automatiquement vos invités. Les groupes restent ensemble — un groupe de 20 (toute la famille du marié) sera réparti sur deux tables de 10 sans casser le groupe.
- 🚨 Alertes intelligentes sur le tableau de bord : 6 règles qui vous préviennent quand quelque chose mérite attention (RSVP en retard, budget dépassé, prestataires non confirmés…).
- 🔍 Recherche globale ⌘K : appuyez sur
⌘K(Mac) ouCtrl+K(PC) n'importe où dans l'app pour chercher invités, tâches, prestataires et événements en un instant.
- Version 0.6.025 avril 2026(afternoon-late)
Six itérations shipées en série :
- 🌟 Mariage activé par défaut + anglais en langue d'interface (Settings → Langue) + nouvelle moonshot WhatsApp Business documentée.
- 🪄 Onboarding guidé en 4 étapes pour les nouveaux couples — invisible pour vous, mais ce sera le premier écran d'un nouvel inscrit.
- 📱 Barre de navigation mobile en bas d'écran (5 onglets : Accueil, Invités, Planning, Budget, Plus). Plus de scroll horizontal moche sur smartphone.
- 📊 Suivi RSVP consolidé dans
/invites/rsvp— un tableau qui croise vos invités et vos cérémonies, avec totaux par événement. - ⏳ Compte à rebours du mariage en haut du dashboard, qui passe en mode urgence à J-30 et propose un raccourci vers le tableau d'urgence.
- 📸 Galerie photos sur la page publique
/p/<slug>— uploadez jusqu'à 12 photos depuis Paramètres → Espace public → Galerie photos (max 5 Mo, JPEG/PNG/WebP).
- Version 0.5.025 avril 2026(afternoon)
- 🪑 Plan de table interactif (premier jet). Créez vos tables avec un nom et une capacité optionnelle, puis assignez vos invités d'un clic. Les invités sans table apparaissent en bas de l'écran. La page calcule automatiquement le nombre d'invités placés, ceux qui restent à placer, et la capacité totale utilisée. Disponible dans Organisation → Plan de table.
- Version 0.4.025 avril 2026
- 🌐 Page « Save the date » à partager (option opt-in). Choisissez un slug (ex.
salma-yassir-2026), publiez votre page et envoyez le lienlallakenza.com/p/<slug>à votre famille. La page reprend vos prénoms, la date et la liste des cérémonies activées — aucune donnée privée (budget, invités, prestataires) n'y apparaît. Désactivable à tout moment depuis Paramètres → Espace public.
- 🌐 Page « Save the date » à partager (option opt-in). Choisissez un slug (ex.
- Version 0.3.224 avril 2026(night)
- ♿ Lecture plus confortable, partout sur le site. On a affiné les couleurs des textes et des boutons pour qu'ils soient lisibles même en plein soleil ou pour les personnes avec une vue moins fine. Le doré reste la couleur signature mais s'utilise désormais à la bonne intensité selon qu'il sert de décor ou de texte.
- Version 0.3.124 avril 2026(late evening)
- 🌍 Préparation pour la traduction arabe (invisible aujourd'hui). Toutes les chaînes de l'interface sont désormais centralisées dans un fichier de messages — quand on activera l'arabe, l'interface basculera automatiquement (sens d'écriture droite-à-gauche inclus). Aucun changement visuel pour vous.
- Version 0.3.025 avril 2026
- 🗓 Préparation du modèle multi-jours (Henné, Sbouhi, Cérémonie, Soirée). C'est invisible aujourd'hui — la base de données est prête à recevoir un mariage avec plusieurs événements. La prochaine itération apportera l'interface pour les gérer + la page RSVP par événement (chaque invité confirme jour par jour).
- Version 0.2.124 avril 2026(late afternoon)
- 🐛 Bugs de comportement subtils corrigés : animation de confettis après inscription, génération d'ID unique pour les brouillons d'articles, boutons "créer nouveau groupe" dans la liste d'invités. Vous ne le verrez pas — mais le site est plus stable sous React 19.
- Version 0.2.024 avril 2026
Rien ne change visuellement aujourd'hui — toute la journée était consacrée à renforcer les fondations pour construire plus vite et mieux dans les semaines à venir.
Ce qu'on a préparé en coulisses :
- 🛡️ Sécurité renforcée — chaque modification du site est maintenant scannée automatiquement pour vérifier qu'aucun mot de passe ou clé secrète ne fuite, et que les accès aux données restent bien cloisonnés par utilisateur.
- 🍪 Bannière cookies conforme — avant d'activer la moindre mesure d'usage (PostHog), le site demande votre accord en français. Vous pouvez refuser, et tout continue à fonctionner normalement.
- 📋 Politique de confidentialité provisoire à [
/legal/privacy](https://mvp-mlk1.vercel.app/legal/privacy) — version légale définitive dans quelques semaines (déclaration CNDP + review juridique en cours). - 🐛 Un bug corrigé : le bouton "Voir les prestataires" depuis la page d'accueil vous dirigeait vers une page qui nécessitait une connexion. Il vous amène maintenant directement à l'annuaire public.
- 🧪 30+ tests automatiques créés pour vérifier que les fonctionnalités actuelles ne cassent pas quand on ajoute du nouveau code.
- Version 0.1.024 avril 2026(morning session)
Zéro changement visible pour les utilisateurs du site. C'est une journée "infrastructure" :
- ⚙️ Toute la journée à organiser le code, installer les outils de qualité, et écrire la documentation qui permet à l'IA d'assister le développement sans casser de fonctionnalités.
- 🧪 Un système de contrôles automatiques qui vérifie à chaque modification du code : syntaxe correcte, sécurité, formatage, aucune fuite de secret, parcours utilisateurs toujours fonctionnels.