# Avancement — advmfr-next

> Mise à jour : 2026-05-29. Suivi : ✅ fait · 🔧 à fixer / décision en attente · ⚠️ impasse / raccourci / dette.

## État des branches

- `dev` (intégration) : SEO (3 strates) + Hero + section Heritage **mergés**. En avance sur `origin/dev` (non poussé — push sur demande).
- `feat/swiperjs` : slider version `<img>` (fallback) — **non mergé**, encore sur 5 slides placeholder.
- `feat/swiperjs-next-image` : slider version `next/image` + 14 vraies images + fixes CSS — **non mergé**, branche courante.

## ✅ Fait

### SEO (mergé dans dev — voir specs/plans dans docs/superpowers)

- Modules `src/config/seo/` (meta, robots, ai, structured-data, index façade).
- `robots.txt` via Route Handler (posture AI : training bloqué / citation autorisé, `noai`/`noimageai`, `Content-Signal`).
- `manifest.ts`, viewport (`viewport-fit=cover`, theme-color, color-scheme).
- Headers sécurité (`next.config` : Referrer-Policy, Permissions-Policy, X-Robots-Tag noimageai).
- JSON-LD par page (Organization, WebSite, WebPage, AboutPage, ContactPage, ImageGallery, BreadcrumbList) + home & pathnames.
- `ai-disclosure="none"`, images dans le sitemap (gallery).
- Migration namespace i18n : clés SEO sous `<Page>.seo` (en/fr synchronisés).

### Hero (mergé)

- Texte + ALT i18n (en/fr), ALT descriptif, `<section aria-labelledby>`, flèche décorative `aria-hidden`.
- CTAs réels (Link locale-aware → /contact-us, /production-process), empilés un par ligne en mobile.
- Couleurs de marque (primaire charcoal→teal, secondaire bordure acier), `priority` sur l'image LCP.
- Image responsive (`sizes`, `object-position` par breakpoint) + décalée sous la navbar fixe (`top-16`).

### Section Heritage (mergé)

- Layout responsive 2 colonnes (gabarit `feature.tsx`), contenu i18n en/fr.
- Style marque (overline / serif / CTA) + cadre image « structural line work » teal.

### Section Slider Swiper (sur feat/swiperjs-next-image)

- Effet « expo » (uiinitiative) copié en local, Swiper 12 (install via `sfw`), `optimizePackageImports`.
- Server-first : wrapper Server Component + island client.
- 14 vraies images `public/home/slider/`, `next/image` (fill + sizes) avec override `!important` pour préserver l'effet.
- Dimensionnement `aspect-video` (16/9) + radius responsive 16/32 (réglages repris du `main.css` de la démo).
- **Arrondi corrigé sur toutes les slides** : `transform-style: flat` (le contexte 3D cassait le clipping `overflow+radius` des images transformées).
- **Arrondi du slide actif (coin droit) corrigé** : `max-width/max-height: none !important` sur `.expo-image`. Cause = `next/image (fill)` (`inset:0` inline) + Preflight Tailwind (`img{max-width:100%}`) clampaient l'image à 100% au lieu de 125% (`--expo-image-offset`) → elle ne couvrait que la gauche, le coin droit clippait du vide. Diagnostic via devtools (playwright headless).
- **Migration vers `swiper/react`** (`<Swiper>/<SwiperSlide>`, install officielle) à la place de l'init manuelle `new Swiper()`. Param custom `expoEffect` posé via `onBeforeInit` (sinon fuit sur le DOM → warning React). Styling du conteneur (radius, overflow, taille, `transform-style:flat`) passé en classes Tailwind.
- **Autoplay + loop + transitions très lentes** : `loop:true`, `speed:2500` (glissement lent, pacing cinématique), `autoplay { delay:4000, disableOnInteraction:false, pauseOnMouseEnter:true }`. Vérifié : autoplay actif, index avance seul.

## 🔧 À fixer / décisions en attente

- **Choix de la branche slider** : `feat/swiperjs-next-image` (next/image, validée visuellement, arrondi OK) vs `feat/swiperjs` (`<img>`). Décision attendue → merger l'une, supprimer l'autre. Si next/image retenue : reporter les 14 images n'est pas nécessaire (déjà là) ; supprimer `feat/swiperjs`.
- **Fond du slider** : actuellement `bg-black` (mis pour inspection). Choisir le fond final (blanc demandé initialement).
- **Hauteur slider grand écran** : `aspect-video` plein cadre devient très haut sur desktop large — à valider / éventuellement contraindre (max-w ou aspect différent).
- **« Même écart » autour du slide central** : vertical = `--expo-padding` (auto, ~scale), horizontal = `spaceBetween` — pas numériquement égaux par construction ; à valider visuellement ou ajuster.
- **Tactile mobile (« le swipe foire ») — NON reproduit / NON confirmé** : signalé par l'utilisateur sur vrai téléphone. En headless desktop tout marche (swipe synthétique PointerEvent `touch` OK, `touch-action:pan-y` correct, module d'effet identique au dist officiel). La migration `swiper/react` est le correctif le plus probable (cycle de vie/init) → **à retester sur device**. Si KO : symptôme exact à préciser. Piste suivante : le module force `perspective:true` (contexte 3D) alors que `rotate:0` n'en a pas besoin ; le hit-testing 3D peut diverger sur mobile.
- **Cadence autoplay à valider** : `speed:2500` / `delay:4000` posés par défaut « cinématique » — ajuster si trop/pas assez lent.
- Push de `dev` vers `origin` (sur demande). Merge `dev`→`main` : jamais sans demande explicite.

