---
phase: 01-foundation
plan: 02
type: execute
wave: 2
depends_on: ["01-01"]
files_modified:
  - app/data/projects.ts
  - app/data/testimonials.ts
  - app/data/faq.ts
  - app/data/techstack.ts
  - app/composables/useProjects.ts
  - public/images/
autonomous: true
requirements:
  - DATA-01
  - DATA-02
  - DATA-03
  - DATA-04
  - DATA-05

must_haves:
  truths:
    - "Les donnees projets sont importables depuis app/data/projects.ts avec le type Project"
    - "Les donnees testimonials sont importables avec le type Testimonial"
    - "Les donnees FAQ utilisent des cles i18n et non du texte direct"
    - "Les donnees techstack sont importables avec le type TechStack"
    - "useProjects() retourne une liste typee et supporte filterByCategory, search, findById"
    - "Toutes les images referenceent /images/ et non @/assets/images/"
  artifacts:
    - path: "app/data/projects.ts"
      provides: "Donnees brutes des 7 projets"
      contains: "export const projects"
    - path: "app/data/testimonials.ts"
      provides: "Donnees temoignages"
      contains: "export const testimonials"
    - path: "app/data/faq.ts"
      provides: "Donnees FAQ avec cles i18n"
      contains: "export const homeFAQs"
    - path: "app/data/techstack.ts"
      provides: "Donnees tech stack"
      contains: "export const techStack"
    - path: "app/composables/useProjects.ts"
      provides: "Composable filtrage/recherche projets"
      exports: ["useProjects"]
  key_links:
    - from: "app/composables/useProjects.ts"
      to: "app/data/projects.ts"
      via: "import direct"
      pattern: "import.*from.*data/projects"
    - from: "app/data/projects.ts"
      to: "shared/types/index.ts"
      via: "type import"
      pattern: "import type.*Project"
---

<objective>
Migrer toutes les donnees statiques vers app/data/, copier les images vers public/images/, et reecrire useProjects() en style Nuxt natif.

Purpose: Les donnees du portfolio sont disponibles et typees pour les phases suivantes.
Output: 4 fichiers data, 1 composable, images dans public/images/.
</objective>

<execution_context>
@C:/Users/minit/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/minit/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-foundation/01-CONTEXT.md
@.planning/phases/01-foundation/01-RESEARCH.md
@.planning/phases/01-foundation/01-01-SUMMARY.md

<interfaces>
<!-- Types crees par Plan 01 dans shared/types/index.ts -->
```typescript
export interface Project {
  id: string
  image: string
  technologies: string[]
  category: string
  date: string
  featured?: boolean
  buttons?: ProjectButton[]
  gallery?: string[]
  demoUrl?: string
  githubUrl?: string
  features?: string[]
}

export interface ProjectButton {
  title: string
  link: string
}

export interface Technology {
  name: string
  level: 'Beginner' | 'Intermediate' | 'Advanced'
  image: string
}

export interface TechStack {
  programming: Technology[]
  front: Technology[]
  database: Technology[]
  devtools: Technology[]
  operating_systems: Technology[]
  socials: Technology[]
}

export interface Testimonial {
  name: string
  role: string
  company: string
  avatar: string
  rating: number
  content: string
  date: string
  platform: string
  featured?: boolean
  project_type: string
  results?: string[]
}

export interface TestimonialsStats {
  totalReviews: number
  averageRating: number
  projectsCompleted: number
}

export interface FAQ {
  questionKey: string
  answerKey: string
  featuresKey: string
}
```
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Migrer les donnees statiques et les images</name>
  <files>app/data/projects.ts, app/data/testimonials.ts, app/data/faq.ts, app/data/techstack.ts, public/images/</files>
  <read_first>
    - src/composables/useProjects.ts (donnees projets inline a extraire)
    - src/data/testimonials.ts (donnees + interface existantes)
    - src/data/faq.ts (donnees + pattern getHomeFAQs existant)
    - src/data/techstack.ts (donnees existantes)
    - shared/types/index.ts (interfaces resserrees de Plan 01)
  </read_first>
  <action>
1. Copier toutes les images WebP de `src/assets/images/` vers `public/images/` (per D-06, D-07):
   ```bash
   mkdir -p public/images/flowboard
   cp src/assets/images/*.webp public/images/
   cp src/assets/images/flowboard/*.webp public/images/flowboard/
   ```

