--- phase: 05-nuxt-content-setup-renderer plan: 01 type: execute wave: 1 depends_on: [] files_modified: - nuxt.config.ts - app/assets/css/main.css - content.config.ts - package.json autonomous: true requirements: - BLOG-01 - BLOG-04 must_haves: truths: - "@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" artifacts: - path: "content.config.ts" provides: "Déclaration des collections bilingues blog_fr + blog_en avec schema Zod" exports: ["defineContentConfig"] - path: "nuxt.config.ts" provides: "Module @nuxt/content + config Shiki dual-theme + sqliteConnector native" contains: "@nuxt/content" - path: "app/assets/css/main.css" provides: "Plugin @tailwindcss/typography chargé" contains: "@plugin" key_links: - from: "nuxt.config.ts content.build.markdown.highlight" to: "Shiki dual-theme github-light/github-dark" via: "theme.default + theme.dark" pattern: "github-light.*github-dark|github-dark.*github-light" - from: "content.config.ts collections.blog_fr" to: "content/fr/blog/**/*.md" via: "source.include" pattern: "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 @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.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' ], ``` ```typescript colorMode: { preference: 'dark', fallback: 'dark', storage: 'cookie', storageKey: 'nuxt-color-mode', classSuffix: '' // ← CRITIQUE: Shiki dual-theme nécessite classSuffix: '' pour html.dark }, ``` ```css @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. ## 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 | Après exécution du plan 01, vérifier : ```bash # 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 ``` - `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) Après completion, créer `.planning/phases/05-nuxt-content-setup-renderer/05-01-SUMMARY.md`