docs: create roadmap (3 phases)

This commit is contained in:
2026-04-07 23:24:38 +02:00
parent 7273c6e815
commit 8177ff045a
4 changed files with 486 additions and 5 deletions
+42 -5
View File
@@ -98,13 +98,50 @@
| Requirement | Phase | Status | | Requirement | Phase | Status |
|-------------|-------|--------| |-------------|-------|--------|
| (populated during roadmap creation) | | | | SSR-01 | Phase 1 | Pending |
| SSR-02 | Phase 1 | Pending |
| SSR-03 | Phase 1 | Pending |
| DATA-01 | Phase 1 | Pending |
| DATA-02 | Phase 1 | Pending |
| DATA-03 | Phase 1 | Pending |
| DATA-04 | Phase 1 | Pending |
| DATA-05 | Phase 1 | Pending |
| INFRA-02 | Phase 1 | Pending |
| INFRA-03 | Phase 1 | Pending |
| I18N-01 | Phase 2 | Pending |
| I18N-02 | Phase 2 | Pending |
| I18N-03 | Phase 2 | Pending |
| I18N-04 | Phase 2 | Pending |
| I18N-05 | Phase 2 | Pending |
| THEME-01 | Phase 2 | Pending |
| THEME-02 | Phase 2 | Pending |
| THEME-03 | Phase 2 | Pending |
| SEO-01 | Phase 2 | Pending |
| SEO-02 | Phase 2 | Pending |
| SEO-03 | Phase 2 | Pending |
| SEO-04 | Phase 2 | Pending |
| COMP-05 | Phase 2 | Pending |
| COMP-06 | Phase 2 | Pending |
| PAGE-01 | Phase 3 | Pending |
| PAGE-02 | Phase 3 | Pending |
| PAGE-03 | Phase 3 | Pending |
| PAGE-04 | Phase 3 | Pending |
| PAGE-05 | Phase 3 | Pending |
| PAGE-06 | Phase 3 | Pending |
| PAGE-07 | Phase 3 | Pending |
| PAGE-08 | Phase 3 | Pending |
| COMP-01 | Phase 3 | Pending |
| COMP-02 | Phase 3 | Pending |
| COMP-03 | Phase 3 | Pending |
| COMP-04 | Phase 3 | Pending |
| INFRA-01 | Phase 3 | Pending |
| INFRA-04 | Phase 3 | Pending |
**Coverage:** **Coverage:**
- v1 requirements: 35 total - v1 requirements: 38 total
- Mapped to phases: 0 - Mapped to phases: 38
- Unmapped: 35 ⚠️ - Unmapped: 0 ✓
--- ---
*Requirements defined: 2026-04-07* *Requirements defined: 2026-04-07*
*Last updated: 2026-04-07 after initial definition* *Last updated: 2026-04-07 after roadmap creation*
+67
View File
@@ -0,0 +1,67 @@
# Roadmap: Portfolio Killian Dalcin — Nuxt 4 Migration
## Overview
Three phases following the strict build order from research: first lay the Nuxt 4 project skeleton with all modules configured and data migrated, then implement the SSR-critical cross-cutting concerns (i18n, theme, SEO, header/footer), and finally build all pages and ship to production via Docker. Every page is crawlable by search engines when Phase 3 completes.
## Phases
**Phase Numbering:**
- Integer phases (1, 2, 3): Planned milestone work
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 1: Foundation** - Nuxt 4 project scaffold, all modules configured, static data migrated, composables ported
- [ ] **Phase 2: SSR Shell** - i18n FR/EN, dark/light theme, SEO per route, header + footer layout
- [ ] **Phase 3: Pages & Ship** - All 8 pages, interactive components, EmailJS plugin, GA4, Dockerfile
## Phase Details
### Phase 1: Foundation
**Goal**: The Nuxt 4 project runs locally with all modules installed, data in `data/`, composables wired, and TypeScript strict mode passing
**Depends on**: Nothing (first phase)
**Requirements**: SSR-01, SSR-02, SSR-03, DATA-01, DATA-02, DATA-03, DATA-04, DATA-05, INFRA-02, INFRA-03
**Success Criteria** (what must be TRUE):
1. `nuxt dev` starts without errors and serves a blank app at `localhost:3000`
2. All static data files exist under `data/` and are importable with TypeScript strict — no `any` types
3. `useProjects()` composable returns typed project list and supports filtering by category and search
4. `npx nuxi typecheck` and `npx eslint .` exit with 0 errors
**Plans**: TBD
### Phase 2: SSR Shell
**Goal**: Every route renders the correct language, theme, and SEO metadata on the server — confirmed by `curl` with no JavaScript
**Depends on**: Phase 1
**Requirements**: I18N-01, I18N-02, I18N-03, I18N-04, I18N-05, THEME-01, THEME-02, THEME-03, SEO-01, SEO-02, SEO-03, SEO-04, COMP-05, COMP-06
**Success Criteria** (what must be TRUE):
1. `curl http://localhost:3000` returns French HTML; `curl http://localhost:3000/en/` returns English HTML — no JS required
2. Switching language via the header dropdown persists across page reload (cookie, no FOUC)
3. Toggling dark/light mode in the header persists across page reload with no flash on cold load
4. `curl http://localhost:3000` response includes `<title>`, `og:title`, `og:description`, and JSON-LD script tag
5. `http://localhost:3000/sitemap.xml` returns a valid XML sitemap with `hreflang` alternates for FR and EN URLs
**Plans**: TBD
**UI hint**: yes
### Phase 3: Pages & Ship
**Goal**: All portfolio pages are live, forms work, analytics fire in production, and the Docker image builds and runs
**Depends on**: Phase 2
**Requirements**: PAGE-01, PAGE-02, PAGE-03, PAGE-04, PAGE-05, PAGE-06, PAGE-07, PAGE-08, COMP-01, COMP-02, COMP-03, COMP-04, INFRA-01, INFRA-04
**Success Criteria** (what must be TRUE):
1. All 8 routes (`/`, `/projects`, `/project/[id]`, `/about`, `/contact`, `/fiverr`, `/formation`, 404) return complete HTML when fetched with `curl`
2. Clicking an image in a project detail page opens a modal carousel with keyboard navigation (arrow keys + Escape closes)
3. Submitting the contact form with valid data shows a success toast; EmailJS delivers the email
4. `docker build` completes and `docker run` serves the SSR app on port 3000
5. Google Analytics 4 events appear in GA4 DebugView when browsing in production mode
**Plans**: TBD
**UI hint**: yes
## Progress
**Execution Order:**
Phases execute in numeric order: 1 → 2 → 3
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Foundation | 0/TBD | Not started | - |
| 2. SSR Shell | 0/TBD | Not started | - |
| 3. Pages & Ship | 0/TBD | Not started | - |
+64
View File
@@ -0,0 +1,64 @@
# Project State
## Project Reference
See: .planning/PROJECT.md (updated 2026-04-07)
**Core value:** Chaque page du portfolio doit être crawlable par les moteurs de recherche sans JavaScript côté client
**Current focus:** Phase 1 — Foundation
## Current Position
Phase: 1 of 3 (Foundation)
Plan: 0 of TBD in current phase
Status: Ready to plan
Last activity: 2026-04-07 — Roadmap created, project initialized
Progress: [░░░░░░░░░░] 0%
## Performance Metrics
**Velocity:**
- Total plans completed: 0
- Average duration: —
- Total execution time: 0 hours
**By Phase:**
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| - | - | - | - |
**Recent Trend:**
- Last 5 plans: —
- Trend: —
*Updated after each plan completion*
## Accumulated Context
### Decisions
Decisions are logged in PROJECT.md Key Decisions table.
Recent decisions affecting current work:
- Init: Use `@nuxtjs/seo` meta-bundle (covers sitemap + og:image + schema-org) instead of standalone modules
- Init: SSR mode (not SSG) — i18n cookie detection requires server execution per request
- Init: Cookie-only persistence for i18n + theme (SSR-safe, no localStorage)
- Init: Static TS data files under `data/` (no @nuxt/content needed)
### Pending Todos
None yet.
### Blockers/Concerns
- Open: Confirm @nuxtjs/i18n v9 stable + Nuxt 4 compatible before Phase 2 planning
- Open: Confirm @nuxt/ui v3 stable (not beta/rc) before Phase 1 planning
- Open: Confirm nuxt-gtag Nuxt 4 compatibility before Phase 3 planning
## Session Continuity
Last session: 2026-04-07
Stopped at: Roadmap created — ready to plan Phase 1
Resume file: None
+313
View File
@@ -0,0 +1,313 @@
<!-- GSD:project-start source:PROJECT.md -->
## Project
**Portfolio Killian Dalcin — Migration Nuxt 4**
Migration complète d'un portfolio freelance de Vue 3 SPA vers Nuxt 4 avec SSR complet. Le site présente les projets, services et compétences de Killian Dalcin, développeur freelance, avec support bilingue FR/EN. L'objectif est un SEO parfait et un développement rapide via des composants prêts à l'emploi (Nuxt UI v3).
**Core Value:** Chaque page du portfolio doit être crawlable par les moteurs de recherche sans JavaScript côté client — le SSR est la raison d'être de cette migration.
### Constraints
- **Stack**: Nuxt 4 + Nuxt UI v3 + Tailwind v4 — dernières versions stables
- **Coût**: Zéro dépendance payante
- **Composants**: Nuxt UI v3 en priorité sur le custom (80% suffit)
- **TypeScript**: Mode strict partout
- **Déploiement**: Docker node:22-alpine, nuxt build (SSR) ou nuxt generate (SSG) selon stratégie
- **i18n/Theme**: Persistance cookie uniquement (SSR-safe), pas de localStorage
<!-- GSD:project-end -->
<!-- GSD:stack-start source:codebase/STACK.md -->
## Technology Stack
## Languages
- TypeScript ~5.8.0 - Full application development
- JavaScript (ES modules) - Frontend runtime
- HTML5 - Document structure (in `index.html`)
- CSS - Styling with Tailwind CSS
- Markdown - Documentation (README.md)
- YAML - Configuration (implied through Dockerfile)
## Runtime
- Node.js 22 - Development and build environment
- Browser environment - Vue 3 SFC runtime
- npm - Dependency management
- Lockfile: `package-lock.json` (present and tracked)
## Frameworks
- Vue 3.5.13 - Progressive JavaScript framework for UI
- Vue Router 4.5.0 - Client-side routing with lazy-loaded pages
- Pinia 3.0.1 - State management (minimal usage - currently only `counter.ts`)
- Vue I18n 9.14.4 - Internationalization (English and French locale files in `src/locales/`)
- Vite 6.2.4 - Build tool and dev server
- Vite Plugin Vue DevTools 7.7.2 - Development utilities
- @vitejs/plugin-vue 5.2.3 - Vue 3 SFC support
- Tailwind CSS 4.1.10 - Utility-first CSS framework
- @tailwindcss/postcss 4.1.10 - PostCSS plugin for Tailwind
- PostCSS 8.5.6 - CSS transformation pipeline
- Autoprefixer 10.4.21 - Vendor prefix handling
- Terser 5.43.1 - JavaScript minification
- ESLint 9.22.0 - Linting (config: `eslint.config.ts`)
- Prettier 3.5.3 - Code formatting (config: `.prettierrc.json`)
- vue-tsc 2.2.8 - Vue component type checking
- TypeScript compiler with `type-check` npm script
- @vueuse/head 2.0.0 - Dynamic document head management for meta tags and SEO
## Key Dependencies
- vue 3.5.13 - Core framework
- vue-router 4.5.0 - SPA routing with code splitting
- pinia 3.0.1 - State management store
- vue-i18n 9.14.4 - Multi-language support
- vite 6.2.4 - Next-gen build tool with HMR
- tailwindcss 4.1.10 - Rapid UI development
- typescript 5.8.0 - Static typing and compilation
- eslint 9.22.0 - Code linting
- prettier 3.5.3 - Code formatting
- npm-run-all2 7.0.2 - Parallel script execution (used in build process)
- @tsconfig/node22 22.0.1 - TSConfig preset for Node 22
- @types/node 22.14.0 - Node.js type definitions
- jiti 2.4.2 - CommonJS loader for TypeScript modules
## Configuration
- No `.env` files detected in source
- Google Analytics tracking ID hardcoded: `G-CDVVNFY6MV` (in `index.html`)
- Umami analytics script loaded from `umami.killiandalcin.fr` (in `index.html`)
- Google AdSense client ID hardcoded: `ca-pub-5219367964457248` (in `index.html`)
- `vite.config.ts` - Build optimizations:
- `tsconfig.json` - References `tsconfig.app.json` and `tsconfig.node.json`
- `tsconfig.app.json`:
- `eslint.config.ts` - Flat config format:
- `.prettierrc.json`:
- `postcss.config.js` - Tailwind CSS and Autoprefixer
- `tailwind.config.js` - Content scanning for `index.html` and `src/**/*.{vue,js,ts,jsx,tsx}`
## Platform Requirements
- Node.js 22+ (specified in Dockerfile)
- npm 10+ (implied by Node 22)
- TypeScript 5.8+
- Any Unix-like shell (bash/zsh) or Windows with Node.js
- Docker - Multi-stage build with Node 22-alpine and nginx stable-alpine
- Web server: nginx (configured in `nginx.conf`)
- Deployment target: Static HTML served via nginx
- JavaScript enabled (noscript fallback message in `index.html`)
- Modern browsers with ES2020+ support (Vite default targets)
## Scripts & Commands
<!-- GSD:stack-end -->
<!-- GSD:conventions-start source:CONVENTIONS.md -->
## Conventions
## Naming Patterns
- Vue components: PascalCase (e.g., `AppHeader.vue`, `ProjectCard.vue`)
- Composables: camelCase with `use` prefix (e.g., `useTheme.ts`, `useProjects.ts`)
- Utility/config files: camelCase (e.g., `site.ts`, `techstack.ts`)
- Data files: camelCase (e.g., `testimonials.ts`, `faq.ts`)
- Type definitions: camelCase in `types/index.ts`
- All functions use camelCase (e.g., `toggleTheme`, `openGallery`, `getImageUrl`)
- Composables are named with `use` prefix: `useTheme()`, `useGallery()`, `useSeo()`
- Getter functions use `get` prefix: `getTheme()`, `getImageUrl()`
- Boolean functions/computed use `is`/`has` prefix: `isDark`, `hasNext`, `isOpen`
- Handler functions use verb + `Handler`: `toggleTheme`, `openGallery`, `closeGallery`
- Refs and computed properties: camelCase (e.g., `isDark`, `currentIndex`, `isOpen`)
- Interfaces and types: PascalCase (e.g., `Props`, `SeoOptions`, `Theme`)
- Constants: UPPER_SNAKE_CASE for config constants (not extensively used in codebase)
- Private/module state: camelCase prefixed with `_` if truly private
- Type aliases: PascalCase (e.g., `type Theme = 'light' | 'dark'`)
- Interface names: PascalCase (e.g., `interface Props`, `interface SeoOptions`)
- Props interfaces: Always named `Props` (e.g., in `<script setup lang="ts">` components)
- Generic types from Vue use their original names (e.g., `Ref<boolean>`, `Computed<string>`)
## Code Style
- Tool: Prettier 3.5.3
- Semi-colons: **disabled** (`semi: false`)
- Quotes: **single quotes** (`singleQuote: true`)
- Print width: **100 characters** (`printWidth: 100`)
- Tool: ESLint 9.22.0 with Vue support
- Config: `eslint.config.ts` using flat config format
- Plugins:
## Import Organization
- `@/` maps to `./src/` (configured in `tsconfig.app.json`)
- Always use `@/` prefix for imports from src directory
- Examples:
## Error Handling
- Try-catch blocks wrap risky operations (e.g., dynamic imports, DOM manipulation)
- Fallback values provided when operations fail:
- Console warnings for non-critical failures:
- Silent failures with fallbacks preferred over throwing errors for UI operations
## Logging
- `console.warn()` for warnings (missing assets, invalid input)
- Logging only in composables for utility functions
- No console.log() in production code (only development/debugging)
- Error context included: `console.warn('context', error)`
## Comments
- JSDoc comments for composable functions (exported functions)
- Inline comments for non-obvious logic (especially SEO handling in router)
- Comments explaining why (not what the code does)
- TODO comments for known issues: `// TODO: page 404` in `src/router/index.ts`
- Composables include JSDoc for exported functions
- Example from `useAssets.ts`:
- Not consistently applied across all files; use when function signature isn't obvious
## Function Design
- Props interfaces always named `Props` in components
- Use destructuring in setup: `const { t } = useI18n()`
- Optional config objects in composables (e.g., `SeoOptions` with defaults)
- Explicit typing on all parameters
- Composables return object with all exposed functions and reactive state
- Always return computed versions of reactive state when exposing refs:
- Functions return early on validation failures with fallbacks
## Module Design
- Composables export single named function: `export function useTheme() { ... }`
- Config files export named constants: `export const siteConfig: SiteConfig = { ... }`
- Type definitions export interfaces and types: `export interface Project { ... }`
- Data files export arrays or objects: `export const techStack: TechStack = { ... }`
- Not extensively used; direct imports preferred
- Only `src/types/index.ts` serves as barrel export for type definitions
- Components use direct imports: `import AppHeader from '@/components/layout/AppHeader.vue'`
- `<script setup lang="ts">` for all components (Vue 3 Composition API)
- Props validated with TypeScript interfaces
- Composables called at top of setup
- Computed properties for derived state
- Functions defined after setup calls
- `<template>` uses semantic HTML and accessibility attributes
- Scoped styles at bottom with `@import` for external stylesheets
## Type Safety
- Version: ~5.8.0
- DOM-focused (`tsconfig.dom.json` from @vue/tsconfig)
- Path alias `@/*` points to `./src/*`
- Type checking enabled in build: `npm run type-check` runs `vue-tsc --build`
- All component Props use interface definitions
- Composable return values typed explicitly
- Function parameters and return types annotated
- Type imports use `import type` syntax
- Avoid `any` type; use proper interfaces/generics
## Vue 3 Specific
- `<script setup>` syntax exclusively used
- No Options API in codebase
- Composables follow Composition API patterns
- `onMounted()` for initialization (theme loading, SEO setup)
- `onUnmounted()` for cleanup (removing DOM elements in useSeo)
- `watch()` for reactive side effects (theme changes)
- `ref()` for primitive state
- `computed()` for derived state
- Avoid unnecessary reactivity; use constants when possible
- Return computed versions of refs from composables
<!-- GSD:conventions-end -->
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
## Architecture
## Pattern Overview
- Client-side routing with lazy-loaded views for performance optimization
- Composition API-based composables for shared logic and state management
- Global state managed via Pinia stores
- Multi-language support with vue-i18n
- Theme switching with localStorage persistence
- SEO-optimized with dynamic meta tags and structured data
- Google Analytics and GTM integration for tracking
## Layers
- Purpose: Render UI and handle user interactions
- Location: `src/components/`
- Contains: Vue Single File Components organized by domain (layout, sections, shared, testimonials, icons)
- Depends on: Composables for data access and side effects, Router for navigation
- Used by: Views and other components
- Purpose: Page-level component assembly and routing targets
- Location: `src/views/`
- Contains: Full page components (HomePage, ProjectsPage, ContactPage, AboutPage, FiverrPage, FormationPage, ProjectDetailPage)
- Depends on: Composables (useSeo, useI18n, useProjects), components, data stores
- Used by: Router for navigation
- Purpose: Encapsulate reusable logic, data fetching, and side effects
- Location: `src/composables/`
- Contains: Vue composables for projects, SEO, i18n, themes, galleries, date formatting, assets, site config
- Depends on: Types, stores, external libraries (vue-router, vue-i18n)
- Used by: Components and views
- Purpose: Global state and static data management
- Location: `src/stores/`, `src/data/`
- Contains: Pinia stores, static project data, testimonials, tech stack, FAQs
- Depends on: Types, composables (useI18n for localized data)
- Used by: Composables and components
- Purpose: Application-wide settings and configuration
- Location: `src/config/`, `src/router/`, `src/i18n/`
- Contains: Site configuration, router setup, i18n initialization, locale messages
- Depends on: Types, data
- Used by: Main entry point and throughout app
- Purpose: TypeScript interfaces and types
- Location: `src/types/index.ts`
- Contains: Project, Technology, TechStack, SocialLink, ContactInfo, FiverrService, SiteConfig interfaces
## Data Flow
- **Global:** Pinia stores (currently minimal - `useCounterStore` exists but unused)
- **Composable State:** Reactive refs in composables (theme, locale, gallery state)
- **Component State:** Local reactive refs for UI state (menu toggle, form inputs)
- **Persistence:** localStorage for theme and locale preferences
- **Server-Side Data:** Static JSON-like data in `src/data/` files, not fetched from API
## Key Abstractions
- Purpose: Unified i18n access with convenience methods
- Examples: `src/composables/useI18n.ts`
- Pattern: Wraps vue-i18n's `useI18n()`, adds locale switching and computed locale state
- Usage: Available in all components via injection
- Purpose: Dynamic SEO tag management for SPA
- Examples: `src/composables/useSeo.ts`
- Pattern: Lifecycle hooks to create/remove meta tags on mount/unmount, prevents tag duplication
- Usage: Called in view components with options object for title, description, OG tags, structured data
- Purpose: Project data access with localization
- Examples: `src/composables/useProjects.ts`
- Pattern: Base data stored separately, computed properties merge translations on read
- Usage: Returns computed `projects` array that updates when language changes
- Purpose: Centralized theme state and persistence
- Examples: `src/composables/useTheme.ts`
- Pattern: Reactive boolean with computed getter, watch for persistence, DOM manipulation
- Usage: Injected globally in App.vue, consumed by ThemeToggle component
- Purpose: Typed structure for technology categories
- Examples: `src/types/index.ts`
- Pattern: Categorized array structure (programming, front, database, devtools, operating_systems, socials)
- Usage: Imported in `src/data/techstack.ts` and AboutPage.vue
- Purpose: Single source of truth for site-wide settings
- Examples: `src/config/site.ts`
- Pattern: Exported constant object with typed structure, includes contact info, social links, SEO config
- Usage: Imported where needed for links, contact info, performance settings
## Entry Points
- Location: `index.html`
- Triggers: Browser page load
- Responsibilities: Define DOM root (`#app`), load analytics/ads scripts, include meta tags, defer main.ts loading
- Location: `src/main.ts`
- Triggers: After HTML DOM ready
- Responsibilities: Create Vue app, install plugins (Pinia, Router, i18n), mount to #app
- Location: `src/router/index.ts`
- Triggers: App.use(router) in main.ts
- Responsibilities: Define route table, implement beforeEach/afterEach hooks for SEO and analytics
- Location: `src/App.vue`
- Triggers: After Vue app mounts
- Responsibilities: Initialize theme, render layout structure (header + router-view + footer), handle route-change scroll behavior
- Location: `src/views/*.vue`
- Triggers: Router navigation to matching path
- Responsibilities: Page-specific SEO setup via `useSeo()`, compose sections and content, manage page-level state
## Error Handling
- Lazy-loaded routes with no 404 component (TODO comment in router) - currently redirects to HomePage
- SEO composable safely creates/finds meta elements before updating
- Theme fallback to 'dark' if localStorage empty
- Locale fallback to 'en' if not in localStorage
- Gallery modal (GalleryModal.vue) handles missing images gracefully
- Contact form likely has validation but not visible in read scope
## Cross-Cutting Concerns
<!-- GSD:architecture-end -->
<!-- GSD:skills-start source:skills/ -->
## Project Skills
No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, or `.github/skills/` with a `SKILL.md` index file.
<!-- GSD:skills-end -->
<!-- GSD:workflow-start source:GSD defaults -->
## GSD Workflow Enforcement
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
Use these entry points:
- `/gsd-quick` for small fixes, doc updates, and ad-hoc tasks
- `/gsd-debug` for investigation and bug fixing
- `/gsd-execute-phase` for planned phase work
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
<!-- GSD:workflow-end -->
<!-- GSD:profile-start -->
## Developer Profile
> Profile not yet configured. Run `/gsd-profile-user` to generate your developer profile.
> This section is managed by `generate-claude-profile` -- do not edit manually.
<!-- GSD:profile-end -->