From 23cd32087108030a70f63d60b43f0fb8aa4d8424 Mon Sep 17 00:00:00 2001 From: kayjaydee Date: Wed, 22 Apr 2026 22:24:00 +0200 Subject: [PATCH] =?UTF-8?q?docs(m1.2):=20bootstrap=20milestone=20=E2=80=94?= =?UTF-8?q?=20ship=20to=20prod=20+=20credibility=20gap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PROJECT.md: v1.2 active, why-now, scope resserré (deploy + demos + rebrand) - REQUIREMENTS.md: v1.2 section (DEPLOY-02/03, DEMO-01/02/03, REBRAND-01/02/03, COCON-01) - ROADMAP.md: phases 9 (Deploy), 10 (Demo Plugins), 11 (Rebranding + Cocon) — 6 plans - STATE.md: reset progress 0/6, focus Phase 9, context gotchas M1.1 conservé - MILESTONES.md: M1.1 partielle (Phase 8 carried), M1.2 active Prochaine étape: /gsd-plan-phase 9 Co-Authored-By: Claude Sonnet 4.6 --- .planning/MILESTONES.md | 22 ++++++++++--- .planning/PROJECT.md | 45 +++++++++++++------------ .planning/REQUIREMENTS.md | 31 +++++++++++++++++- .planning/ROADMAP.md | 49 +++++++++++++++++++++++++-- .planning/STATE.md | 69 ++++++++++++++++++++------------------- 5 files changed, 152 insertions(+), 64 deletions(-) diff --git a/.planning/MILESTONES.md b/.planning/MILESTONES.md index 2a45c7d..9d0b80b 100644 --- a/.planning/MILESTONES.md +++ b/.planning/MILESTONES.md @@ -17,9 +17,8 @@ ## M1.1 — SEO Hytale — Autorité & Contenu **Version:** v1.1 -**Completed:** 2026-04-22 -**Phases:** 4 (5–8) -**Plans:** 13 +**Completed:** 2026-04-22 (partial — Phase 8 composant HytaleRecentArticles reporté en M1.2) +**Phases:** 4 (5–8), Plans 17/18 **Archive:** [v1.1-ROADMAP.md](./milestones/v1.1-ROADMAP.md) · [v1.1-REQUIREMENTS.md](./milestones/v1.1-REQUIREMENTS.md) **Delivered:** @@ -28,4 +27,19 @@ - SEO par article : useSeoMeta enrichi, JSON-LD Article/Breadcrumb/CollectionPage, og:image résolu - Sitemap dynamique avec hreflang x-default (endpoint Nitro) - 2 articles seed Hytale publiés FR+EN (API Java réelle `com.hypixel.hytale.plugin`) -- Section "Articles récents" dynamique sur `/hytale` (cocon sémantique bidirectionnel) + +**Carried to M1.2:** Composant HytaleRecentArticles (finalisation cocon sémantique — Phase 11) + +## M1.2 — Ship to Prod + Credibility Gap + +**Version:** v1.2 +**Started:** 2026-04-22 +**Status:** Active +**Phases:** 3 (9–11), Plans: 6 + +**Goal:** Débloquer la prospection active en déployant M1.1 en prod, combler le gap crédibilité (démos plugins open-source), finaliser cohérence branding Hytale. + +**Planned:** +- Phase 9 : Deploy prod via Portainer (M1.1 live sur killiandalcin.fr) +- Phase 10 : 2-3 mini-plugins Hytale open-source (GitHub public + README EN + section Live Demos sur `/hytale`) +- Phase 11 : Fix JSON-LD `index.vue` (REBRAND-01..03) + composant `HytaleRecentArticles` (COCON-01) diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md index de7524c..1e0c205 100644 --- a/.planning/PROJECT.md +++ b/.planning/PROJECT.md @@ -10,23 +10,25 @@ Le portfolio doit positionner Killian comme LE developpeur de plugins Hytale pro ## Current State -**Shipped:** v1.1 (2026-04-22) — SEO Hytale — Autorité & Contenu -- Blog markdown bilingue FR/EN live avec 2 articles seed Hytale (Java API réelle) -- SEO blog complet : JSON-LD Article/Breadcrumb/CollectionPage, sitemap hreflang x-default, og:image résolu -- Cocon sémantique bidirectionnel `/blog` ↔ `/hytale` établi +**Active:** v1.2 (started 2026-04-22) — Ship to Prod + Credibility Gap +- Ship-first : déployer M1.1 en prod (blog/SEO/sitemap pas encore live) +- Combler le gap crédibilité : 2-3 plugins Hytale démo open-source (effet wahou) +- Finaliser cohérence branding : fix JSON-LD homepage, HytaleRecentArticles, audit jobTitle -**Prior milestones:** v1.0 (2026-04-21) — Portfolio Hytale-first SSR déployé. Voir `.planning/milestones/`. +**Shipped:** +- v1.1 (2026-04-22) — SEO Hytale — Autorité & Contenu (blog bilingue, JSON-LD, sitemap hreflang) +- v1.0 (2026-04-21) — Portfolio Hytale-first SSR déployé -## Next Milestone +Voir `.planning/milestones/` pour archives. -*No active milestone.* Candidats identifiés : -- Asset branded `/og-blog-default.jpg` 1200×630 (design) -- Page `/blog/tags/[tag]` (SEO long-tail dès 10+ articles) -- og:image dynamique Satori -- Analytics blog (reading completion, conversions CTA /hytale) -- Pipeline éditorial continu (3-5 articles supplémentaires) +## Why v1.2 Now -Lancer `/gsd-new-milestone` pour définir v1.2. +Le portfolio est prêt techniquement mais : +1. M1.1 n'est pas déployée en prod → SEO Hytale invisible +2. Zéro démo plugin concret à montrer en DM Discord (blocker business #1 selon plan stratégique) +3. Incohérence JSON-LD `index.vue` (encore "Developpeur Full Stack") + +Objectif : débloquer la prospection active (5-10h/sem Discord + DMs) qui vient après. ## Requirements @@ -45,16 +47,13 @@ Lancer `/gsd-new-milestone` pour définir v1.2. - ✓ useSeoMeta() par route avec title, description, og:tags bilingues — existant - ✓ Dockerfile SSR multi-stage node:22-alpine — existant -### Active +### Active (v1.2) -- [ ] Refonte Hero — positionner "Hytale Plugin Developer" en premier plan, pas "Full Stack Developer" -- [ ] Page Hytale dediee — services plugin dev, demos (placeholders), offre maintenance recurrente -- [ ] Section pricing/services — grille tarifaire visible (plugin simple, complexe, sur-mesure, maintenance, web) -- [ ] Temoignages clients — section avis sur page d'accueil et page Hytale -- [ ] Audit et correction i18n — traductions FR/EN completes et naturelles (certaines traductions sont approximatives) -- [ ] Correction concerns codebase — og:image hardcodee, sitemap statique obsolete, email validation serveur, flowboard features non-i18n -- [ ] Page 404 personnalisee — verifier que error.vue fonctionne correctement avec i18n -- [ ] SEO consolide — canonical links, ogUrl par page, og:image dynamique par projet +- [ ] **DEPLOY**: Pull image autobuild Portainer → M1.1 live sur killiandalcin.fr (blog, sitemap, JSON-LD) +- [ ] **DEMO-1**: 2-3 mini-plugins Hytale open-source, simples à coder mais effet wahou (GitHub public + README EN) +- [ ] **DEMO-2**: Section "Live Demos" sur `/hytale` listant les plugins démo (screenshots, lien GitHub, lien code) +- [ ] **REBRAND**: Fix JSON-LD `app/pages/index.vue` (Developpeur Full Stack → Hytale Plugin Developer) + audit cohérence jobTitle toutes pages +- [ ] **COCON**: Composant `HytaleRecentArticles` sur `/hytale` (tire derniers articles blog, renforce maillage interne) ### Out of Scope @@ -103,4 +102,4 @@ Lancer `/gsd-new-milestone` pour définir v1.2. This document evolves at phase transitions and milestone boundaries. --- -*Last updated: 2026-04-10 after initialization* +*Last updated: 2026-04-22 — M1.2 bootstrap* diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 07a7896..1051eaa 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -1,9 +1,38 @@ # Requirements: Portfolio Killian' Dalcin **Defined:** 2026-04-10 -**Updated:** 2026-04-21 (v1.1 added) +**Updated:** 2026-04-22 (v1.2 active) **Core Value:** Positionner Killian comme dev Hytale #1, crawlable sans JS, SEO optimise +--- + +## v1.2 Requirements (M1.2 — Active) — Ship to Prod + Credibility Gap + +**Goal:** Débloquer la prospection active en déployant M1.1 en prod + combler le gap crédibilité (démos plugins) + finaliser cohérence branding. + +### Deploy — Ship M1.1 to Production + +- [ ] **DEPLOY-02**: Pull image autobuild via Portainer sur killiandalcin.fr — M1.1 (blog bilingue, sitemap hreflang, JSON-LD Article) live en prod +- [ ] **DEPLOY-03**: Smoke test prod — vérifier `/blog`, `/blog/{slug}` FR+EN, `/sitemap.xml`, JSON-LD homepage + hytale + article, og:image résolu + +### Demo Plugins — Credibility Gap + +- [ ] **DEMO-01**: 2-3 mini-plugins Hytale open-source publiés sur GitHub — critères : simples à coder (1-3j chacun), effet wahou visuel, poussent Hytale au max de ses capacités. Chaque repo avec README EN pro (installation, features, screenshots/gif). +- [ ] **DEMO-02**: Section "Live Demos" sur `/hytale` — liste les plugins démo avec screenshot/gif, description 1-2 phrases, lien GitHub, tag techno (Java/Kotlin). Composant `HytaleDemoGrid.vue`. +- [ ] **DEMO-03**: Recherche + idéation plugins — choix des 2-3 concepts (brainstorm guidé, critères : feasibility 1-3j, wow factor, showcase API Hytale avancée) + +### Rebranding — Cohérence SEO + +- [ ] **REBRAND-01**: Fix JSON-LD `app/pages/index.vue` lignes 28 + 38 — remplacer "Developpeur Full Stack Freelance" / "Developpeur Full Stack" par "Hytale Plugin Developer" (via `siteConfig.jobTitle`, pas de hardcode) +- [ ] **REBRAND-02**: Audit cohérence jobTitle — grep toutes les pages, composants, i18n FR/EN pour "full stack", "fullstack", "développeur web" → corriger ou justifier +- [ ] **REBRAND-03**: Vérif meta descriptions + og:title toutes pages — homepage, about, contact, projets, fiverr, formation — alignés sur positionnement Hytale + +### Cocon Sémantique — Finalisation M1.1 Phase 8 + +- [ ] **COCON-01**: Composant `HytaleRecentArticles.vue` — affiche les 3 derniers articles blog (tags hytale uniquement) sur `/hytale`, bidirectionnel avec le maillage `/blog` → `/hytale` + +--- + ## v1 Requirements (M1 — Complété 2026-04-21) ### Content diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 0a10977..317ad59 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -178,6 +178,51 @@ Plans: --- -## Next Milestone +## M1.2 — Ship to Prod + Credibility Gap (Active) -*No active milestone — run `/gsd-new-milestone` to define v1.2.* +**Version:** v1.2 +**Started:** 2026-04-22 +**Goal:** Déployer M1.1 en prod + combler le gap crédibilité (démos plugins) + cohérence branding. Débloque la prospection active qui suit. +**Phases:** 3 (9–11) + +### Phase 9: Deploy Production +**Goal**: M1.1 est live sur killiandalcin.fr — blog bilingue, sitemap hreflang, JSON-LD Article accessibles en prod +**Depends on**: M1.1 code en main (already) +**Requirements**: DEPLOY-02, DEPLOY-03 +**Success Criteria** (what must be TRUE): + 1. `curl https://killiandalcin.fr/blog` retourne le listing bilingue SSR + 2. `curl https://killiandalcin.fr/sitemap.xml` contient les URLs `/blog/{slug}` avec hreflang x-default + 3. Les 2 articles seed Hytale sont accessibles FR+EN en prod + 4. JSON-LD homepage + hytale + article rendus correctement (aucune ref "Full Stack" côté prod avant Phase 11) +**Plans:** 1 plan +Plans: +- [ ] 09-01-PLAN.md — Pull image autobuild Portainer + smoke test prod (blog, sitemap, JSON-LD, og:image) + +### Phase 10: Demo Plugins Hytale +**Goal**: 2-3 mini-plugins Hytale open-source publiés sur GitHub avec section "Live Demos" sur `/hytale` — donnent une preuve crédible à montrer en DM Discord +**Depends on**: Phase 9 (pas techniquement, mais prospection = après déploiement) +**Requirements**: DEMO-01, DEMO-02, DEMO-03 +**Success Criteria** (what must be TRUE): + 1. 2-3 repos GitHub publics avec README EN pro (installation, features, screenshot/gif) + 2. Chaque plugin poussé jusqu'à un effet wahou visuel ou gameplay (pas juste "hello world") + 3. Section `/hytale` affiche les démos via composant `HytaleDemoGrid.vue` — card avec screenshot, description, lien GitHub + 4. Tooling build plugin Hytale documenté au moins une fois dans un README (Kotlin ou Java) +**Plans:** 3 plans +Plans: +- [ ] 10-01-PLAN.md — Brainstorm + choix 2-3 concepts plugins (critères : 1-3j de code, wow factor, API Hytale avancée) + spec rapide chaque plugin +- [ ] 10-02-PLAN.md — Code plugins + publish GitHub + README EN (gif/screenshot assets dans public/demos/) +- [ ] 10-03-PLAN.md — Composant `HytaleDemoGrid.vue` + intégration `/hytale` + i18n hytale.demos.* + data source (app/data/hytaleDemos.ts ou frontmatter) + +### Phase 11: Rebranding + Cocon +**Goal**: Zéro ref "Full Stack" dans le code/JSON-LD/meta, jobTitle cohérent partout, `/hytale` affiche les derniers articles blog +**Depends on**: rien (parallélisable avec 10) +**Requirements**: REBRAND-01, REBRAND-02, REBRAND-03, COCON-01 +**Success Criteria** (what must be TRUE): + 1. `grep -rni "full stack\|fullstack" app/ content/ i18n/` retourne 0 match non-justifié + 2. JSON-LD `app/pages/index.vue` utilise `siteConfig.jobTitle` (pas de hardcode) + 3. Meta description + og:title de chaque page (index, about, contact, projets, fiverr, formation) parlent d'Hytale ou positionnement gaming + 4. Section "Articles récents" sur `/hytale` affiche les 3 derniers articles tag "hytale" (FR ou EN selon locale) +**Plans:** 2 plans +Plans: +- [ ] 11-01-PLAN.md — Grep + fix index.vue JSON-LD + audit jobTitle toutes pages + i18n FR/EN cohérence positionnement +- [ ] 11-02-PLAN.md — Composant `HytaleRecentArticles.vue` (queryCollection bilingue, filter tag hytale, limit 3) + injection `/hytale` + i18n hytale.recentArticles.* diff --git a/.planning/STATE.md b/.planning/STATE.md index 14a0da8..debc080 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,16 +1,16 @@ --- gsd_state_version: 1.0 -milestone: v1.0 -milestone_name: milestone -status: Plan 07-04 shipped — endpoint Nitro sitemap bilingue (draft-filtered + hreflang x-default), SEO-12 complet -last_updated: "2026-04-22T16:39:45.338Z" +milestone: v1.2 +milestone_name: Ship to Prod + Credibility Gap +status: M1.2 bootstrapped — 3 phases (9–11), 6 plans, awaiting /gsd-plan-phase 9 +last_updated: "2026-04-22T17:00:00.000Z" last_activity: 2026-04-22 progress: - total_phases: 8 - completed_phases: 5 - total_plans: 18 - completed_plans: 17 - percent: 94 + total_phases: 3 + completed_phases: 0 + total_plans: 6 + completed_plans: 0 + percent: 0 --- # Project State @@ -23,31 +23,32 @@ progress: ## Current Focus -Phase: Phase 7 — SEO Blog -Plan: 07-03 (next — Wave 2, blog index/tags SEO) -Status: Plan 07-04 shipped — endpoint Nitro sitemap bilingue (draft-filtered + hreflang x-default), SEO-12 complet +Milestone: M1.2 — Ship to Prod + Credibility Gap +Phase: Phase 9 — Deploy Production (next) +Plan: 09-01 (to be planned — pull image autobuild Portainer + smoke test prod) +Status: M1.2 bootstrapped — 3 phases (9–11), 6 plans Last activity: 2026-04-22 -Resume file: .planning/phases/07-seo-blog/07-03-PLAN.md +Resume file: lancer `/gsd-plan-phase 9` -## Accumulated Context +## Milestone Context (v1.2) -- M1 complet — déployé en production sur killiandalcin.fr (phases 1–4) -- Stack : Nuxt 4 SSR + Nuxt UI v3 + Tailwind v4 + pnpm + @nuxt/content v3 -- Phase 5 shipped: @nuxt/content installé, collections bilingues `blog_fr`/`blog_en`, composants MDC (ProseImg, Alert, ProsePre, Columns, Details, Badge, Video, Clear), Shiki single github-dark, `app/pages/blog/[slug].vue` rend les articles FR/EN -- **Gotchas Phase 5 (à retenir)** : - - Catch-all `[...slug].vue` + `@nuxtjs/i18n` strategy `prefix` → page component résout à `{}` (Vue warn: missing template). Fix : single-segment `[slug].vue`. - - `queryCollection(variable)` pas analysable par le Vite extractor de @nuxt/content → utiliser toujours des littéraux `queryCollection('blog_fr')` / `queryCollection('blog_en')`. - - `i18n.baseUrl` requis pour `useLocaleHead` (SEO tags). Ne pas retirer. - - Redirection langue-détectée sans langue dans l'URL : `detectBrowserLanguage.redirectOn: 'no prefix'` + `fallbackLocale`. Éviter les `routeRules` `/blog/**` hardcodés (cassent le slug + bloquent la détection navigateur). -- Objectif double : ranker sur "Hytale plugin developer" ET capter trafic longue traîne via contenu communauté -- Articles bilingues : structure FR/EN dans content/ (ex: content/fr/blog/, content/en/blog/) -- og:image par article : image frontmatter ou fallback branded — jamais l'og-image.png générique M1 -- **Plan 06-01 shipped (2026-04-22)** : blogSchema étendu (draft.default(false) + wordCount.optional + minutes.optional), Nitro hook `content:file:afterParse` injecte wordCount+minutes (200 wpm, floor 1 min) sur chaque `.md` via `countWordsInMinimalBody`, composable fallback `useReadingTime(number|string)` auto-importé, articles `test-kotlin-syntax.md` (FR+EN) marqués `draft: true` — exclus des listings `where('draft', '=', false)` mais accessibles par URL directe. Cache `node_modules/.cache/content` + `.nuxt` vidés. -- **Gotcha 06-01** : Le hook `content:file:afterParse` exige que `wordCount`/`minutes` soient déclarés dans le schema Zod (`.optional()` sans default) sinon ils sont strippés avant persistance DB — les propriétés injectées par hook ne sont queryables que si le schema les expose. -- **Gotcha 06-01 (convention)** : Dans un plugin Nitro, importer depuis `app/utils/` se fait via `~/utils/...` (et non `~~/app/utils/...`). Nuxt 4 mappe `~/` → `app/` par défaut. Vérifié par typecheck vert sur server/plugins/reading-time.ts. -- **Plan 06-02 shipped (2026-04-22)** : i18n `nav.blog` + 3 clés `a11y.blog*` (avec interpolation `{title}`) + bloc `blog.*` 14 clés (title, subtitle, stats.*, readingTime, prevArticle/nextArticle, backToBlog, toc.title, emptyState.*, breadcrumb.*) ajoutés dans fr.json + en.json. AppHeader.vue navLinks : `{ key: 'blog', path: '/blog' }` inséré entre hytale et projects (ligne 11, ordre D-15 respecté). `app/components/BlogCard.vue` créé (192 lignes, auto-importé Nuxt) : variant `default` (listing) avec cover conditional + tag UBadge + date Intl.DateTimeFormat + h2 + description line-clamp-2 + reading-time (minutes hook || useReadingTime fallback) + extra tags pills + full-card NuxtLink SEO + Schema.org BlogPosting markup ; variant `compact` (prev/next, D-09/D-10) : no image + label row avec UIcon arrow directionnelle + h3 + date + NuxtLink aria-label interpolé `a11y.blogPrev`/`a11y.blogNext`. Typecheck exit 0. -- **Gotcha 06-02 (slug derivation)** : Les articles @nuxt/content ont un `path` de forme `/fr/blog/my-slug`. Dans BlogCard.vue, on extrait le slug via `article.path.split('/').filter(Boolean).pop()` puis on reconstruit `localePath('/blog/' + slug)` — locale-agnostique. Évite de demander un champ `slug` explicite dans le frontmatter (cohérent convention @nuxt/content : path dérivé du nom de fichier). -- **Plan 07-02 shipped (2026-04-22)** : `app/utils/resolve-og-image.ts` (préfixe https://killiandalcin.fr + fallback /og-blog-default.jpg) + `public/og-blog-default.jpg` (placeholder copié depuis og-image.png — design branded 1200×630 en follow-up backlog) + `app/pages/blog/[slug].vue` enrichi : imports KILLIAN_PERSON_ID+resolveOgImage, useAsyncData altExists (détecte pair bilingue FR/EN), computeds ogImage/canonicalUrl/publishedIso/modifiedIso/inLanguageTag, useSeoMeta étendu 5→14 clés (D-15 complet : ogImage, ogUrl, ogLocale, ogLocaleAlternate conditionnel, twitterCard, twitterImage, articlePublishedTime, articleModifiedTime, articleAuthor string[]), useSchemaOrg([defineArticle {author/publisher @id=#killian}, defineBreadcrumb 3 items]). Curl /fr/blog/{slug} valide : og:image absolu, article:published_time, JSON-LD Article + BreadcrumbList. -- **Plan 07-04 shipped (2026-04-22)** : `server/api/__sitemap__/urls.ts` (76 lignes) — `defineSitemapEventHandler` (auto-import @nuxtjs/sitemap v8) avec `Promise.all([queryCollection(event,'blog_fr'), queryCollection(event,'blog_en')]).where('draft','=',false).order('date','DESC').select('path','date','updated').all()`. Map pour détecter paires bilingues → alternates [fr, en, x-default→FR] si bilingue, sinon []. lastmod = updated ?? date. Validé curl : endpoint JSON valide, sitemap XML multi-sitemap mode (fr-FR.xml + en-US.xml) contient bien les URLs /blog/{slug} avec hreflang x-default, drafts absents. SEO-12 requirement complete. -- **Gotcha 07-04 (queryCollection import)** : `pnpm typecheck` (vue-tsc) ne résout pas l'auto-import Nitro de `queryCollection` dans server/ — il prend la signature client `(collection)` et râle `TS2554 Expected 1, got 2`. Fix : `import { queryCollection } from '@nuxt/content/server'` (même runtime, signature Nitro `(event, collection)` correctement typée). Aussi : `defineSitemapEventHandler` est un auto-import @nuxtjs/sitemap, PAS un export de `#imports` — ne pas importer explicitement. -- **Gotcha 07-02 (typings nuxt-schema-org)** : `defineArticle.inLanguage` inféré `ComputedRef>` (narrow) refuse une union `'fr-FR' | 'en-US'`. Cast localisé `as unknown as ComputedRef<'fr-FR'>` suffit — runtime émet correctement les deux valeurs selon locale. `articleAuthor` de useSeoMeta attend `string[]`, pas `string` (packaging @unhead récent). +- **Why v1.2** : débloquer prospection active (Discord + DMs 5-10h/sem) qui suit. Deploy + démos + cohérence branding. +- **Phase 9** : Deploy prod (Portainer autobuild pull) — M1.1 codée mais pas live +- **Phase 10** : 2-3 mini-plugins Hytale open-source — effet wahou, simple à coder, API Hytale poussée au max. Crédibilité DM Discord. +- **Phase 11** : Fix JSON-LD `index.vue` (Full Stack → Hytale Plugin Developer via siteConfig) + audit cohérence + composant `HytaleRecentArticles` sur `/hytale` + +## Accumulated Context (carried from v1.1) + +- Stack : Nuxt 4 SSR + Nuxt UI v3 + Tailwind v4 + pnpm + @nuxt/content v3 + nuxt-schema-org + @nuxtjs/sitemap v8 +- Deployment : Docker node:22-alpine, Portainer autobuild, pull manuel par Killian côté prod +- Gotchas M1.1 (à retenir pour plans à venir) : + - `queryCollection(variable)` pas analysable par Vite extractor @nuxt/content → toujours littéraux `queryCollection('blog_fr')` + - Dans server/, importer `queryCollection` depuis `@nuxt/content/server` pour vue-tsc (sinon signature client incompatible) + - `defineSitemapEventHandler` = auto-import @nuxtjs/sitemap (pas d'import explicite) + - `defineArticle.inLanguage` typing narrow → cast `as unknown as ComputedRef<'fr-FR'>` + - `useSeoMeta.articleAuthor` attend `string[]` (pas string) + - Hook `content:file:afterParse` : propriétés injectées doivent être déclarées `.optional()` dans le schema Zod + - Imports Nitro plugin : `~/utils/...` (Nuxt 4 `~/` → `app/`) +- Articles seed Hytale en prod : `how-to-build-your-first-hytale-plugin`, `hytale-plugin-development-2026` (FR+EN, draft:false) +- `app/data/site.ts` / `app/pages/hytale.vue` / `app/utils/seo-person.ts` : `jobTitle` = "Hytale Plugin Developer" (aligné) +- `app/pages/index.vue` lignes 28 + 38 : encore "Developpeur Full Stack" (cible REBRAND-01)