042a05c3a8
DEPLOY-02 + DEPLOY-03 validés. Build hang résolu via hook close dans nuxt.config.ts (nuxt/nuxt#33987). Next: Phase 10 (démos plugins). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
224 lines
13 KiB
Markdown
224 lines
13 KiB
Markdown
# Roadmap: Portfolio Killian' Dalcin
|
||
|
||
**Milestone:** M1 — Portfolio Hytale-first, SEO-ready, production
|
||
**Granularity:** Coarse
|
||
**Coverage:** 19/19 requirements mapped
|
||
|
||
---
|
||
|
||
## Phases
|
||
|
||
- [x] **Phase 1: Cleanup & Fixes** - Sitemap conflit, Dockerfile pnpm, deps pinning, donnees incoherentes, rate limiting
|
||
- [x] **Phase 2: Content** - Hero Hytale, page Hytale, pricing, temoignages, jobTitle
|
||
- [x] **Phase 3: SEO & i18n** - Canonical, ogUrl, og:image, JSON-LD, audit i18n, traductions
|
||
- [x] **Phase 4: Ship** - Dockerfile final, verification production, deploy
|
||
|
||
---
|
||
|
||
## Phase Details
|
||
|
||
### Phase 1: Cleanup & Fixes
|
||
**Goal**: Le codebase est propre — pas de conflits de config, deps pinees, contact form protege, donnees coherentes
|
||
**Depends on**: Nothing
|
||
**Requirements**: FIX-01, FIX-02, FIX-03, FIX-04, FIX-05, DEPLOY-01
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `public/sitemap.xml` supprime — `curl localhost:3000/sitemap.xml` retourne le sitemap dynamique genere par `@nuxtjs/sitemap`
|
||
2. `Dockerfile` utilise `pnpm install --frozen-lockfile` — `docker build` reussit sans npm
|
||
3. `package.json` ne contient ni `"latest"` ni `"*"` dans les deps
|
||
4. `siteConfig.seo.organization.aggregateRating.reviewCount` correspond a `testimonials.totalReviews`
|
||
5. 10 requetes POST rapides sur `/api/contact` → les dernieres sont rejetees (rate limit)
|
||
**Plans:** 2 plans
|
||
Plans:
|
||
- [ ] 01-01-PLAN.md — Delete static sitemap, pin deps, fix data inconsistencies
|
||
- [ ] 01-02-PLAN.md — Migrate Dockerfile to pnpm, add contact API rate limiting
|
||
|
||
### Phase 2: Content
|
||
**Goal**: Un visiteur comprend immediatement que Killian est dev Hytale, peut voir les services/prix, et lire des temoignages clients
|
||
**Depends on**: Phase 1
|
||
**Requirements**: CONT-01, CONT-02, CONT-03, CONT-04, SEO-05
|
||
**Success Criteria** (what must be TRUE):
|
||
1. Le H1 de la homepage contient "Hytale" — `curl localhost:3000 | grep -i hytale` dans le `<h1>`
|
||
2. `/hytale` existe avec 3+ tiers de pricing visibles et un CTA contact/Discord
|
||
3. `app/data/site.ts` contient `jobTitle: 'Hytale Plugin Developer'`
|
||
4. Les temoignages apparaissent sur la homepage ET la page Hytale
|
||
5. Tout le contenu est bilingue — `curl localhost:3000/en/hytale` retourne du contenu anglais
|
||
**Plans:** 3 plans
|
||
Plans:
|
||
- [ ] 02-01-PLAN.md — Types, data files, site.ts config, i18n keys (foundation)
|
||
- [ ] 02-02-PLAN.md — Hero refonte Hytale, testimonials featured prop, nav link
|
||
- [ ] 02-03-PLAN.md — Hytale page creation with pricing, services, and sections
|
||
**UI hint**: yes
|
||
|
||
### Phase 3: SEO & i18n
|
||
**Goal**: Chaque page a des meta tags complets, JSON-LD, canonical links, et des traductions FR/EN naturelles et completes
|
||
**Depends on**: Phase 2
|
||
**Requirements**: SEO-01, SEO-02, SEO-03, SEO-04, I18N-01, I18N-02, I18N-03, I18N-04
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `curl localhost:3000` retourne `<link rel="canonical">` et `ogUrl` dans le HTML
|
||
2. `curl localhost:3000/hytale` retourne un JSON-LD `Service` avec les 3 tiers
|
||
3. `curl localhost:3000/en/` retourne du HTML anglais sans hardcoded French strings
|
||
4. Aucun composant ne contient de chaine en dur (grep pour strings hors `t()` dans les templates)
|
||
5. Les traductions FR sonnent naturel — pas de calque anglais
|
||
**Plans:** 4 plans
|
||
Plans:
|
||
- [ ] 06-01-PLAN.md — Content schema Zod extension (draft/wordCount/minutes) + Nitro reading-time hook + draft:true sur test articles
|
||
- [ ] 06-02-PLAN.md — i18n keys blog.*/nav.blog/a11y.blog* + lien Blog dans AppHeader + BlogCard.vue unifié (default + compact)
|
||
- [ ] 06-03-PLAN.md — Page listing app/pages/blog/index.vue (hero + grid + empty state, SSR bilingue)
|
||
- [ ] 06-04-PLAN.md — BlogToc.vue + BlogPrevNext.vue + enrichissement app/pages/blog/[slug].vue (breadcrumb + header + TOC + surround)
|
||
|
||
### Phase 4: Ship
|
||
**Goal**: Le site est deployable en production via Docker et passe tous les checks
|
||
**Depends on**: Phase 3
|
||
**Requirements**: DEPLOY-01
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `docker build` complete sans erreur
|
||
2. Le container sert le site SSR sur le port attendu
|
||
3. `pnpm typecheck` et `pnpm lint` passent avec 0 erreurs
|
||
4. `curl` sur chaque page retourne `<title>`, `<meta description>`, `og:title` dans le HTML brut
|
||
**Plans:** 4 plans
|
||
Plans:
|
||
- [ ] 06-01-PLAN.md — Content schema Zod extension (draft/wordCount/minutes) + Nitro reading-time hook + draft:true sur test articles
|
||
- [ ] 06-02-PLAN.md — i18n keys blog.*/nav.blog/a11y.blog* + lien Blog dans AppHeader + BlogCard.vue unifié (default + compact)
|
||
- [ ] 06-03-PLAN.md — Page listing app/pages/blog/index.vue (hero + grid + empty state, SSR bilingue)
|
||
- [ ] 06-04-PLAN.md — BlogToc.vue + BlogPrevNext.vue + enrichissement app/pages/blog/[slug].vue (breadcrumb + header + TOC + surround)
|
||
|
||
---
|
||
|
||
## Progress
|
||
|
||
| Phase | Plans Complete | Status | Completed |
|
||
|-------|----------------|--------|-----------|
|
||
| 1. Cleanup & Fixes | 2/2 | Complete | 2026-04-21 |
|
||
| 2. Content | 3/3 | Complete | 2026-04-21 |
|
||
| 3. SEO & i18n | 1/1 | Complete | 2026-04-21 |
|
||
| 4. Ship | 1/1 | Complete | 2026-04-21 |
|
||
|
||
---
|
||
|
||
---
|
||
|
||
# Archived Milestones
|
||
|
||
- **M1.1 — SEO Hytale — Autorité & Contenu** — ✅ Shipped 2026-04-22 (phases 5–8, 13 plans) — see [v1.1-ROADMAP.md](./milestones/v1.1-ROADMAP.md)
|
||
|
||
---
|
||
|
||
<details>
|
||
<summary>M1.1 phase details (collapsed)</summary>
|
||
|
||
### Phase 5: @nuxt/content Setup & Renderer
|
||
**Goal**: Le systeme de contenu markdown est installe et rend fidelement le contenu technique — blocs de code colores, images optimisees, tables, alerts — sans configuration supplementaire dans les phases suivantes
|
||
**Depends on**: Phase 4 (M1 complete)
|
||
**Requirements**: BLOG-01, BLOG-04, BLOG-05
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `@nuxt/content` est installe et configure dans `nuxt.config.ts` — `pnpm dev` demarre sans erreur
|
||
2. Un article markdown de test avec un bloc Kotlin est rendu avec coloration syntaxique visible dans le navigateur
|
||
3. Une image referencee dans un article s'affiche via `<NuxtImg>` avec les optimisations (lazy, format webp)
|
||
4. Un tableau markdown et un callout/alert sont rendus avec le style correct
|
||
**Plans:** 2 plans
|
||
Plans:
|
||
- [ ] 05-01-PLAN.md — Installation @nuxt/content, configuration Shiki dual-theme, content.config.ts collections bilingues
|
||
- [ ] 05-02-PLAN.md — Composants MDC ProseImg + Alert, articles de test FR/EN, checkpoint visuel
|
||
**UI hint**: yes
|
||
|
||
### Phase 6: Blog Pages
|
||
**Goal**: Un visiteur peut naviguer vers /blog, parcourir la liste des articles, ouvrir un article, voir sa table des matieres et naviguer vers l'article precedent/suivant — le tout en SSR et en FR ou EN
|
||
**Depends on**: Phase 5
|
||
**Requirements**: BLOG-02, BLOG-03, BLOG-06
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `curl localhost:3000/blog` retourne du HTML SSR avec une liste d'articles (titre, description, date, tags)
|
||
2. `curl localhost:3000/blog/[slug]` retourne le contenu de l'article rendu en HTML, pas de SPA shell vide
|
||
3. La page article affiche une table des matieres generee depuis les headings du markdown
|
||
4. Des liens "Article precedent" et "Article suivant" sont presents en bas de chaque article
|
||
5. `curl localhost:3000/en/blog` retourne le listing en anglais — les articles ont leur version EN
|
||
**Plans:** 4 plans
|
||
Plans:
|
||
- [x] 06-01-PLAN.md — Content schema Zod extension (draft/wordCount/minutes) + Nitro reading-time hook + draft:true sur test articles
|
||
- [x] 06-02-PLAN.md — i18n keys blog.*/nav.blog/a11y.blog* + lien Blog dans AppHeader + BlogCard.vue unifié (default + compact)
|
||
- [x] 06-03-PLAN.md — Page listing app/pages/blog/index.vue (hero + grid + empty state, SSR bilingue)
|
||
- [x] 06-04-PLAN.md — BlogToc.vue + BlogPrevNext.vue + enrichissement app/pages/blog/[slug].vue (breadcrumb + header + TOC + surround)
|
||
**UI hint**: yes
|
||
|
||
### Phase 7: SEO Blog
|
||
**Goal**: Chaque page blog est indexable avec des meta tags complets, un JSON-LD Article valide, et les URLs /blog figurent dans le sitemap — Google peut crawler et comprendre le contenu sans ambiguite
|
||
**Depends on**: Phase 6
|
||
**Requirements**: SEO-10, SEO-11, SEO-12, SEO-13, SEO-15
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `curl localhost:3000/blog/[slug]` retourne `<meta property="og:title">`, `<meta property="og:description">` et `<meta property="og:image">` uniques dans le HTML
|
||
2. Le meme curl retourne un JSON-LD de type `Article` avec `author`, `datePublished`, `headline` remplis
|
||
3. `curl localhost:3000/sitemap.xml` contient les URLs `/blog/[slug]` et `/en/blog/[slug]`
|
||
4. `og:image` pointe vers l'image de l'article ou vers un fallback branded — jamais vers og-image.png generique
|
||
5. La page article contient un JSON-LD `BreadcrumbList` : Accueil → Blog → Titre de l'article
|
||
**Plans:** 4 plans
|
||
Plans:
|
||
- [ ] 07-01-PLAN.md — Install nuxt-schema-org + schema updated + definePerson/defineWebSite global + sitemap.sources
|
||
- [ ] 07-02-PLAN.md — resolveOgImage helper + og-blog-default.jpg + [slug].vue useSeoMeta enrichi + defineArticle/defineBreadcrumb
|
||
- [ ] 07-03-PLAN.md — index.vue useSeoMeta enrichi + defineWebPage(CollectionPage) + defineBreadcrumb
|
||
- [x] 07-04-PLAN.md — server/api/__sitemap__/urls.ts (bilingue, draft:false, alternates hreflang, lastmod=updated||date)
|
||
|
||
### Phase 8: Content & Cocon Semantique
|
||
**Goal**: Le blog est lance avec au moins 2 articles Hytale de qualite, et un visiteur qui arrive sur /hytale decouvre les articles recents — le cocon semantique entre blog et page hytale est etabli
|
||
**Depends on**: Phase 7
|
||
**Requirements**: BLOG-07, SEO-14
|
||
**Success Criteria** (what must be TRUE):
|
||
1. `/blog` liste au moins 2 articles avec le tag "hytale", avec titres, descriptions et dates reels
|
||
2. Chaque article blog contient au moins un lien interne vers `/hytale` dans le corps du texte
|
||
3. La page `/hytale` affiche une section "Articles recents" avec liens vers les 2 articles seed
|
||
4. Les articles existent en FR et EN — `curl localhost:3000/en/blog` les liste en anglais
|
||
**Plans:** 3 plans
|
||
Plans:
|
||
- [ ] 08-01-PLAN.md — Scaffold HytaleRecentArticles.vue (queryCollection bilingue + filtre tag hytale + limit 2) + injection hytale.vue + i18n hytale.recentArticles.*
|
||
- [ ] 08-02-PLAN.md — Article seed tutorial how-to-build-your-first-hytale-plugin (FR+EN, draft:false, bloc Kotlin, liens inline /hytale)
|
||
- [ ] 08-03-PLAN.md — Article seed autorité hytale-plugin-development-2026 (FR+EN, draft:false, bloc Kotlin coroutines, liens inline /hytale)
|
||
**UI hint**: yes
|
||
|
||
---
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## M1.2 — Ship to Prod + Credibility Gap (Active)
|
||
|
||
**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 ✅ (shipped 2026-04-22)
|
||
**Goal**: M1.1 est live sur killiandalcin.fr — blog bilingue, sitemap hreflang, JSON-LD Article accessibles en prod
|
||
**Outcome**: Shipped. Bug build hang (nuxt/nuxt#33987) fixé via `hooks.close: () => process.exit(0)` dans nuxt.config.ts.
|
||
**Requirements**: DEPLOY-02 ✅, DEPLOY-03 ✅
|
||
**Plans:** 1 plan
|
||
Plans:
|
||
- [x] 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.*
|