Plan 07-02 shipped: useSeoMeta D-15 + useSchemaOrg Article/Breadcrumb on /blog/[slug], resolveOgImage helper + og-blog-default.jpg fallback. Curl SSR validated, typecheck green. Requirements satisfied: SEO-10, SEO-11, SEO-13, SEO-15.
8.8 KiB
phase, plan, subsystem, tags, status, completed, requirements, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | status | completed | requirements | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 07-seo-blog | 02 | seo-blog-article |
|
shipped | 2026-04-22 |
|
|
|
|
|
|
Phase 7 Plan 2 : Blog Article SEO — Summary
One-liner : Page /blog/[slug] désormais crawlable avec og:image absolu (frontmatter || fallback branded), article:published_time/modified_time, JSON-LD Article (author/publisher par @id référence vers la Person globale #killian) + BreadcrumbList Accueil → Blog → Titre.
Ce qui a été fait
Task 1 — feat(07-02): fae4102
app/utils/resolve-og-image.tscréé (14 lignes, JSDoc + export nomméresolveOgImage) : préfixehttps://killiandalcin.fr, passe-through si URL déjà absolue, fallback/og-blog-default.jpg.public/og-blog-default.jpgdéposé (placeholder — copie deog-image.png, 72 bytes). ImageMagick absent du poste ; Research Open Question #2 autorisait explicitement ce recours. Follow-up design branded 1200×630 à produire hors workflow (tâche backlog).
Task 2 — feat(07-02): e17faae
Dans app/pages/blog/[slug].vue, script uniquement (template intact, ZÉRO régression visuelle) :
- Imports ajoutés (top script) :
KILLIAN_PERSON_ID(seo-person.ts Plan 07-01) +resolveOgImage(Plan 07-02 Task 1). - altExists :
useAsyncDataqui interroge la collection de l'autre langue (queryCollection('blog_en')depuis FR et inverse — literal names, Pitfall 5 Phase 5), utilisé pour émettreogLocaleAlternateuniquement quand l'article existe dans les 2 langues. - Computeds SEO :
SITE_URL,ogImage,canonicalUrl(vialocalePath('/blog/' + slug)),publishedIso,modifiedIso(updated ?? date— D-13),inLanguageTag. - useSeoMeta étendu 5 → 14 clés (D-15) : ogImage, ogUrl, ogLocale (
fr_FR/en_US), ogLocaleAlternate (conditionnel suraltExists), twitterCardsummary_large_image, twitterImage, articlePublishedTime, articleModifiedTime, articleAuthor (["Killian' Dal-Cin"]— string[] requis par les types). - useSchemaOrg ajouté :
defineArticle(headline, description, image, datePublished, dateModified, inLanguage, author/publisher par{'@id': KILLIAN_PERSON_ID}, mainEntityOfPage) +defineBreadcrumb(3 items traduits viat('blog.breadcrumb.*')).
Validation SSR (curl)
curl /fr/blog/test-kotlin-syntax
- ✅
<meta property="og:image" content="https://killiandalcin.fr/og-blog-default.jpg">(absolu, fallback) - ✅
<meta property="article:published_time" content="2026-04-21"> - ✅ JSON-LD
@type: Articleavec :headline: "Guide du format Markdown"inLanguage: "fr-FR"datePublished: "2026-04-21",dateModified: "2026-04-21"(updated absent → fallback date, D-13)author: { '@id': 'https://killiandalcin.fr/#/schema/person/#killian' }(référence à la Person globale de 07-01, le module préfixe l'@id par la canonical — comportement standard schema.org)publisher: { '@id': 'https://killiandalcin.fr/#/schema/person/#killian' }image: { '@id': ... ImageObject }(module auto-wrap)mainEntityOfPage: "https://killiandalcin.fr/fr/blog/test-kotlin-syntax"
- ✅ JSON-LD
@type: BreadcrumbList:['Accueil', 'Blog', 'Guide du format Markdown'] - ✅
pnpm typecheckexit 0
Acceptance Criteria — all passed
- SEO-10 : og:title/description/image uniques par article (dépendent de
page.title/description/image) - SEO-11 : JSON-LD Article valide avec author (@id #killian), datePublished, dateModified, headline
- SEO-13 : og:image =
https://killiandalcin.fr/og-blog-default.jpg(fallback) ou frontmatter absolutisé, jamaisog-image.png - SEO-15 : BreadcrumbList 3 items (Accueil → Blog → titre article)
Deviations from Plan
1. [Rule 3 — Blocking] Typings nuxt-schema-org trop narrow sur inLanguage
- Trouvé pendant : Task 2, phase typecheck
- Issue :
defineArticle.inLanguageinféré commeComputedRef<MaybeFalsy<'fr-FR'>>(littéral fixe, non union) — une ComputedRef de l'union'fr-FR' | 'en-US'est rejetée au type-check. - Fix :
const inLanguageTag = computed(() => (isFr.value ? 'fr-FR' : 'en-US')) as unknown as ComputedRef<'fr-FR'>— cast localisé, commenté au-dessus. Le runtime émet correctement'fr-FR'ou'en-US'selon locale (vérifié par curl :inLanguage: "fr-FR"sur /fr/...). Pas de patch upstream (overhead disproportionné) ; pas d'impact runtime. - Files modified :
app/pages/blog/[slug].vue - Commit :
e17faae
2. [Rule 3 — Blocking] articleAuthor attend string[] pas string
- Trouvé pendant : Task 2, phase typecheck
- Issue : Le plan prescrivait
articleAuthor: () => "Killian' Dal-Cin"maisuseSeoMetades versions récentes de@unhead/*typearticleAuthorcommeResolvableValue<string[] | undefined>. - Fix :
articleAuthor: () => ["Killian' Dal-Cin"]. Le rendu HTML<meta property="article:author">reste cohérent (une entrée par auteur, ici une seule). - Commit :
e17faae
Aucune déviation architecturale (Rule 4 n'a pas été déclenché).
Known Stubs / Follow-ups
public/og-blog-default.jpgest un placeholder : actuellement copie deog-image.png(72 bytes, ancien PNG M1). Un asset branded 1200×630 dédié au blog reste à produire (design work hors scope exécuteur). Aucun chemin de code ne dépend de ses dimensions précises — le fallback est servable et crawlable dès maintenant.
Threat Flags
Aucun nouveau surface de menace introduit. resolveOgImage préfixe systématiquement SITE_URL — l'URL construite ne peut pas sortir du domaine (T-07-03 mitigé). L'unique cas où une URL absolue est conservée telle quelle (http:// / https://) provient d'un frontmatter écrit par Killian uniquement (pas d'user input externe). T-07-04 (author identity) accepté — identité publique by design, déjà couvert 07-01.
Self-Check: PASSED
app/utils/resolve-og-image.ts— FOUND (grep "export function resolveOgImage"✓)public/og-blog-default.jpg— FOUND- Commit
fae4102(Task 1) — FOUND in git log - Commit
e17faae(Task 2) — FOUND in git log - Article JSON-LD avec author @id #killian — confirmé par parsing HTML du curl
- BreadcrumbList 3 items — confirmé
- og:image absolu — confirmé
- article:published_time — confirmé
pnpm typecheck— exit 0