--- 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" --- 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/. @C:/Users/minit/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/minit/.claude/get-shit-done/templates/summary.md @.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 ```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 } ``` Task 1: Migrer les donnees statiques et les images app/data/projects.ts, app/data/testimonials.ts, app/data/faq.ts, app/data/techstack.ts, public/images/ - 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) 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). 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');" - 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 4 fichiers data migres avec types corrects, images dans public/images/, aucune reference a @/assets/images/ dans aucun fichier app/data/ Task 2: Reecrire useProjects() en style Nuxt natif app/composables/useProjects.ts - src/composables/useProjects.ts (composable existant a reecrire) - app/data/projects.ts (donnees separees de Task 1) - shared/types/index.ts (interfaces) 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) { 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) cd C:/Users/minit/Desktop/portfolio/portfolio && npx nuxi typecheck 2>&1 | tail -5 - 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 useProjects() retourne projects, featuredProjects, filterByCategory, search, findById — tout type-safe et style Nuxt natif ## 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 | 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 - 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/ After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`