Files
portfolio/.planning/phases/05-nuxt-content-setup-renderer/05-01-PLAN.md
T
kayjaydee 808835d5eb docs(05): create phase 5 plan — @nuxt/content setup & renderer
2 plans, 2 waves. Plan 01 installe @nuxt/content + typography et
configure Shiki dual-theme + collections bilingues. Plan 02 crée
ProseImg/Alert MDC et articles de test FR/EN avec checkpoint visuel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 12:48:02 +02:00

12 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
05-nuxt-content-setup-renderer 01 execute 1
nuxt.config.ts
app/assets/css/main.css
content.config.ts
package.json
true
BLOG-01
BLOG-04
truths artifacts key_links
@nuxt/content est installé et `pnpm dev` démarre sans erreur
Shiki est configuré avec les langages Kotlin, Java, TypeScript, Shell et les thèmes github-light/github-dark
Les collections blog_fr et blog_en sont déclarées dans content.config.ts avec le bon prefix i18n
@tailwindcss/typography est chargé via `@plugin` dans main.css
path provides exports
content.config.ts Déclaration des collections bilingues blog_fr + blog_en avec schema Zod
defineContentConfig
path provides contains
nuxt.config.ts Module @nuxt/content + config Shiki dual-theme + sqliteConnector native @nuxt/content
path provides contains
app/assets/css/main.css Plugin @tailwindcss/typography chargé @plugin
from to via pattern
nuxt.config.ts content.build.markdown.highlight Shiki dual-theme github-light/github-dark theme.default + theme.dark github-light.*github-dark|github-dark.*github-light
from to via pattern
content.config.ts collections.blog_fr content/fr/blog/**/*.md source.include fr/blog/**
Installer `@nuxt/content` v3 et `@tailwindcss/typography`, puis configurer le système de rendu markdown — Shiki dual-theme, collections bilingues, connecteur SQLite natif.

Purpose: Cette phase pose les fondations du CMS. Sans elle, les phases 6, 7 et 8 ne peuvent pas fonctionner. La configuration doit être définitive — aucun retour en arrière attendu.

Output:

  • @nuxt/content installé et déclaré dans nuxt.config.ts
  • content.config.ts avec collections blog_fr + blog_en
  • Shiki configuré pour Kotlin, Java, TypeScript, Shell avec thèmes dark/light
  • @tailwindcss/typography chargé via @plugin dans main.css
  • pnpm dev démarre sans erreur

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/05-nuxt-content-setup-renderer/05-CONTEXT.md @.planning/phases/05-nuxt-content-setup-renderer/05-RESEARCH.md ```typescript modules: [ '@nuxt/ui', '@nuxtjs/i18n', '@nuxt/eslint', '@nuxtjs/sitemap', 'nuxt-gtag', '@nuxt/image' ], ```
colorMode: {
  preference: 'dark',
  fallback: 'dark',
  storage: 'cookie',
  storageKey: 'nuxt-color-mode',
  classSuffix: ''   // ← CRITIQUE: Shiki dual-theme nécessite classSuffix: '' pour html.dark
},
@import "tailwindcss";
@import "@nuxt/ui";

@theme {
  --color-brand-500: #85cb85;
  /* ... autres tokens brand */
}
Task 1: Installer @nuxt/content et @tailwindcss/typography package.json - package.json (vérifier pnpm.onlyBuiltDependencies existant, ne pas écraser) Exécuter les deux commandes d'installation suivantes dans l'ordre :
```bash
pnpm add @nuxt/content
pnpm add -D @tailwindcss/typography
```

Versions cibles : `@nuxt/content@^3.6.3`, `@tailwindcss/typography@^0.5.x`.

NE PAS ajouter `better-sqlite3` — le connecteur natif Node 22 sera utilisé via `experimental.sqliteConnector: 'native'` dans nuxt.config.ts (Task 2).

