8.0 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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-ssr-shell | 03 | execute | 2 |
|
|
true |
|
|
Purpose: Every route returns correct, unique, localized SEO tags in server-rendered HTML — verifiable by curl. Output: 6 page files with useSeoMeta(), homepage with JSON-LD, all with og:image.
<execution_context>
@/.claude/get-shit-done/workflows/execute-plan.md
@/.claude/get-shit-done/templates/summary.md
</execution_context>
Pattern for every page (example: projects.vue):
<script setup lang="ts">
const { t } = useI18n()
useSeoMeta({
title: () => t('seo.projects.title'),
description: () => t('seo.projects.description'),
ogTitle: () => t('seo.projects.title'),
ogDescription: () => t('seo.projects.description'),
ogImage: 'https://killiandalcin.fr/og-image.png',
ogImageWidth: 1200,
ogImageHeight: 630,
ogType: 'website',
})
</script>
<template>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h1 class="text-2xl font-bold">{{ t('nav.projects') }}</h1>
<p class="text-gray-600 dark:text-gray-400 mt-4">Phase 3 content placeholder</p>
</div>
</template>
Apply this pattern to all 6 pages using their respective seo.{page}.title and seo.{page}.description keys:
- index.vue → seo.home.*
- projects.vue → seo.projects.*
- about.vue → seo.about.*
- contact.vue → seo.contact.*
- fiverr.vue → seo.fiverr.*
- formation.vue → seo.formation.*
All pages use ogImage: 'https://killiandalcin.fr/og-image.png' (per user decision: static image, no nuxt-og-image).
Homepage (index.vue) ADDITIONALLY gets JSON-LD (per D-11, SEO-02):
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: JSON.stringify({
'@context': 'https://schema.org',
'@graph': [
{
'@type': 'Person',
name: 'Killian Dalcin',
url: 'https://killiandalcin.fr',
jobTitle: 'Developpeur Full Stack Freelance',
email: 'contact@killiandalcin.fr',
sameAs: [
'https://linkedin.com/in/killian-dal-cin',
'https://www.fiverr.com/users/mr_kayjaydee',
'https://gitea.kamisama.ovh/kayjaydee',
],
},
{
'@type': 'ProfessionalService',
name: 'Killian Dalcin - Developpeur Full Stack',
url: 'https://killiandalcin.fr',
logo: 'https://killiandalcin.fr/images/logo.webp',
priceRange: '$$$',
areaServed: 'Worldwide',
},
],
}),
},
],
})
Create pages that do not yet exist (projects.vue, about.vue, contact.vue, fiverr.vue, formation.vue) as new files. Update existing index.vue.
Each stub page template should have:
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">wrapper (per D-16)- An
<h1>using the nav translation key - A placeholder paragraph
grep -q "useSeoMeta" app/pages/index.vue && grep -q "application/ld+json" app/pages/index.vue && grep -q "useSeoMeta" app/pages/projects.vue && grep -q "useSeoMeta" app/pages/about.vue && grep -q "useSeoMeta" app/pages/contact.vue && grep -q "useSeoMeta" app/pages/fiverr.vue && grep -q "useSeoMeta" app/pages/formation.vue && grep -q "og-image.png" app/pages/index.vue && echo "PASS" || echo "FAIL"
<acceptance_criteria>
- All 6 page files exist under app/pages/
- Every page contains
useSeoMetawith title, description, ogTitle, ogDescription, ogImage - ogImage value is
https://killiandalcin.fr/og-image.pngon every page - index.vue contains
application/ld+jsonwithPersonandProfessionalService - index.vue JSON-LD contains
sameAsarray with LinkedIn, Fiverr, Gitea URLs - Each page uses localized seo keys:
t('seo.home.title'),t('seo.projects.title'), etc. - Each page template has
max-w-7xl mx-autowrapper npx nuxi typecheckpasses </acceptance_criteria> All 6 routes have unique, localized SEO metadata via useSeoMeta(). Homepage includes JSON-LD with Person + ProfessionalService schema. Every page has og:image with absolute URL.
<threat_model>
Trust Boundaries
| Boundary | Description |
|---|---|
| SEO meta tags | Server-rendered meta tags include user-controlled translation values |
STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|---|---|---|---|---|
| T-02-06 | Injection | JSON-LD innerHTML | mitigate | JSON.stringify() escapes special characters; no user input in JSON-LD — all values are hardcoded constants |
| T-02-07 | Information Disclosure | og:image URL | accept | Public URL pointing to public image — no sensitive data |
| </threat_model> |