docs(02): create phase 2 content plans
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
---
|
||||
phase: 02-content
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: [02-01]
|
||||
files_modified:
|
||||
- app/pages/hytale.vue
|
||||
- app/components/sections/hytale/HytaleHeroSection.vue
|
||||
- app/components/sections/hytale/HytalePricingSection.vue
|
||||
- app/components/sections/hytale/HytaleServicesSection.vue
|
||||
autonomous: false
|
||||
requirements: [CONT-02, CONT-03, CONT-04]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "/hytale route exists and renders SSR HTML"
|
||||
- "Hytale page has 4 sections: hero, services, pricing, testimonials"
|
||||
- "Pricing grid shows 5 tiers with correct prices and CTAs"
|
||||
- "Each pricing CTA links to /contact"
|
||||
- "All text uses i18n t() — no hardcoded strings"
|
||||
- "Testimonials section shows all 5 on /hytale page"
|
||||
- "Page has useSeoMeta with hytale-specific title/description"
|
||||
artifacts:
|
||||
- path: "app/pages/hytale.vue"
|
||||
provides: "Hytale dedicated page with 4 sections"
|
||||
contains: "useSeoMeta"
|
||||
- path: "app/components/sections/hytale/HytaleHeroSection.vue"
|
||||
provides: "Hero section for /hytale page"
|
||||
contains: "t('hytale.hero"
|
||||
- path: "app/components/sections/hytale/HytalePricingSection.vue"
|
||||
provides: "Pricing grid with 5 tiers"
|
||||
contains: "hytalePricing"
|
||||
- path: "app/components/sections/hytale/HytaleServicesSection.vue"
|
||||
provides: "Services/expertise section"
|
||||
contains: "t('hytale.services"
|
||||
key_links:
|
||||
- from: "app/pages/hytale.vue"
|
||||
to: "app/components/sections/hytale/HytaleHeroSection.vue"
|
||||
via: "component composition"
|
||||
pattern: "HytaleHeroSection"
|
||||
- from: "app/components/sections/hytale/HytalePricingSection.vue"
|
||||
to: "app/data/pricing.ts"
|
||||
via: "import hytalePricing"
|
||||
pattern: "hytalePricing"
|
||||
- from: "app/components/sections/hytale/HytalePricingSection.vue"
|
||||
to: "/contact"
|
||||
via: "UButton :to localePath('/contact')"
|
||||
pattern: "localePath.*contact"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the dedicated /hytale page with hero, services, pricing grid, and testimonials sections.
|
||||
|
||||
Purpose: A visitor landing on /hytale sees Killian's Hytale plugin development services, transparent pricing tiers with CTAs to contact, and client testimonials proving track record (CONT-02, CONT-03, CONT-04).
|
||||
|
||||
Output: New hytale.vue page and 3 new section components in app/components/sections/hytale/.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/phases/02-content/02-CONTEXT.md
|
||||
@.planning/phases/02-content/02-RESEARCH.md
|
||||
@.planning/phases/02-content/02-UI-SPEC.md
|
||||
@.planning/phases/02-content/02-01-SUMMARY.md
|
||||
|
||||
@app/pages/index.vue
|
||||
@app/components/sections/HeroSection.vue
|
||||
@app/components/sections/TestimonialsSection.vue
|
||||
@app/data/pricing.ts
|
||||
@i18n/locales/fr.json
|
||||
|
||||
<interfaces>
|
||||
<!-- From shared/types/index.ts (plan 01): -->
|
||||
export interface PricingTier {
|
||||
id: string
|
||||
priceFixed: string | null
|
||||
priceLabel?: string
|
||||
featured?: boolean
|
||||
}
|
||||
|
||||
<!-- From app/data/pricing.ts (plan 01): -->
|
||||
export const hytalePricing: PricingTier[] // 5 tiers
|
||||
|
||||
<!-- From TestimonialsSection.vue (plan 02): -->
|
||||
// Accepts optional `featured` prop — omit prop to show all 5 testimonials
|
||||
|
||||
<!-- i18n keys available (plan 01): -->
|
||||
hytale.hero.label, hytale.hero.title, hytale.hero.subtitle,
|
||||
hytale.services.label, hytale.services.title, hytale.services.subtitle,
|
||||
hytale.pricing.label, hytale.pricing.title, hytale.pricing.subtitle,
|
||||
hytale.pricing.cta, hytale.pricing.popular, hytale.pricing.from,
|
||||
hytale.pricing.perMonth, hytale.pricing.onQuote,
|
||||
hytale.pricing.{tierId}.name, hytale.pricing.{tierId}.description,
|
||||
hytale.pricing.{tierId}.features.{0-3},
|
||||
seo.hytale.title, seo.hytale.description
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create hytale.vue page and 3 section components</name>
|
||||
<files>app/pages/hytale.vue, app/components/sections/hytale/HytaleHeroSection.vue, app/components/sections/hytale/HytalePricingSection.vue, app/components/sections/hytale/HytaleServicesSection.vue</files>
|
||||
<read_first>app/pages/index.vue, app/components/sections/HeroSection.vue, app/components/sections/ServicesSection.vue, app/data/pricing.ts</read_first>
|
||||
<action>
|
||||
Create 4 new files following existing project patterns (index.vue structure, section component patterns).
|
||||
|
||||
**1. app/pages/hytale.vue** — Follow index.vue pattern exactly (per D-08):
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
useSeoMeta({
|
||||
title: () => t('seo.hytale.title'),
|
||||
description: () => t('seo.hytale.description'),
|
||||
ogTitle: () => t('seo.hytale.title'),
|
||||
ogDescription: () => t('seo.hytale.description'),
|
||||
ogImage: 'https://killiandalcin.fr/og-image.png',
|
||||
ogType: 'website',
|
||||
})
|
||||
|
||||
useHead({
|
||||
script: [{
|
||||
type: 'application/ld+json',
|
||||
innerHTML: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Service',
|
||||
name: 'Hytale Plugin Development',
|
||||
provider: {
|
||||
'@type': 'Person',
|
||||
name: "Killian' DAL-CIN",
|
||||
jobTitle: 'Hytale Plugin Developer',
|
||||
},
|
||||
}),
|
||||
}],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<HytaleHeroSection />
|
||||
<HytaleServicesSection />
|
||||
<HytalePricingSection />
|
||||
<TestimonialsSection />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
Note: TestimonialsSection without `featured` prop shows all 5 testimonials (per D-15).
|
||||
|
||||
**2. app/components/sections/hytale/HytaleHeroSection.vue** — Simpler hero than homepage. Follow UI-SPEC:
|
||||
- Mono label: `{{ t('hytale.hero.label') }}` with `font-mono text-sm text-brand-500`
|
||||
- H1: `{{ t('hytale.hero.title') }}` with gradient text styling (same as homepage H1)
|
||||
- Subtitle: `{{ t('hytale.hero.subtitle') }}` with `text-lg text-gray-500 dark:text-gray-400`
|
||||
- Section padding: `py-16 md:py-24` (matching existing hero pattern)
|
||||
- Center-aligned, max-width container: `max-w-4xl mx-auto text-center`
|
||||
- Use `<script setup lang="ts">` with `const { t } = useI18n()`
|
||||
|
||||
**3. app/components/sections/hytale/HytaleServicesSection.vue** — Services/expertise:
|
||||
- Mono label: `{{ t('hytale.services.label') }}`
|
||||
- H2 title: `{{ t('hytale.services.title') }}`
|
||||
- Subtitle: `{{ t('hytale.services.subtitle') }}`
|
||||
- Display 3-4 service cards using `UCard` in a responsive grid `grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6`
|
||||
- Each card shows an icon (`UIcon` with lucide icons like `i-lucide-puzzle`, `i-lucide-settings`, `i-lucide-shield`), title, and short description
|
||||
- Service content via i18n keys. Create simple service items inline (not from data file — services are page-specific):
|
||||
- Plugin Development (i-lucide-puzzle)
|
||||
- Server Configuration (i-lucide-settings)
|
||||
- Maintenance & Support (i-lucide-shield-check)
|
||||
- Add i18n keys for service items: `hytale.services.items.{id}.title` and `hytale.services.items.{id}.description` — these keys MUST also be added to fr.json and en.json (executor: add them to both locale files).
|
||||
- Section padding: `py-16 md:py-24`, max-w-7xl container
|
||||
|
||||
**4. app/components/sections/hytale/HytalePricingSection.vue** — Pricing grid (per D-09, D-10, D-11, CONT-03, UI-SPEC):
|
||||
- Mono label: `{{ t('hytale.pricing.label') }}`
|
||||
- H2 title: `{{ t('hytale.pricing.title') }}`
|
||||
- Subtitle: `{{ t('hytale.pricing.subtitle') }}`
|
||||
- Import `hytalePricing` from `~/data/pricing`
|
||||
- Grid: `grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6` (5 tiers wrap to 3+2 or 2+3)
|
||||
- Each tier is a `UCard`:
|
||||
- If `tier.featured`, add `ring-2 ring-brand-500` class and `UBadge` with `{{ t('hytale.pricing.popular') }}`
|
||||
- Header: `{{ t('hytale.pricing.${tier.id}.name') }}` as h3
|
||||
- Price display: If `tier.priceFixed`, show `{{ t('hytale.pricing.from') }} {{ tier.priceFixed }}`. If not, show `{{ t('hytale.pricing.onQuote') }}`.
|
||||
- Description: `{{ t('hytale.pricing.${tier.id}.description') }}`
|
||||
- Features list: Loop 0-3, `{{ t('hytale.pricing.${tier.id}.features.${i}') }}` with `UIcon name="i-lucide-check"` prefix
|
||||
- Footer CTA: `UButton` with `{{ t('hytale.pricing.cta') }}`, `:to="localePath('/contact')"`, `block` prop, `color="primary"` for featured tier / `variant="outline"` for others
|
||||
- Hover effect on cards: `hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1 transition-all duration-200`
|
||||
- All text via i18n — zero hardcoded strings
|
||||
</action>
|
||||
<verify>
|
||||
<automated>test -f app/pages/hytale.vue && test -f app/components/sections/hytale/HytaleHeroSection.vue && test -f app/components/sections/hytale/HytalePricingSection.vue && test -f app/components/sections/hytale/HytaleServicesSection.vue && grep -q "useSeoMeta" app/pages/hytale.vue && grep -q "hytalePricing" app/components/sections/hytale/HytalePricingSection.vue && grep -q "localePath.*contact" app/components/sections/hytale/HytalePricingSection.vue && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `test -f app/pages/hytale.vue` succeeds (page exists)
|
||||
- `test -f app/components/sections/hytale/HytalePricingSection.vue` succeeds
|
||||
- `grep "useSeoMeta" app/pages/hytale.vue` shows SEO meta setup
|
||||
- `grep "hytalePricing" app/components/sections/hytale/HytalePricingSection.vue` shows data import
|
||||
- `grep "localePath" app/components/sections/hytale/HytalePricingSection.vue` shows CTA links to /contact
|
||||
- `grep "UCard" app/components/sections/hytale/HytalePricingSection.vue` shows Nuxt UI cards
|
||||
- `grep "t('hytale" app/components/sections/hytale/HytaleHeroSection.vue` shows i18n usage
|
||||
- No hardcoded French or English strings in any of the 4 files (except schema.org JSON-LD values which are language-neutral)
|
||||
</acceptance_criteria>
|
||||
<done>4 files created: hytale.vue page with SEO + JSON-LD, 3 section components. /hytale renders hero, services, pricing (5 tiers with CTAs to /contact), and all 5 testimonials.</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<name>Task 2: Verify /hytale page and homepage changes</name>
|
||||
<files>app/pages/hytale.vue</files>
|
||||
<action>Human visual verification of the complete phase 2 content delivery. Start dev server with `pnpm dev` if not running. Verify homepage hero, /hytale page, and navigation across FR and EN locales.</action>
|
||||
<verify>Human visual verification — no automated test</verify>
|
||||
<done>User approved homepage hero, /hytale page with pricing and testimonials, and bilingual content</done>
|
||||
<what-built>Complete Hytale content phase: homepage hero rebranded, /hytale page with pricing grid and testimonials, nav link added</what-built>
|
||||
<how-to-verify>
|
||||
1. Run `pnpm dev` if not already running
|
||||
2. Visit http://localhost:3000 — verify:
|
||||
- H1 says "Hytale Plugin Developer" (gradient text)
|
||||
- Badge says "Disponible pour vos projets" (FR) or "Available for projects" (EN)
|
||||
- Two CTAs: Discord + Contact
|
||||
- 3 featured testimonials shown (not all 5)
|
||||
3. Visit http://localhost:3000/hytale — verify:
|
||||
- Page loads with 4 sections: hero, services, pricing, testimonials
|
||||
- Pricing grid shows 5 tiers with prices and "Demander un devis" buttons
|
||||
- One tier has "Populaire" badge
|
||||
- All CTA buttons link to /contact
|
||||
- All 5 testimonials shown at bottom
|
||||
4. Visit http://localhost:3000/en/hytale — verify English content (no raw i18n keys visible)
|
||||
5. Check nav bar — /hytale link present in both desktop and mobile menu
|
||||
6. View page source (Ctrl+U) on /hytale — confirm SSR renders HTML content (not empty div)
|
||||
</how-to-verify>
|
||||
<resume-signal>Type "approved" or describe issues to fix</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| JSON-LD output | Schema.org structured data rendered in page head |
|
||||
| CTA links | Pricing buttons redirect to /contact |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-02-05 | I (Information Disclosure) | JSON-LD in hytale.vue | accept | Intentionally public structured data for SEO |
|
||||
| T-02-06 | T (Tampering) | Pricing data | accept | Static TypeScript data, no user input, SSR-rendered |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `curl localhost:3000/hytale` returns HTML with pricing tier content
|
||||
- `curl localhost:3000/hytale | grep -i "Hytale"` returns multiple matches
|
||||
- `curl localhost:3000/en/hytale` returns English content
|
||||
- `pnpm typecheck` passes
|
||||
- View source shows SSR-rendered content (not client-only)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- /hytale page exists with 4 sections, all content bilingual
|
||||
- Pricing grid shows 5 tiers with working CTAs to /contact
|
||||
- All 5 testimonials visible on /hytale, only 3 featured on homepage
|
||||
- SSR renders full HTML (no JS required to see content)
|
||||
- Human verification confirms visual quality
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/02-content/02-03-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user