2. Creer `app/data/projects.ts` (per D-01, D-02 — donnees separees, cles i18n):
   ```typescript
   import type { Project } from '~~/shared/types'

   export const projects: Project[] = [
     {
       id: 'virtual-tour',
       image: '/images/virtualtour.webp',
       technologies: ['Vue.js', 'Three.js', 'WebGL', 'Node.js'],
       category: 'Web Development',
       date: '2022',
       buttons: [
         { title: 'Visit', link: 'https://www.lycee-chabanne16.fr/visites/BACSN/index.htm' }
       ]
     },
     {
       id: 'xinko',
       image: '/images/xinko.webp',
       technologies: ['Node.js', 'Discord.js', 'MongoDB', 'Express'],
       category: 'Bot Development',
       date: '2023',
       featured: true,
       buttons: [
         { title: 'Invite', link: 'https://discord.com/api/oauth2/authorize?client_id=1035571329866407976&permissions=292288982151&scope=applications.commands%20bot' }
       ]
     },
     {
       id: 'image-manipulation',
       image: '/images/dig.webp',
       technologies: ['JavaScript', 'Node.js', 'Canvas', 'npm'],
       category: 'Open Source',
       date: '2022',
       featured: true,
       buttons: [
         { title: 'Repository', link: 'https://git.mrkayjaydee.xyz/Mr-KayJayDee/discord-image-generation' },
         { title: 'NPM Package', link: 'https://www.npmjs.com/package/discord-image-generation' }
       ]
     },
     {
       id: 'primate-web-admin',
       image: '/images/primate.webp',
       technologies: ['React', 'TypeScript', 'Node.js', 'Express'],
       category: 'Enterprise Software',
       date: '2023'
     },
     {
       id: 'instagram-bot',
       image: '/images/instagram.webp',
       technologies: ['JavaScript', 'Node.js', 'Instagram API', 'Canvas'],
       category: 'Social Media Bot',
       date: '2022',
       buttons: [
         { title: 'Repository', link: 'https://git.mrkayjaydee.xyz/Mr-KayJayDee/instagram-bot' }
       ]
     },
     {
       id: 'crowdin-status-bot',
       image: '/images/crowdin.webp',
       technologies: ['Node.js', 'Discord.js', 'Crowdin API', 'Cron'],
       category: 'Automation',
       date: '2023',
       buttons: [
         { title: 'Repository', link: 'https://git.mrkayjaydee.xyz/Mr-KayJayDee/discord-crowdin-status' }
       ]
     },
     {
       id: 'flowboard',
       image: '/images/flowboard/flowboard_1.webp',
       technologies: ['Vue.js', 'Node.js', 'TypeScript', 'MongoDB', 'Express'],
       category: 'Web Development',
       date: '2024',
       featured: true,
       features: [
         'Organize your tasks, projects and ideas by creating thematic boards adapted to your needs',
         'Add cards for each task, assign members, set due dates, and track progress at a glance',
         'Invite colleagues and teammates to join your boards to work together, share ideas, and coordinate your efforts',
         'Keep an overview of the progress of your projects thanks to a simple and intuitive interface',
         'Use labels, lists and tables to prioritize tasks, set priorities and keep the overview clear'
       ],
       gallery: [
         '/images/flowboard/flowboard_1.webp',
         '/images/flowboard/flowboard_2.webp',
         '/images/flowboard/flowboard_3.webp',
         '/images/flowboard/flowboard_4.webp'
       ]
     }
   ]
   ```

3. Creer `app/data/testimonials.ts` — copie directe, juste changer l'import type:
   ```typescript
   import type { Testimonial, TestimonialsStats } from '~~/shared/types'

   export const testimonials: Testimonial[] = [
     // ... (copier les 5 temoignages existants tels quels de src/data/testimonials.ts)
   ]

   export const testimonialsStats: TestimonialsStats = {
     totalReviews: 10,
     averageRating: 5.0,
     projectsCompleted: 25
   }
   ```

4. Creer `app/data/faq.ts` (per D-02 — cles i18n au lieu de texte):
   ```typescript
   import type { FAQ } from '~~/shared/types'

   export const homeFAQs: FAQ[] = [
     {
       questionKey: 'faq.homeFaq.delivery.question',
       answerKey: 'faq.homeFaq.delivery.answer',
       featuresKey: 'faq.homeFaq.delivery.features'
     },
     {
       questionKey: 'faq.homeFaq.maintenance.question',
       answerKey: 'faq.homeFaq.maintenance.answer',
       featuresKey: 'faq.homeFaq.maintenance.features'
     },
     {
       questionKey: 'faq.homeFaq.companies.question',
       answerKey: 'faq.homeFaq.companies.answer',
       featuresKey: 'faq.homeFaq.companies.features'
     }
   ]
   ```

