- 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/
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 |
|
|
true |
|
|
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/
-
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' ] } ] -
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 } -
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' } ] -
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/
- app/data/projects.ts contains
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
- app/composables/useProjects.ts contains
<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> |
<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>