--- phase: 03-pages-ship plan: 02 type: execute wave: 2 depends_on: ["03-01"] files_modified: - app/pages/index.vue - app/pages/projects.vue - app/pages/project/[id].vue autonomous: true requirements: - PAGE-01 - PAGE-02 - PAGE-03 must_haves: truths: - "Landing page affiche 6 sections : Hero, FeaturedProjects, Services, Testimonials, FAQ, CTA" - "Projects page filtre par recherche texte et boutons categorie" - "Project detail affiche description, features, technologies, galerie modale" - "Chaque page a ses metadonnees SEO via useSeoMeta()" artifacts: - path: "app/pages/index.vue" provides: "Landing page avec 6 sections" - path: "app/pages/projects.vue" provides: "Liste projets avec filtres" - path: "app/pages/project/[id].vue" provides: "Detail projet avec galerie" key_links: - from: "app/pages/index.vue" to: "app/components/sections/*.vue" via: "auto-import composants" pattern: "HeroSection|FeaturedProjectsSection|ServicesSection" - from: "app/pages/project/[id].vue" to: "app/components/ProjectGallery.vue" via: "useTemplateRef + openGallery" pattern: "ProjectGallery|openGallery" --- Construire les 3 pages principales du portfolio : Landing (accueil), Projects (liste), et Project Detail (detail + galerie). Ces pages consomment les composants crees en Plan 01. Purpose: Ce sont les pages les plus visitees du portfolio — la landing convertit les visiteurs, la liste projets montre le travail, et le detail permet l'exploration approfondie. Output: 3 pages fonctionnelles dans app/pages/. @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/phases/03-pages-ship/03-CONTEXT.md @.planning/phases/03-pages-ship/03-RESEARCH.md @.planning/phases/03-pages-ship/03-01-SUMMARY.md @src/views/HomePage.vue @src/views/ProjectsPage.vue @src/views/ProjectDetailPage.vue @app/composables/useProjects.ts @app/data/projects.ts @app/data/testimonials.ts @app/data/faq.ts From app/composables/useProjects.ts: ```typescript export function useProjects(): { projects: ComputedRef featuredProjects: ComputedRef filterByCategory(cat: string): ComputedRef search(query: Ref | string): ComputedRef findById(id: string): ComputedRef } ``` From app/data/faq.ts: ```typescript export const homeFAQs: FAQ[] // { questionKey, answerKey, featuresKey } ``` From app/data/testimonials.ts: ```typescript export const testimonials: Testimonial[] export const testimonialsStats: TestimonialsStats ``` Composants disponibles (auto-importes, crees en Plan 01): - HeroSection — pas de props (utilise i18n interne) - FeaturedProjectsSection — pas de props (utilise useProjects interne) - ServicesSection — pas de props (utilise i18n interne) - TestimonialsSection — props: title, subtitle, testimonials, stats, statsLabels, ctaTitle, ctaSubtitle, ctaText, ctaLink - FAQSection — props: faqs (FAQ[]), title, subtitle - CTASection — pas de props (utilise i18n interne) - ProjectCard — props: project (Project) - ProjectGallery — props: gallery (string[]), projectTitle (string); expose: openGallery(index) - TechBadge — props: tech (Technology | string), showLevel?, showImage? Task 1: Page Landing (index.vue) avec 6 sections app/pages/index.vue Remplacer le contenu stub de `app/pages/index.vue` par la page landing complete (per D-01, D-02, D-03). Structure exacte — 6 sections dans cet ordre (per D-01) : 1. `` — auto-importe, texte seul (per D-02) 2. `` — auto-importe, 3 projets featured (per D-03) 3. `` — auto-importe 4. `` — passer les props i18n depuis `t()`, importer `testimonials` et `testimonialsStats` depuis `~/data/testimonials` 5. `` — passer `homeFAQs` depuis `~/data/faq` et titres i18n 6. `` — auto-importe SEO via `useSeoMeta()` : titre, description, og:title, og:description, og:image (per SEO-01). Conserver le JSON-LD Person + ProfessionalService deja present dans le stub via `useHead({ script })`. Wrapper `
` pour le contenu selon le layout Phase 2 (D-16 max-w-7xl). cd C:/Users/minit/Desktop/portfolio/portfolio && grep -c "Section" app/pages/index.vue | grep -q "[456789]" && grep -q "useSeoMeta" app/pages/index.vue && echo "PASS" Page landing avec 6 sections dans l'ordre Hero > FeaturedProjects > Services > Testimonials > FAQ > CTA, SEO meta configurees Task 2: Page Projects (projects.vue) avec filtres recherche + categorie app/pages/projects.vue Remplacer le stub `app/pages/projects.vue` par la page projets complete (per D-04, PAGE-02). Migrer depuis `src/views/ProjectsPage.vue` en adaptant pour Nuxt : 1. **Script setup** : `const { projects } = useProjects()` (auto-import). Refs : `searchQuery`, `selectedCategory` (defaut 'all'). Computed `categories` : `['all', ...new Set(projects.value.map(p => p.category))]`. Computed `filteredProjects` : filtre par searchQuery (titre, description, technologies) puis par selectedCategory. 2. **Template** : - Section hero : titre `t('projects.title')`, sous-titre, stats (total projets, featured, categories) - Section filtres (per D-04) : `UInput` pour recherche avec icone search (`icon="i-lucide-search"`) + boutons categorie `UButton` pour chaque categorie (variant `soft` pour inactif, `solid` pour actif). PAS de select/dropdown — boutons cliquables comme l'actuel. - Grille projets : `grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6`. Utiliser `` pour chaque projet filtre. - Etat vide : message "Aucun resultat" avec bouton reset filtres. 3. **SEO** : `useSeoMeta()` avec titre, description, og specifiques a la page projets. cd C:/Users/minit/Desktop/portfolio/portfolio && grep -q "filteredProjects" app/pages/projects.vue && grep -q "searchQuery" app/pages/projects.vue && grep -q "ProjectCard" app/pages/projects.vue && echo "PASS" Page projects avec recherche texte + filtres categorie boutons, grille ProjectCard, etat vide, SEO meta Task 3: Page Project Detail (project/[id].vue) avec galerie modale app/pages/project/[id].vue Creer `app/pages/project/[id].vue` — route dynamique (per PAGE-03). Migrer depuis `src/views/ProjectDetailPage.vue` : 1. **Script setup** : - `const route = useRoute()` puis `const { findById } = useProjects()` - `const project = findById(route.params.id as string)` - 404 si non trouve : `if (!project.value) throw createError({ status: 404, statusText: 'Project not found' })` (per RESEARCH.md Code Examples) - `const galleryRef = useTemplateRef('gallery')` pour acceder a ProjectGallery.openGallery - Computed `relatedProjects` : meme categorie, exclure le projet courant, slice(0, 3) - `useSeoMeta()` avec titre du projet, description 2. **Template** : - Breadcrumb : `UButton variant="link"` vers /projects avec icone fleche retour - Hero grid 2 colonnes : image principale `NuxtImg` a gauche, infos (categorie, date, titre, description, boutons CTA) a droite - Boutons CTA : `UButton` pour demo, source code, boutons custom du projet - Section "A propos" : longDescription ou description, liste features avec checkmarks - Section technologies : grille `TechBadge` pour chaque tech - Section galerie : grille thumbnails cliquables. Au clic sur une image : `galleryRef.value?.openGallery(index)`. Chaque thumbnail : `NuxtImg` avec overlay zoom au hover. - Sidebar : card infos projet (date, categorie, status) + projets lies `NuxtLink` - `` en bas du template 3. **Responsive** : layout 2 colonnes (main + sidebar) sur desktop, stack sur mobile. cd C:/Users/minit/Desktop/portfolio/portfolio && test -f app/pages/project/\[id\].vue && grep -q "findById" app/pages/project/\[id\].vue && grep -q "ProjectGallery" app/pages/project/\[id\].vue && grep -q "createError" app/pages/project/\[id\].vue && echo "PASS" Page project detail avec route dynamique [id], 404 si non trouve, galerie modale via ProjectGallery, projets lies, SEO meta ## Trust Boundaries | Boundary | Description | |----------|-------------| | URL params -> findById | route.params.id est une entree utilisateur | ## STRIDE Threat Register | Threat ID | Category | Component | Disposition | Mitigation Plan | |-----------|----------|-----------|-------------|-----------------| | T-03-05 | Tampering | project/[id].vue | mitigate | createError(404) si projet non trouve — pas d'injection possible via les donnees statiques | - `npx nuxi dev` puis naviguer vers `/` — 6 sections visibles - `/projects` — filtres fonctionnels, cards affichees - `/project/flowboard` — detail avec galerie, clic image ouvre modal - `/project/inexistant` — redirige vers page 404 - `curl http://localhost:3000/` contient les balises meta SEO - Landing affiche les 6 sections dans l'ordre correct (per D-01) - Hero est texte seul, pas d'image (per D-02) - 3 projets featured affiches (per D-03) - Projects page a recherche texte + boutons categorie (per D-04) - Project detail a galerie modale UModal+UCarousel fonctionnelle - Route /project/[id] inexistant retourne 404 - Toutes les pages ont useSeoMeta() After completion, create `.planning/phases/03-pages-ship/03-02-SUMMARY.md`