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).
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 |
|
|
true |
|
|
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?
Structure exacte — 6 sections dans cet ordre (per D-01) :
<HeroSection />— auto-importe, texte seul (per D-02)<FeaturedProjectsSection />— auto-importe, 3 projets featured (per D-03)<ServicesSection />— auto-importe<TestimonialsSection>— passer les props i18n depuist(), importertestimonialsettestimonialsStatsdepuis~/data/testimonials<FAQSection>— passerhomeFAQsdepuis~/data/faqet titres i18n<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
Migrer depuis src/views/ProjectsPage.vue en adaptant pour Nuxt :
-
Script setup :
const { projects } = useProjects()(auto-import). Refs :searchQuery,selectedCategory(defaut 'all'). Computedcategories:['all', ...new Set(projects.value.map(p => p.category))]. ComputedfilteredProjects: filtre par searchQuery (titre, description, technologies) puis par selectedCategory. -
Template :
- Section hero : titre
t('projects.title'), sous-titre, stats (total projets, featured, categories) - Section filtres (per D-04) :
UInputpour recherche avec icone search (icon="i-lucide-search") + boutons categorieUButtonpour chaque categorie (variantsoftpour inactif,solidpour 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.
- Section hero : titre
-
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
Migrer depuis src/views/ProjectDetailPage.vue :
-
Script setup :
const route = useRoute()puisconst { 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
-
Template :
- Breadcrumb :
UButton variant="link"vers /projects avec icone fleche retour - Hero grid 2 colonnes : image principale
NuxtImga gauche, infos (categorie, date, titre, description, boutons CTA) a droite - Boutons CTA :
UButtonpour demo, source code, boutons custom du projet - Section "A propos" : longDescription ou description, liste features avec checkmarks
- Section technologies : grille
TechBadgepour chaque tech - Section galerie : grille thumbnails cliquables. Au clic sur une image :
galleryRef.value?.openGallery(index). Chaque thumbnail :NuxtImgavec 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
- Breadcrumb :
-
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> |
<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>