3.1 KiB
3.1 KiB
Architect — F-015 SEO core: structured data, sitemap, redirects
Feature
F-015 adds SEO crawlability and structured data to the existing F-014 storefront catalog pages.
Design
Storefront SEO module
Create a small storefront SEO module under project/storefront/src/lib/seo/:
json-ld.tsbuilds typed JSON-LD objects for Organization, BreadcrumbList and Product.redirects.tsdefines aRedirectRepositoryinterface and an env-backed implementation.- Keep public URL generation centralized through existing
absoluteUrl()/SITE_URL.
No new runtime dependency is required.
Structured data
- Root layout embeds Organization JSON-LD once.
- Product pages embed:
- Product JSON-LD using product name, description, canonical URL and main image when available.
- BreadcrumbList JSON-LD for Home → Product.
- Category and brand pages embed BreadcrumbList JSON-LD.
- JSON-LD is rendered as
application/ld+jsonwith JSON serialization, not string concatenation.
Sitemap and robots
Use Next.js metadata routes:
src/app/sitemap.tsreturnsMetadataRoute.Sitemap.src/app/robots.tsreturnsMetadataRoute.Robots.
Sitemap source:
- Static public URLs:
/,/products/search. - Product URLs from
searchProducts({ limit: 100, offset }), which returns active products only through backendSearchProducts.activeOnly = true; page through results to avoid silently truncating the first page. - Category URLs from
listCategoryTree()flattened recursively. - Brand URLs from a new public
GET /brandsbackend endpoint and storefrontlistBrands()client helper. - On API failure, sitemap degrades to static URLs rather than failing the build.
Redirect management
- Add
src/middleware.tsusing an env-backed redirect store. RedirectRepository.findBySourcePath(pathname)returns a redirect target when configured.- Configure redirects with
REDIRECTS_JSON, an array of{ "from": "/old", "to": "/new" }entries. - Middleware returns permanent
301redirects only for same-origin local paths. External targets are rejected by the parser to avoid open redirects. - Redirect source and target paths must start with
/; source cannot equal target.
Backend brand listing
Extend the brands module minimally:
- Add
BrandRepository.list(). - Add
ListBrandsuse case. - Add public
GET /brandsreturning{ items: [...] }in stablename ASC, id ASCorder.
Acceptance trace
- Product JSON-LD: product page embeds Product schema script.
- Sitemap: lists active product URLs via search API, category URLs, brand URLs and static pages; draft products excluded by backend active search.
- Redirect: middleware redirects stored old path with HTTP 301 to same-origin local target.
- Canonical URLs: existing F-014 canonical metadata remains on product/category/brand/search and root layout gains canonical metadata.
verify.sh: must pass after gates.
Risks / constraints
- No hreflang and no external SEO tooling by scope.
- Lighthouse/Google validator may be unavailable locally; validate structurally and through build output.
- Env redirects are enough for this slice; a database-backed admin UI is intentionally deferred.