c32e44d0e8
M1.1 complete (phases 5-8, 13 plans): - @nuxt/content v3 + Shiki syntax highlighting - Blog listing + article pages SSR bilingue (TOC + prev/next) - JSON-LD Article/Breadcrumb/CollectionPage + sitemap hreflang x-default - 2 articles seed Hytale FR+EN (API Java réelle) - Cocon sémantique /blog ↔ /hytale
102 lines
6.1 KiB
Markdown
102 lines
6.1 KiB
Markdown
# Milestone v1.1: SEO Hytale — Autorité & Contenu
|
||
|
||
**Status:** ✅ SHIPPED 2026-04-22
|
||
**Phases:** 5–8
|
||
**Total Plans:** 13 (2 + 4 + 4 + 3)
|
||
|
||
## Overview
|
||
|
||
Construction d'un blog markdown bilingue complet (@nuxt/content v3) avec SEO de niveau production — JSON-LD Article/Breadcrumb/CollectionPage, sitemap dynamique avec hreflang x-default, og:image résolu par article — et cocon sémantique bidirectionnel entre `/blog` et `/hytale` via 2 articles seed Hytale.
|
||
|
||
## Phases
|
||
|
||
### Phase 5: @nuxt/content Setup & Renderer
|
||
|
||
**Goal:** Système de contenu markdown installé et rend fidèlement le contenu technique — blocs de code colorés, images optimisées, tables, alerts.
|
||
**Depends on:** Phase 4 (M1 complete)
|
||
**Requirements:** BLOG-01, BLOG-04, BLOG-05
|
||
**Plans:** 2 plans
|
||
|
||
- [x] 05-01: Installation @nuxt/content, configuration Shiki github-dark, content.config.ts collections bilingues
|
||
- [x] 05-02: Composants MDC (ProseImg, Alert, ProsePre, Columns, Details, Badge, Video, Clear), articles de test FR/EN
|
||
|
||
**Key decisions captured:** queryCollection avec littéraux seulement (pitfall Vite extractor), single-segment `[slug].vue` vs catch-all, Shiki single-theme, `i18n.baseUrl` requis pour useLocaleHead.
|
||
|
||
### Phase 6: Blog Pages
|
||
|
||
**Goal:** Un visiteur navigue /blog, parcourt la liste, ouvre un article, voit sa TOC et navigue prev/next — en SSR FR/EN.
|
||
**Depends on:** Phase 5
|
||
**Requirements:** BLOG-02, BLOG-03, BLOG-06
|
||
**Plans:** 4 plans
|
||
|
||
- [x] 06-01: Content schema Zod (draft/wordCount/minutes) + Nitro hook reading-time + draft:true test articles
|
||
- [x] 06-02: i18n keys blog.*/nav.blog/a11y.blog* + lien Blog AppHeader + BlogCard.vue (default + compact variants)
|
||
- [x] 06-03: Page listing app/pages/blog/index.vue (hero + grid + empty state, SSR bilingue)
|
||
- [x] 06-04: BlogToc.vue + BlogPrevNext.vue + enrichissement [slug].vue (breadcrumb + TOC + surround)
|
||
|
||
**Key decisions captured:** Hook `content:file:afterParse` exige `.optional()` sur schema Zod pour les champs injectés ; derivation slug via `article.path.split('/').pop()` ; cache `.nuxt` + `node_modules/.cache/content` à purger après changement schema.
|
||
|
||
### Phase 7: SEO Blog
|
||
|
||
**Goal:** Chaque page blog indexable avec meta tags complets, JSON-LD Article valide, URLs blog dans sitemap.
|
||
**Depends on:** Phase 6
|
||
**Requirements:** SEO-10, SEO-11, SEO-12, SEO-13, SEO-15
|
||
**Plans:** 4 plans
|
||
|
||
- [x] 07-01: Install nuxt-schema-org + schema `updated` + definePerson/defineWebSite global app.vue + sitemap.sources
|
||
- [x] 07-02: resolveOgImage helper + /og-blog-default.jpg + [slug].vue useSeoMeta D-15 + defineArticle/defineBreadcrumb
|
||
- [x] 07-03: index.vue useSeoMeta D-16 + defineWebPage(CollectionPage) + defineBreadcrumb
|
||
- [x] 07-04: server/api/__sitemap__/urls.ts — Nitro endpoint bilingue, draft filter, hreflang alternates x-default
|
||
|
||
**Key decisions captured:** `queryCollection` en Nitro prend `event` en premier argument (via `@nuxt/content/server` explicit import pour satisfaire vue-tsc) ; `definePerson` global avec @id=#killian réutilisé inline via `{'@id': '#killian'}` ; `articleAuthor` attend `string[]` ; cast local pour `inLanguage` union FR/EN.
|
||
|
||
### Phase 8: Content & Cocon Sémantique
|
||
|
||
**Goal:** 2 articles seed Hytale de qualité + section "Articles récents" sur /hytale + cocon sémantique bidirectionnel.
|
||
**Depends on:** Phase 7
|
||
**Requirements:** BLOG-07, SEO-14
|
||
**Plans:** 3 plans
|
||
|
||
- [x] 08-01: Scaffold HytaleRecentArticles.vue (queryCollection bilingue + filtre JS `tags.includes('hytale')` + limit 2 + v-if hide) + injection hytale.vue + i18n keys
|
||
- [x] 08-02: Article seed "How to build your first Hytale plugin" (FR 1209 / EN 1123 mots, Java/JavaPlugin, manifest.json, Gradle)
|
||
- [x] 08-03: Article seed "Hytale plugin development in 2026" (FR 1468 / EN 1335 mots, early access state, modern Java features)
|
||
|
||
**Key decisions captured:** Filtre JS post-query plutôt que SQL LIKE pour les tags JSON array ; liens `/hytale` hardcoded en markdown (pas de `localePath()` en MDC) ; slugs FR/EN identiques pour hreflang pairing. **Correction post-shipping :** articles initialement rédigés en Kotlin (placeholder), réécrits en Java après fetch hytalemodding.dev + britakee-studios GitBook pour refléter l'API réelle (`com.hypixel.hytale.plugin.JavaPlugin`, constructor `JavaPluginInit`, `manifest.json`, Gradle, Java 25).
|
||
|
||
---
|
||
|
||
## Milestone Summary
|
||
|
||
**Shipped features:**
|
||
- Blog markdown bilingue FR/EN avec @nuxt/content v3 + Shiki syntax highlighting
|
||
- Page listing `/blog` + page article `/blog/[slug]` SSR avec TOC + prev/next
|
||
- SEO complet par article : useSeoMeta enrichi (14 clés), JSON-LD Article + Breadcrumb + CollectionPage, og:image résolu
|
||
- Sitemap dynamique `/api/__sitemap__/urls` avec alternates hreflang fr/en/x-default, drafts filtrés
|
||
- 2 articles seed Hytale publiés (Java API réelle, 2 liens inline /hytale chacun)
|
||
- Section "Articles récents" sur `/hytale` (filtrée tag=hytale, v-if hide si vide)
|
||
- Cocon sémantique bidirectionnel blog ↔ hytale établi
|
||
|
||
**New dependencies added:** `@nuxt/content`, `nuxt-schema-org`
|
||
|
||
**Files created (top-level):**
|
||
- `app/components/BlogCard.vue`, `BlogToc.vue`, `BlogPrevNext.vue`, `HytaleRecentArticles.vue`
|
||
- `app/pages/blog/index.vue`, `app/pages/blog/[slug].vue`
|
||
- `app/utils/seo-person.ts`, `resolve-og-image.ts`
|
||
- `server/api/__sitemap__/urls.ts`
|
||
- `server/plugins/reading-time.ts`
|
||
- `content/fr/blog/` + `content/en/blog/` (4 seed articles)
|
||
- `content.config.ts` (schemas Zod bilingues)
|
||
|
||
**Requirements coverage:** 13/13 — BLOG-01..07, SEO-10..15 tous satisfaits.
|
||
|
||
**Git range:** 31 commits sur les phases 05-08.
|
||
|
||
**Notable learnings:**
|
||
- Nuxt 4 + @nuxt/content + @nuxtjs/i18n : single-segment `[slug].vue` obligatoire (catch-all casse en strategy `prefix`)
|
||
- `queryCollection` dans Nitro nécessite `event` first-arg + import explicite depuis `@nuxt/content/server` pour vue-tsc
|
||
- Schema Zod `.optional()` requis pour que les champs injectés par Nitro hook `content:file:afterParse` soient queryables
|
||
- Recherche API tierce avant rédaction tutoriel : Kotlin assumé pour Hytale → en réalité Java (correction post-shipping documentée)
|
||
|
||
**Archive date:** 2026-04-22
|
||
**Full phase artifacts:** `.planning/phases/05-*` through `.planning/phases/08-*` (preserved)
|