jedmund-svelte/prd/PRD-seo-metadata-system-v2.md

4.8 KiB

PRD: SEO & Metadata System - V2

Executive Summary

This updated PRD acknowledges the existing comprehensive SEO metadata implementation on jedmund.com and focuses on the remaining gaps: dynamic sitemap generation, OG image generation for text content, and metadata testing/validation.

Current State Assessment

Already Implemented

  • Metadata utilities (/src/lib/utils/metadata.ts) providing:
    • Complete OpenGraph and Twitter Card support
    • JSON-LD structured data generators
    • Smart title formatting and fallbacks
    • Canonical URL handling
  • 100% page coverage with appropriate metadata
  • Dynamic content support with excerpt generation
  • Error handling with noindex for 404 pages

Remaining Gaps

  1. No dynamic sitemap.xml
  2. No OG image generation API for text-based content
  3. No automated metadata validation
  4. robots.txt doesn't reference sitemap

Revised Goals

  1. Complete technical SEO with dynamic sitemap generation
  2. Enhance social sharing with generated OG images for text content
  3. Ensure quality with metadata validation tools
  4. Improve discoverability with complete robots.txt

Proposed Implementation

Phase 1: Dynamic Sitemap (Week 1)

Create /src/routes/sitemap.xml/+server.ts

export async function GET() {
	const pages = await getAllPublicPages()
	const xml = generateSitemapXML(pages)

	return new Response(xml, {
		headers: {
			'Content-Type': 'application/xml',
			'Cache-Control': 'max-age=3600'
		}
	})
}

Features:

  • Auto-discover all public routes
  • Include lastmod dates from content
  • Set appropriate priorities
  • Exclude admin routes

Phase 2: OG Image Generation (Week 1-2)

Create /src/routes/api/og-image/+server.ts

export async function GET({ url }) {
	const { title, subtitle, type } = Object.fromEntries(url.searchParams)

	const svg = generateOGImageSVG({
		title,
		subtitle,
		type, // 'post', 'project', 'default'
		brandColor: '#your-brand-color'
	})

	const png = await convertSVGtoPNG(svg)

	return new Response(png, {
		headers: {
			'Content-Type': 'image/png',
			'Cache-Control': 'public, max-age=31536000'
		}
	})
}

Templates:

  • Posts: Title + excerpt on branded background
  • Projects: Logo placeholder + title
  • Default: Site logo + tagline

Phase 3: Metadata Validation (Week 2)

Create /src/lib/utils/metadata-validator.ts

export function validateMetaTags(page: string) {
	return {
		hasTitle: checkTitle(),
		titleLength: getTitleLength(),
		hasDescription: checkDescription(),
		descriptionLength: getDescriptionLength(),
		hasOGImage: checkOGImage(),
		hasCanonical: checkCanonical(),
		structuredDataValid: validateJSONLD()
	}
}

Add development-only validation component

  • Console warnings for missing/invalid metadata
  • Visual indicators in dev mode
  • Automated tests for all routes

Phase 4: Final Touches (Week 2)

  1. Update robots.txt
Sitemap: https://jedmund.com/sitemap.xml

# Existing rules...
  1. Add metadata debugging route (dev only)
  • /api/meta-debug - JSON output of all pages' metadata
  • Useful for testing social media previews

Success Metrics

  • Sitemap.xml validates and includes all public pages
  • OG images generate for all text-based content
  • All pages pass metadata validation
  • Google Search Console shows improved indexing
  • Social media previews display correctly

Technical Considerations

Performance

  • Cache generated OG images (1 year)
  • Cache sitemap (1 hour)
  • Lazy-load validation in development only

Maintenance

  • Sitemap auto-updates with new content
  • OG image templates easy to modify
  • Validation runs in CI/CD pipeline

Implementation Timeline

Week 1:

  • Day 1-2: Implement dynamic sitemap
  • Day 3-5: Create OG image generation API

Week 2:

  • Day 1-2: Add metadata validation utilities
  • Day 3-4: Testing and refinement
  • Day 5: Documentation and deployment

Total: 2 weeks (vs. original 5 weeks)

Future Enhancements

  1. A/B testing different OG images/titles
  2. Multi-language support with hreflang tags
  3. Advanced schemas (FAQ, HowTo) for specific content
  4. Analytics integration to track metadata performance

Appendix: Current Implementation Reference

Existing Files

  • /src/lib/utils/metadata.ts - Core utilities
  • /src/lib/utils/content.ts - Content extraction
  • /src/routes/+layout.svelte - Default metadata
  • All page routes - Individual implementations

Usage Pattern

<script>
	import { generateMetaTags, generateArticleJsonLd } from '$lib/utils/metadata'

	$: metaTags = generateMetaTags({
		title: pageTitle,
		description: pageDescription,
		url: $page.url.href,
		type: 'article',
		image: contentImage
	})
</script>

<svelte:head>
	<title>{metaTags.title}</title>
	<!-- ... rest of meta tags ... -->
</svelte:head>