Si `pnpm add` échoue avec une erreur de script build SQLite, c'est normal sans la config native — continuer vers Task 2 qui la résout.
```bash grep '"@nuxt/content"' package.json grep '"@tailwindcss/typography"' package.json ``` Les deux lignes doivent apparaître. - `package.json` contient `"@nuxt/content"` dans `dependencies` - `package.json` contient `"@tailwindcss/typography"` dans `devDependencies` - `node_modules/@nuxt/content` existe - `node_modules/@tailwindcss/typography` existe Les deux packages sont installés via pnpm sans erreur bloquante. Task 2: Configurer nuxt.config.ts et app/assets/css/main.css nuxt.config.ts, app/assets/css/main.css - nuxt.config.ts (lire INTÉGRALEMENT avant de modifier — ne jamais réécrire, uniquement étendre) - app/assets/css/main.css (lire INTÉGRALEMENT) **1. nuxt.config.ts — deux modifications :**
a) Ajouter `'@nuxt/content'` à la fin du tableau `modules` (après `'@nuxt/image'`) :
```typescript
modules: [
  '@nuxt/ui',
  '@nuxtjs/i18n',
  '@nuxt/eslint',
  '@nuxtjs/sitemap',
  'nuxt-gtag',
  '@nuxt/image',
  '@nuxt/content'    // ← ligne ajoutée
],
```

b) Ajouter le bloc `content` après le bloc `gtag` existant (avant la fermeture `}`) :
```typescript
content: {
  build: {
    markdown: {
      highlight: {
        theme: {
          default: 'github-light',
          dark: 'github-dark'
        },
        langs: ['kotlin', 'java', 'typescript', 'shell', 'bash', 'json', 'vue', 'html', 'css']
      }
    }
  },
  experimental: {
    sqliteConnector: 'native'
  }
}
```

NE PAS utiliser `nativeSqlite: true` (déprécié). Utiliser exclusivement `sqliteConnector: 'native'`.
NE PAS modifier `colorMode.classSuffix` — doit rester `''` pour que Shiki dual-theme fonctionne via `html.dark`.

**2. app/assets/css/main.css — une ligne ajoutée :**

Ajouter `@plugin "@tailwindcss/typography";` après `@import "@nuxt/ui";` :
```css
@import "tailwindcss";
@import "@nuxt/ui";
@plugin "@tailwindcss/typography";
```

NE PAS utiliser `plugins: [require('@tailwindcss/typography')]` dans tailwind.config.js — cette syntaxe est ignorée en Tailwind v4. La syntaxe `@plugin` dans le CSS est la seule valide.
NE PAS toucher le bloc `@theme` existant avec les tokens `--color-brand-*`.
```bash grep "'@nuxt/content'" nuxt.config.ts grep "github-dark" nuxt.config.ts grep "sqliteConnector" nuxt.config.ts grep "kotlin" nuxt.config.ts grep '@plugin "@tailwindcss/typography"' app/assets/css/main.css ``` Les cinq lignes doivent retourner un résultat. - `nuxt.config.ts` contient `'@nuxt/content'` dans le tableau `modules` - `nuxt.config.ts` contient le bloc `content.build.markdown.highlight.theme` avec `default: 'github-light'` et `dark: 'github-dark'` - `nuxt.config.ts` contient `sqliteConnector: 'native'` (PAS `nativeSqlite`) - `nuxt.config.ts` liste au minimum ces langages Shiki : `'kotlin'`, `'java'`, `'typescript'`, `'shell'` - `nuxt.config.ts` ne contient PAS `nativeSqlite` - `app/assets/css/main.css` contient `@plugin "@tailwindcss/typography";` sur sa propre ligne - `app/assets/css/main.css` contient toujours le bloc `@theme` avec `--color-brand-500` nuxt.config.ts étend le module @nuxt/content avec Shiki dual-theme. main.css charge @tailwindcss/typography via @plugin. Task 3: Créer content.config.ts avec collections bilingues content.config.ts - nuxt.config.ts (vérifier i18n.strategy et i18n.defaultLocale pour confirmer le prefix des collections) - .planning/phases/05-nuxt-content-setup-renderer/05-RESEARCH.md (Pattern 2 — content.config.ts) Créer `content.config.ts` à la RACINE du projet (même niveau que `nuxt.config.ts`).
Contenu exact :
```typescript
import { defineContentConfig, defineCollection, z } from '@nuxt/content'

const blogSchema = z.object({
  title: z.string(),
  description: z.string(),
  date: z.string(),
  tags: z.array(z.string()).optional(),
  image: z.string().optional(),
})

export default defineContentConfig({
  collections: {
    blog_fr: defineCollection({
      type: 'page',
      source: { include: 'fr/blog/**/*.md', prefix: '/blog' },
      schema: blogSchema,
    }),
    blog_en: defineCollection({
      type: 'page',
      source: { include: 'en/blog/**/*.md', prefix: '/en/blog' },
      schema: blogSchema,
    }),
  },
})
```

