Files
portfolio/.planning/phases/03-pages-ship/03-02-PLAN.md
T
kayjaydee 3e38ea02b1 docs(03): create phase 3 plans — pages, components, Docker SSR
4 plans across 3 waves: shared components + deps (wave 1),
pages landing/projects/detail + about/contact/fiverr/404 (wave 2),
Dockerfile SSR + GA4 + docker-compose (wave 3).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:25:28 +02:00

10 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
03-pages-ship 02 execute 2
03-01
app/pages/index.vue
app/pages/projects.vue
app/pages/project/[id].vue
true
PAGE-01
PAGE-02
PAGE-03
truths artifacts key_links
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()
path provides
app/pages/index.vue Landing page avec 6 sections
path provides
app/pages/projects.vue Liste projets avec filtres
path provides
app/pages/project/[id].vue Detail projet avec galerie
from to via pattern
app/pages/index.vue app/components/sections/*.vue auto-import composants HeroSection|FeaturedProjectsSection|ServicesSection
from to via pattern
app/pages/project/[id].vue app/components/ProjectGallery.vue useTemplateRef + openGallery 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/.

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

export const homeFAQs: FAQ[]  // { questionKey, answerKey, featuresKey }

From app/data/testimonials.ts:

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. <HeroSection /> — auto-importe, texte seul (per D-02)
  2. <FeaturedProjectsSection /> — auto-importe, 3 projets featured (per D-03)
  3. <ServicesSection /> — auto-importe
  4. <TestimonialsSection> — passer les props i18n depuis t(), importer testimonials et testimonialsStats depuis ~/data/testimonials
  5. <FAQSection> — passer homeFAQs depuis ~/data/faq et titres i18n
  6. <CTASection /> — 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 <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> 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 <ProjectCard :project="project" /> 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
    • <ProjectGallery ref="gallery" :gallery="project.gallery" :project-title="project.title" /> 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

<threat_model>

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
</threat_model>
- `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

<success_criteria>

  • 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() </success_criteria>
After completion, create `.planning/phases/03-pages-ship/03-02-SUMMARY.md`