diff --git a/.planning/phases/08-content-cocon-semantique/08-CONTEXT.md b/.planning/phases/08-content-cocon-semantique/08-CONTEXT.md new file mode 100644 index 0000000..13b6453 --- /dev/null +++ b/.planning/phases/08-content-cocon-semantique/08-CONTEXT.md @@ -0,0 +1,134 @@ +# Phase 8: Content & Cocon Sémantique - Context + +**Gathered:** 2026-04-22 +**Status:** Ready for planning + + +## Phase Boundary + +Publier le blog Hytale avec 2 articles seed complets (FR+EN, `draft: false`) et établir le cocon sémantique bidirectionnel entre `/blog` et `/hytale` : chaque article seed contient des liens internes inline vers `/hytale`, et la page `/hytale` affiche une section "Articles récents" qui query dynamiquement les 2 plus récents articles tagués `hytale`. + +**Hors scope :** +- Plus de 2 articles (backlog éditorial continu, pas une phase) +- og:image dynamique via Satori (déferré Phase 7, toujours hors scope) +- Refonte SEO autres pages +- Analytics / tracking de conversion sur les CTA +- RSS feed (peut surgir plus tard si trafic le justifie) + + + +## Implementation Decisions + +### Sujets des 2 articles seed +- **D-01:** Article 1 — `how-to-build-your-first-hytale-plugin` (tutorial débutant, 800-1500 mots, intent transactionnel-info, convertit vers `/hytale` commission). +- **D-02:** Article 2 — `hytale-plugin-development-2026` (positionnement/autorité, état de l'art 2026, stack, outlook — capte trafic info long-tail). +- **D-03:** Slugs FR et EN identiques (convention Phase 5/6/7 maintenue) pour que les hreflang alternates fonctionnent côté sitemap (Phase 7 D-11). Le titre/contenu est localisé, le slug reste technique anglais (simplifie le matching bilingue et évite les caractères accentués dans les URLs). + +### Rédaction +- **D-04:** Claude rédige les 2 articles **complets en FR ET EN**, `draft: false`, prêts à publier. Minimum 800 mots, cible 1200-1500. +- **D-05:** Chaque article contient au moins 1 bloc de code Kotlin réaliste (le rendu Shiki est déjà shippé Phase 5). Pas d'image obligatoire dans le corps à cette phase — un frontmatter `image:` facultatif pointant vers un asset existant de `public/` OU absent (fallback `/og-blog-default.jpg` Phase 7 D-05 s'applique). Pas de nouveau travail design dans cette phase. +- **D-06:** Frontmatter obligatoire par article : `title`, `description`, `date` (ISO), `tags: ['hytale', ...]` (le tag `hytale` est obligatoire sur les 2 seeds pour alimenter le filtre de la section `/hytale`), `draft: false`. Champ `updated` omis à la publication initiale. +- **D-07:** Ton éditorial : première personne, concret, technique mais accessible — cohérent avec la voix portfolio Killian (dev full-stack 7 ans, auto-entrepreneur, pas corporate). + +### Liens internes article → /hytale +- **D-08:** Stratégie **inline dans la prose** uniquement (pas de composant CTA block). 1 à 2 liens markdown `[commissioner un plugin Hytale](/hytale)` ou équivalent locale-aware par article, anchor text naturel SEO-friendly. Le lien DOIT pointer vers `/hytale` en FR et `/en/hytale` en EN (respecter la strategy `prefix` i18n). +- **D-09:** Dans l'article EN, lien `/en/hytale` ; dans l'article FR, lien `/hytale` (le prefix par défaut FR est vide). Ne PAS utiliser `localePath()` côté markdown — écrire les paths en dur car `@nuxt/content` ne wrappe pas les liens markdown avec le router i18n (vérifier comportement `` auto-conversion dans ProseA — si comportement attendu, simplifier). + +### Section "Articles récents" sur /hytale +- **D-10:** Composant `HytaleRecentArticles.vue` auto-importé, inséré dans `app/pages/hytale/index.vue` (ou chemin équivalent — à vérifier au planning). Section ajoutée en bas de page, avant le footer-CTA existant. +- **D-11:** Query : `queryCollection('blog_fr' | 'blog_en')` (branches littérales — Pitfall Phase 5 D-03) avec `.where('draft', '=', false)`, `.where('tags', 'LIKE', '%hytale%')` OU filtre JS post-query sur `article.tags?.includes('hytale')` si l'opérateur SQLite LIKE sur champ JSON n'est pas fiable — au planning de trancher. `.order('date', 'DESC')`. `.limit(2)`. +- **D-12:** Si moins de 2 articles tagués `hytale` existent → la section entière est masquée (`v-if="recent.length"`). Pas d'empty state — comportement "progressive enhancement" du cocon. +- **D-13:** Affichage : réutilise `BlogCard.vue` variant `compact` (créé Phase 6-02) en grid 2 colonnes desktop / 1 colonne mobile. Titre de section i18n-ready (`hytale.recentArticles.title` + `.subtitle` si besoin) — ajouter clés FR/EN. +- **D-14:** i18n keys à ajouter dans `app/locales/fr.json` + `en.json` : `hytale.recentArticles.title`, `hytale.recentArticles.subtitle` (optionnel), `hytale.recentArticles.viewAll` (lien "Voir tous les articles" → `/blog` / `/en/blog`). + +### Tags taxonomy +- **D-15:** Les articles seed utilisent au minimum `['hytale']`. Tags secondaires libres (ex: `['hytale', 'tutorial', 'kotlin']` pour article 1, `['hytale', 'industry', 'analysis']` pour article 2). Pas de page `/blog/tags/[tag]` dans cette phase (backlog). + +### Claude's Discretion +- Formulation exacte des titres finaux FR et EN (dérivés des slugs de travail D-01/D-02) +- Choix et placement précis des 1-2 liens `/hytale` inline dans chaque article (dépend du flow rédactionnel) +- Frontmatter `image:` optionnel par article — si un asset pertinent existe déjà dans `public/`, l'utiliser ; sinon laisser vide (fallback Phase 7 prend le relai) +- Choix entre filtre SQL `LIKE` vs filtre JS post-query pour le tag `hytale` (dépend du comportement runtime de `@nuxt/content` v3 sur les champs array — testable au planning) +- Copy exacte de la section "Articles récents" sur `/hytale` (titre + sous-titre) + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### Specs Phase 8 — sources internes +- `.planning/REQUIREMENTS.md` §BLOG-07, §SEO-14 +- `.planning/ROADMAP.md` §"Phase 8: Content & Cocon Semantique" — 4 Success Criteria + +### Décisions héritées +- `.planning/phases/05-nuxt-content-setup-renderer/05-CONTEXT.md` — schémas Zod blog_fr/blog_en, convention slugs bilingues identiques, Pitfall `queryCollection(variable)` vs littéraux +- `.planning/phases/06-blog-pages/06-CONTEXT.md` — BlogCard variants (default + compact), conventions listing +- `.planning/phases/06-blog-pages/06-02-SUMMARY.md` — BlogCard.vue (compact variant spec, slug derivation via `article.path.split`) +- `.planning/phases/07-seo-blog/07-CONTEXT.md` — frontmatter `image:` optional dans schema (D-14 Phase 7), og:image fallback stratégie + +### Code existant +- `app/pages/hytale/index.vue` (ou chemin actuel de la page Hytale — à vérifier au planning) — y insérer le nouveau composant +- `app/components/BlogCard.vue` — variant `compact` réutilisable +- `app/pages/blog/index.vue` — pattern `queryCollection` page-level (non-event) +- `content.config.ts` — schema blog_fr/blog_en (pas d'extension requise Phase 8) +- `content/fr/blog/`, `content/en/blog/` — dossiers cibles pour les 2 nouveaux articles +- `app/locales/fr.json`, `app/locales/en.json` — i18n keys à étendre (section `hytale.recentArticles.*`) + +### Docs externes +- `@nuxt/content` v3 queryCollection filter API (tags / array fields) : https://content.nuxt.com/docs/utils/query-collection +- Schema.org `BlogPosting` interlinking (hreflang déjà géré Phase 7) + + + +## Existing Code Insights + +### Reusable Assets +- `BlogCard.vue` variant `compact` — déjà spec'é Phase 6-02, auto-importé +- `queryCollection` avec littéraux (Pitfall Phase 5) — pattern éprouvé sur `app/pages/blog/index.vue` +- `useAsyncData({ watch: [locale] })` + key `hytale-recent-${locale.value}` — invalidation SSR/switch langue +- i18n keys déjà structurées par scope (`blog.*`, `hytale.*`, `nav.*`) — ajouter `hytale.recentArticles.*` cohérent + +### Established Patterns +- Articles markdown dans `content/fr/blog/*.md` et `content/en/blog/*.md` — convention slug identique +- Frontmatter Zod validé (Phase 5 + Phase 7 D-14) — les champs supplémentaires non déclarés sont strippés +- Blocs code Kotlin rendus par Shiki single theme github-dark (Phase 5) +- Tag `hytale` n'existe pas encore dans le contenu réel (articles seed = première instance) + +### Integration Points +- `app/pages/hytale/index.vue` : injecter `` (composant auto-importé) à la position décidée au planning (probablement avant la dernière section CTA) +- `content/fr/blog/how-to-build-your-first-hytale-plugin.md` + EN : nouveaux fichiers +- `content/fr/blog/hytale-plugin-development-2026.md` + EN : nouveaux fichiers +- `app/components/HytaleRecentArticles.vue` : nouveau composant +- `app/locales/fr.json` + `en.json` : ajouter clés `hytale.recentArticles.*` + +### Sitemap / SEO (déjà géré Phase 7) +- Les 2 nouveaux articles apparaîtront automatiquement dans `/sitemap.xml` via l'endpoint `/api/__sitemap__/urls` avec alternates hreflang (confirmé Phase 7 D-11) — **aucune action spécifique requise**. Tester curl en verification. +- og:image fallback `/og-blog-default.jpg` s'appliquera automatiquement si frontmatter `image:` absent (Phase 7 D-05/D-06). +- JSON-LD Article auto-émis par `app/pages/blog/[slug].vue` (Phase 7 D-02). + + + +## Specific Ideas + +- Les articles seed sont la première démonstration publique de l'expertise Hytale de Killian — qualité éditoriale > quantité. Chaque article DOIT avoir au moins 1 bloc code Kotlin réaliste (pas pseudo-code). +- Success criteria ROADMAP §3 : "La page `/hytale` affiche une section Articles récents avec liens vers les 2 articles seed" — validation curl + DOM structuré. +- Success criteria ROADMAP §2 : "Chaque article blog contient au moins un lien interne vers `/hytale` dans le corps du texte" — grep `/hytale` dans le markdown final. +- Les articles doivent survivre au `pnpm typecheck` + SSR curl — un frontmatter cassé ou un bloc markdown mal formé sera rattrapé par le Zod schema. + + + +## Deferred Ideas + +- **Plus de 2 articles / backlog éditorial** — pipeline continu, pas une phase. Ajouter au backlog. +- **Page `/blog/tags/[tag]`** — intéressant pour le SEO long-tail mais pas nécessaire tant qu'on a <10 articles. Backlog. +- **CTA block ``** (rejeté D-08) — reconsidérer si les analytics montrent que les liens inline ne convertissent pas. +- **RSS feed** — à envisager si audience organique > 500 sessions/mois sur `/blog`. +- **Articles avec images custom** — les 2 seeds shippent sans image dédiée (fallback og suffit). Design backlog. +- **Analytics / conversion tracking sur les liens inline** — hors scope SEO-14, relève d'une phase Analytics ultérieure. + + +--- + +*Phase: 08-content-cocon-semantique* +*Context gathered: 2026-04-22*