Justification des prefixes :
- `blog_fr` → prefix `/blog` (FR est la locale par défaut avec `prefix_except_default`, donc pas de `/fr/` dans l'URL)
- `blog_en` → prefix `/en/blog` (EN reçoit le préfixe de langue)

Ce schema minimal sera étendu en Phase 7 (author, og:image, etc.) — ne pas anticiper.
```bash test -f content.config.ts && echo "EXISTS" grep "blog_fr" content.config.ts grep "blog_en" content.config.ts grep "prefix: '/blog'" content.config.ts grep "prefix: '/en/blog'" content.config.ts ``` - `content.config.ts` existe à la racine du projet - Contient l'export `defineContentConfig` - Contient la collection `blog_fr` avec `source.include: 'fr/blog/**/*.md'` et `source.prefix: '/blog'` - Contient la collection `blog_en` avec `source.include: 'en/blog/**/*.md'` et `source.prefix: '/en/blog'` - Le schema Zod contient les champs `title`, `description`, `date` (requis) et `tags`, `image` (optionnels) - `pnpm dev` démarre sans erreur après ces trois tasks (vérification smoke finale) content.config.ts créé avec collections bilingues. `pnpm dev` démarre sans erreur — l'infrastructure @nuxt/content est opérationnelle.

<threat_model>

Trust Boundaries

Boundary Description
Système de fichiers → Parser @nuxt/content Fichiers markdown lus au build — source contrôlée (auteur uniquement, pas d'input utilisateur)
Node.js 22 → SQLite natif Connecteur natif utilisé au lieu de better-sqlite3 — pas d'exposition réseau

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-05-01 Tampering content.config.ts source.include glob accept Seuls les fichiers *.md dans content/ sont indexés — aucun input utilisateur dans cette phase, glob contrôlé par l'auteur
T-05-02 Information Disclosure Shiki HTML output accept Shiki génère du HTML échappé — pas de XSS possible via blocs de code
T-05-03 Denial of Service SQLite natif Node 22 au build accept Build-time uniquement, pas d'exposition runtime — risque nul en production
T-05-04 Elevation of Privilege experimental.sqliteConnector: 'native' accept Connecteur natif Node.js — pas de binary externe, surface d'attaque réduite vs better-sqlite3
</threat_model>
Après exécution du plan 01, vérifier :
# 1. Packages installés
grep '"@nuxt/content"' package.json && grep '"@tailwindcss/typography"' package.json

# 2. nuxt.config.ts étendu correctement
grep "'@nuxt/content'" nuxt.config.ts
grep "github-dark" nuxt.config.ts
grep "sqliteConnector.*native" nuxt.config.ts
# NE DOIT PAS contenir l'option dépréciée :
grep "nativeSqlite" nuxt.config.ts  # doit retourner RIEN

# 3. CSS typography
grep '@plugin "@tailwindcss/typography"' app/assets/css/main.css

# 4. content.config.ts collections
grep "blog_fr\|blog_en" content.config.ts

# 5. Smoke test
pnpm dev  # doit démarrer sans erreur

<success_criteria>

  • pnpm dev démarre sans erreur après installation et configuration
  • nuxt.config.ts contient '@nuxt/content' dans modules et le bloc content avec Shiki dual-theme + langages
  • content.config.ts existe avec les deux collections bilingues et le bon prefix i18n
  • app/assets/css/main.css charge @tailwindcss/typography via @plugin
  • pnpm typecheck passe (0 erreur TypeScript) </success_criteria>
Après completion, créer `.planning/phases/05-nuxt-content-setup-renderer/05-01-SUMMARY.md`