5. Creer `app/data/techstack.ts` — copie avec chemins images mis a jour:
   ```typescript
   import type { TechStack } from '~~/shared/types'

   export const techStack: TechStack = {
     // ... (copier depuis src/data/techstack.ts, remplacer TOUS les `@/assets/images/xxx.webp` par `/images/xxx.webp`)
   }
   ```
   Remplacement a effectuer: `@/assets/images/` -> `/images/` pour CHAQUE entree (60+ images).
  </action>
  <verify>
    <automated>cd C:/Users/minit/Desktop/portfolio/portfolio && node -e "const fs=require('fs'); const files=['app/data/projects.ts','app/data/testimonials.ts','app/data/faq.ts','app/data/techstack.ts']; let ok=true; for(const f of files){if(!fs.existsSync(f)){console.log('MISSING: '+f);ok=false;}else{const c=fs.readFileSync(f,'utf8');if(c.includes('@/assets/images/')){console.log('FAIL: '+f+' still contains @/assets/images/');ok=false;}}} if(!fs.existsSync('public/images')){console.log('MISSING: public/images/');ok=false;} console.log(ok?'PASS':'FAIL');"</automated>
  </verify>
  <acceptance_criteria>
    - app/data/projects.ts contains `export const projects: Project[]`
    - app/data/projects.ts contains `/images/virtualtour.webp` (not `@/assets/images/`)
    - app/data/projects.ts contains 7 project objects (virtual-tour through flowboard)
    - app/data/testimonials.ts contains `export const testimonials: Testimonial[]`
    - app/data/testimonials.ts contains `export const testimonialsStats: TestimonialsStats`
    - app/data/faq.ts contains `export const homeFAQs: FAQ[]`
    - app/data/faq.ts contains `questionKey:` (i18n keys, not direct text)
    - app/data/techstack.ts contains `export const techStack: TechStack`
    - app/data/techstack.ts does NOT contain `@/assets/images/` (all paths migrated)
    - app/data/projects.ts does NOT contain `@/assets/images/` (all paths migrated)
    - No file in app/data/ contains `@/assets/images/`
    - public/images/ directory contains .webp files
  </acceptance_criteria>
  <done>4 fichiers data migres avec types corrects, images dans public/images/, aucune reference a @/assets/images/ dans aucun fichier app/data/</done>
</task>

<task type="auto">
  <name>Task 2: Reecrire useProjects() en style Nuxt natif</name>
  <files>app/composables/useProjects.ts</files>
  <read_first>
    - src/composables/useProjects.ts (composable existant a reecrire)
    - app/data/projects.ts (donnees separees de Task 1)
    - shared/types/index.ts (interfaces)
  </read_first>
  <action>
Creer `app/composables/useProjects.ts` en style Nuxt natif (per D-04, D-05):

```typescript
import { projects as projectsData } from '~/data/projects'

export function useProjects() {
  const { t } = useI18n()

  const projects = computed(() =>
    projectsData.map(p => ({
      ...p,
      title: t(`projects.${p.id}.title`),
      description: t(`projects.${p.id}.description`),
      longDescription: t(`projects.${p.id}.longDescription`) || undefined
    }))
  )

  const featuredProjects = computed(() =>
    projects.value.filter(p => p.featured)
  )

  function filterByCategory(category: string) {
    return computed(() =>
      projects.value.filter(p => p.category === category)
    )
  }

  function search(query: Ref<string> | string) {
    return computed(() => {
      const q = typeof query === 'string' ? query : query.value
      if (!q) return projects.value
      const lower = q.toLowerCase()
      return projects.value.filter(p =>
        p.title.toLowerCase().includes(lower) ||
        p.description.toLowerCase().includes(lower) ||
        p.technologies.some(tech => tech.toLowerCase().includes(lower))
      )
    })
  }

  function findById(id: string) {
    return computed(() => projects.value.find(p => p.id === id))
  }

  return {
    projects,
    featuredProjects,
    filterByCategory,
    search,
    findById
  }
}
```

Points cles per D-04:
- Pas d'import `computed`, `useI18n` — auto-importes par Nuxt
- Import des donnees depuis `~/data/projects` (pas `@/`)
- Pas de wrapper useI18n custom — utilise directement l'auto-import @nuxtjs/i18n
- Les cles i18n suivent le pattern `projects.${id}.title` (per D-02)
  </action>
  <verify>
    <automated>cd C:/Users/minit/Desktop/portfolio/portfolio && npx nuxi typecheck 2>&1 | tail -5</automated>
  </verify>
  <acceptance_criteria>
    - app/composables/useProjects.ts contains `export function useProjects()`
    - app/composables/useProjects.ts contains `import { projects as projectsData } from '~/data/projects'`
    - app/composables/useProjects.ts contains `const { t } = useI18n()`
    - app/composables/useProjects.ts contains `filterByCategory`
    - app/composables/useProjects.ts contains `search`
    - app/composables/useProjects.ts contains `findById`
    - app/composables/useProjects.ts contains `featuredProjects`
    - app/composables/useProjects.ts does NOT contain `import { computed }` (auto-imported)
    - app/composables/useProjects.ts does NOT contain `from '@/composables/useI18n'`
    - npx nuxi typecheck exits with code 0
  </acceptance_criteria>
  <done>useProjects() retourne projects, featuredProjects, filterByCategory, search, findById — tout type-safe et style Nuxt natif</done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| Aucune | Donnees statiques, pas d'input utilisateur |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-01-03 | I (Information Disclosure) | testimonials avatars | accept | URLs ui-avatars.com publiques, pas de PII |
</threat_model>

<verification>
1. `npx nuxi typecheck` exit 0
2. Aucun fichier dans app/data/ ne contient `@/assets/images/`
3. app/composables/useProjects.ts exporte useProjects avec 5 fonctions/proprietes
4. public/images/ contient les fichiers WebP
</verification>

<success_criteria>
- Les 4 fichiers data existent et sont type-safe
- useProjects() compile sans erreur
- Images disponibles dans public/images/
- Aucune reference aux anciens chemins @/assets/images/
</success_criteria>

<output>
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`
</output>
