Files

7.2 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
07-seo-blog 03 execute 2
07-01
app/pages/blog/index.vue
true
SEO-10
SEO-13
SEO-15
truths artifacts key_links
curl /fr/blog et /en/blog retournent og:image absolu = https://killiandalcin.fr/og-blog-default.jpg
og:locale = fr_FR (ou en_US) et og:locale:alternate = en_US (ou fr_FR) — le listing existe toujours dans les 2 langues
Le HTML contient un JSON-LD @type: CollectionPage (via defineWebPage) pour le listing
Le HTML contient un JSON-LD BreadcrumbList Accueil → Blog
path provides contains
app/pages/blog/index.vue useSeoMeta enrichi (D-16) + useSchemaOrg CollectionPage + Breadcrumb defineWebPage
from to via pattern
app/pages/blog/index.vue app/utils/resolve-og-image.ts import resolveOgImage resolveOgImage
Enrichir la page listing `/blog` avec (a) `useSeoMeta` étendu (D-16 — og:image fallback, og:locale, og:locale:alternate, twitter), et (b) `useSchemaOrg([defineWebPage({ '@type': 'CollectionPage' }), defineBreadcrumb])` (D-03, SEO-15).

Purpose: Le listing doit être partageable socialement (card OG branded) et porter un breadcrumb JSON-LD cohérent avec les articles. Output: 1 page enrichie.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/07-seo-blog/07-CONTEXT.md @.planning/phases/07-seo-blog/07-RESEARCH.md @.planning/phases/07-seo-blog/07-PATTERNS.md @.planning/phases/07-seo-blog/07-01-SUMMARY.md @app/pages/blog/index.vue Depuis `app/pages/blog/index.vue` (existant, à étendre — ne PAS remplacer) : - `const { t, locale } = useI18n()` (ligne 2) - `const localePath = useLocalePath()` (ligne 3) - `const isFr = computed(() => locale.value === 'fr')` (ligne 4) - `useSeoMeta({ title, description, ogTitle, ogDescription, ogType: 'website' })` (lignes 37-43) — à ÉTENDRE

Auto-imports : useSchemaOrg, defineWebPage, defineBreadcrumb.

resolveOgImage(null) retourne https://killiandalcin.fr/og-blog-default.jpg (fallback, D-06).

Note: app/utils/resolve-og-image.ts est créé dans 07-02 (Wave 2, parallèle). Plan 07-03 a DÉJÀ une dépendance implicite (runtime) sur ce fichier : si 07-03 exécute avant 07-02, import { resolveOgImage } échouera. L'exécuteur DOIT lancer 07-02 d'abord OU créer provisoirement le helper ici. Recommandation : exécuteur vérifie test -f app/utils/resolve-og-image.ts et, si absent, utilise la constante littérale const OG_FALLBACK = 'https://killiandalcin.fr/og-blog-default.jpg' en dur dans ce fichier (évite le couplage). Plan 07-02 n'écrit QUE [slug].vue + utils, donc pas de conflit de fichier.

Task 1: Enrichir app/pages/blog/index.vue — useSeoMeta D-16 + useSchemaOrg CollectionPage + Breadcrumb app/pages/blog/index.vue - app/pages/blog/index.vue (fichier entier 1-151) - .planning/phases/07-seo-blog/07-RESEARCH.md §Open Question #1 (CollectionPage via defineWebPage), §useSeoMeta Enrichment - .planning/phases/07-seo-blog/07-PATTERNS.md §index.vue (modify) - .planning/phases/07-seo-blog/07-CONTEXT.md D-03, D-16 Dans `app/pages/blog/index.vue`, zone `<script setup lang="ts">` uniquement.
1. **Import** — tout en haut du script :
   ```ts
   import { resolveOgImage } from '~/utils/resolve-og-image'
   ```

2. **Computeds SEO** — après la constante `totalLanguages = 2` (ligne 34), avant `useSeoMeta` :
   ```ts
   const SITE_URL = 'https://killiandalcin.fr'
   const ogImage = resolveOgImage(null) // fallback absolute URL (D-16)
   const canonicalUrl = computed(() => `${SITE_URL}${localePath('/blog')}`)
   ```

3. **Remplacer** le `useSeoMeta({...})` existant (lignes 37-43) par la version enrichie D-16 :
   ```ts
   useSeoMeta({
     title: () => t('blog.title'),
     description: () => t('blog.subtitle'),
     ogTitle: () => t('blog.title'),
     ogDescription: () => t('blog.subtitle'),
     ogType: 'website',
     ogImage,
     ogUrl: canonicalUrl,
     ogLocale: () => (isFr.value ? 'fr_FR' : 'en_US'),
     ogLocaleAlternate: () => [isFr.value ? 'en_US' : 'fr_FR'],
     twitterCard: 'summary_large_image',
     twitterImage: ogImage,
   })
   ```

4. **Ajouter** après `useSeoMeta(...)` :
   ```ts
   useSchemaOrg([
     defineWebPage({
       '@type': 'CollectionPage',
       name: () => t('blog.title'),
       description: () => t('blog.subtitle'),
       inLanguage: () => (isFr.value ? 'fr-FR' : 'en-US'),
       url: canonicalUrl,
     }),
     defineBreadcrumb({
       itemListElement: [
         { name: () => t('blog.breadcrumb.home'), item: () => localePath('/') },
         { name: () => t('blog.breadcrumb.blog'), item: () => localePath('/blog') },
       ],
     }),
   ])
   ```
   Ne PAS toucher aux computeds `totalArticles`, `uniqueTags`, `totalLanguages`, au `useAsyncData`, ni au `<template>`.
grep -q "defineWebPage" app/pages/blog/index.vue && grep -q "defineBreadcrumb" app/pages/blog/index.vue && grep -q "resolveOgImage" app/pages/blog/index.vue && grep -q "ogLocaleAlternate" app/pages/blog/index.vue && pnpm typecheck && pnpm dev --port 3000 & sleep 12 && curl -s http://localhost:3000/fr/blog | tee /tmp/blog.html | grep -q 'property="og:image".*og-blog-default.jpg' && grep -q '"@type":"CollectionPage"' /tmp/blog.html && grep -q '"@type":"BreadcrumbList"' /tmp/blog.html && curl -s http://localhost:3000/en/blog | grep -q 'property="og:locale" content="en_US"' && kill %1 curl /fr/blog et /en/blog retournent og:image pointant vers og-blog-default.jpg absolu, og:locale correct, JSON-LD CollectionPage + BreadcrumbList. typecheck vert.

<threat_model>

Trust Boundaries

Boundary Description
(aucune nouvelle) Rien de user-input ; i18n strings déjà trustées

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-07-05 Information Disclosure JSON-LD listing (URLs publiques) accept Par design — le listing doit être crawlable
</threat_model>
- og:image listing : `curl /fr/blog | grep 'og-blog-default.jpg'` - og:locale correct : `curl /en/blog | grep 'content="en_US"'` - JSON-LD CollectionPage : `curl /fr/blog | grep '"@type":"CollectionPage"'` - JSON-LD Breadcrumb : `curl /fr/blog | grep '"@type":"BreadcrumbList"'`

<success_criteria>

  1. SEO-10 étendu : og:title, og:description, og:image distincts du site par défaut
  2. SEO-13 : og:image = /og-blog-default.jpg absolu (jamais og-image.png)
  3. SEO-15 : BreadcrumbList Accueil → Blog présent sur le listing </success_criteria>
Après complétion, créer `.planning/phases/07-seo-blog/07-03-SUMMARY.md`.