Files
portfolio/.planning/phases/01-foundation/01-02-PLAN.md
T
kayjaydee 1704da8ce5 docs(01): address checker revision issues
- Mark RESEARCH.md Open Questions as RESOLVED with decisions
- Fix Plan 01-02 Task 1 verify to be independent of Task 2 (file existence + grep check instead of typecheck)
- Strengthen negative criterion: all app/data/ files must NOT contain @/assets/images/
2026-04-07 23:45:00 +02:00

15 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
01-foundation 02 execute 2
01-01
app/data/projects.ts
app/data/testimonials.ts
app/data/faq.ts
app/data/techstack.ts
app/composables/useProjects.ts
public/images/
true
DATA-01
DATA-02
DATA-03
DATA-04
DATA-05
truths artifacts key_links
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/
path provides contains
app/data/projects.ts Donnees brutes des 7 projets export const projects
path provides contains
app/data/testimonials.ts Donnees temoignages export const testimonials
path provides contains
app/data/faq.ts Donnees FAQ avec cles i18n export const homeFAQs
path provides contains
app/data/techstack.ts Donnees tech stack export const techStack
path provides exports
app/composables/useProjects.ts Composable filtrage/recherche projets
useProjects
from to via pattern
app/composables/useProjects.ts app/data/projects.ts import direct import.*from.*data/projects
from to via pattern
app/data/projects.ts shared/types/index.ts type import 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/.

<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>

@.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 }

</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/
  1. Creer app/data/projects.ts (per D-01, D-02 — donnees separees, cles i18n):

    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'
        ]
      }
    ]
    
  2. Creer app/data/testimonials.ts — copie directe, juste changer l'import type:

    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
    }
    
  3. Creer app/data/faq.ts (per D-02 — cles i18n au lieu de texte):

    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'
      }
    ]
    
  4. Creer app/data/techstack.ts — copie avec chemins images mis a jour:

    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');" <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> 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):
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) cd C:/Users/minit/Desktop/portfolio/portfolio && npx nuxi typecheck 2>&1 | tail -5 <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> useProjects() retourne projects, featuredProjects, filterByCategory, search, findById — tout type-safe et style Nuxt natif

<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>
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

<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>
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`