## ⚠️ Impasses / raccourcis / incomplet

- **Image Heritage = placeholder** (`white-gold-set…webp`) → remplacer par la photo du bâtiment (`TODO(asset)` dans `HeritageSection.tsx`). ALT i18n déjà prêt.
- **Slider `<img>` (feat/swiperjs)** : encore 5 slides placeholder, pas les 14 vraies images (seule la branche next/image les a).
- **ALT slider générique** : même ALT i18n sur les 14 images (pas d'alt par visuel) — à enrichir si SEO image important.
- **next/image + effet expo = exception documentée** : l'effet pilote l'`<img>` via CSS vars ; on bat les styles inline de next/image avec `!important` sur `.expo-image`. Fragile si Swiper ou next/image changent leur rendu interne. (Dérogation à la règle next/image « non négociable », validée par l'utilisateur.)
- **Captions slider retirées** (image-only) : pas de légendes par slide.
- **Effet expo : `rotate` figé à 0** (cohérent brand + nécessaire au fix `transform-style: flat`). Réactiver la rotation 3D casserait le clipping arrondi.
- **`ai-disclosure="none"`** suppose un contenu 100 % humain — à revoir quand le vrai contenu (non lorem) sera en place ; surcharger par page si IA utilisée.
- **Copie Hero (sous-titre)** = brouillon à valider ; **captions/anciennes copies** parfois lorem.
- **SEO strate 3 stubs** : `llms.txt`, C2PA, fediverse/Bluesky **non implémentés** (documentés dans `docs/seo/future-tags.md`, à réévaluer ~sept. 2026).
- **Lint** : quelques warnings pré-existants hors périmètre (`pathnames/page.tsx`, `error.tsx` : `no-unstable-nested-components`).
- **Working tree** : assets `public/` modifiés par l'utilisateur (favicons ajoutés, SVG par défaut supprimés), `src/config/site.ts` — non committés, hors de mes commits.

## Vérification

- `bun run lint` à chaque itération ; `bun run build` en vérif finale (cf. mémoire workflow).
- Slider validé visuellement via devtools (proportions, arrondi) ; effet interactif (parallax/grayscale) à juger dans le navigateur.

---

# Blog MDX (mergé dans `dev`)

## ✅ Fait

- **Moteur blog** (`feat/mdx-blog`) : `next-mdx-remote/rsc` + `gray-matter` + Zod (frontmatter validé), contenu `content/blog/<id>/{en,fr}.mdx`, RSC (0 JS client pour le contenu). Bilingue strict (build throw si une locale manque). Catégories en config TS unique extensible (`src/config/blog/categories.ts`, 6 cat., slugs localisés sans collision). URLs articles `/{locale}/{cat}/{slug}` (`as-needed`), `dynamicParams=false`. Reading-time, auteur+bio, articles liés, route files `loading/error/not-found`, garde-fou anti-collision (`guard.ts`). RSS par locale (`/feed.xml`, `/fr/feed.xml`) + discovery, sitemap + hreflang, BlogPosting/Breadcrumb JSON-LD, OG `type=article`. 1 paire d'articles **seed** (sourcing EN/FR).
- **Index + recherche + breadcrumb** (`feat/blog-index-search`) : page unique `/{locale}/blog` (Fuse.js fuzzy + filtre catégories + deep-link `?category=`), suppression des 6 index catégorie (URLs articles conservées, `/{cat}` → 404), breadcrumbs visibles (shadcn/base-ui + next-intl) sur index + articles, sitemap `/blog` (hreflang). Fix a11y `breadcrumb.tsx` (`role=link` retiré).
- **Audit SEO + correctifs** (`fix/blog-seo`) : `/blog` passe par `buildPageMetadata` (OG/twitter/robots/AI/keywords + feed-discovery RSS) ; article : ajout `og:site_name`/`og:locale`/`alternateLocale` + `robots`/AI meta + `twitter:image` ; lien `/blog` ajouté à la nav (découvrabilité). `buildPageMetadata` : `keywords` rendu optionnel. Vérifié dans le HTML prérendu.

## ✅ Fait — optionnels SEO (#6/#7/#8)

- **#6 copy SEO `/blog`** : `BlogPage.seo` (titre/metaDesc/keywords) distinct du H1 (« Blog » reste le H1) — `<title>` = « Fine Jewellery Manufacturing — Guides & Insights ».
- **#7 JSON-LD `/blog`** : `WebPage` → **`Blog`** (`blogJsonLd`, avec `blogPost[]`).
- **#8 hygiène titres MDX** : `mdx-components` mappe `h1`→`<h2>` (un `#` dans un corps ne crée plus de 2ᵉ `<h1>`).

## 🔧 À fixer / options (blog)

- **Nav chargée** : 7 items + langue + CTA → barre desktop serrée ; à arbitrer au passage design (footer ? menu condensé ?).
- **Contenu** : nourrir les 4 clusters (`_project/blog-plan/`) — 1 seul article seed pour l'instant.
- **Passe design** des pages blog (index, cartes, layout article, breadcrumb) — non encore stylée finement.
