fix(seo): restore descriptive titles and meta descriptions on the priority platform pages (audit WP2) - #8216
Conversation
…m pages Work package 2 of the 2026 post-launch SEO audit. The rebrand had replaced the priority landing pages' titles with bare product names and cut their descriptions to one-line taglines. Sets the approved copy on /orm, /postgres, /compute, /pricing, /enterprise, /support, /studio, and /stack, mirrors it into the llms.txt/llms-full.txt transcription, and pins it with a test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds apps/site/scripts/seo-page-metadata.test.ts, wired into the site's check script, so neither a copy edit nor a createPageMetadata refactor can silently change the rendered <title>, the meta description, or the llms.txt transcription of the eight priority pages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Review clean at f6fab4e What it does. Restores descriptive What I checked. Read the full diff and the code around it ( Risk: low. Metadata-only change on eight pages plus a pure string-trim in the OG card URL; fully covered by the new test, reversible by revert. One caveat, not a blocker: the approved copy table isn't in the repo or the brain, so I verified the strings for internal consistency (page ↔ llms ↔ test ↔ PR body) rather than against the brief; the site owner should eyeball the eight titles in the PR body once before merging. — reviewer |
Work package 2 of 8 of the September 2026 post-launch technical SEO audit. The 2026 rebrand had replaced the descriptive titles of the main organic / AI-answer landing pages with bare product names (
<title>Prisma ORM</title>) and cut their meta descriptions to one-line taglines. This sets the copy approved by the site owner, verbatim, on the eight priority pages and on the second transcription of those strings inllms-content.ts.Scope is exactly those eight pages plus the guardrail test. No other pages, no layout changes, no other audit items.
What changed, page by page
Titles below are the rendered
<title>, i.e. aftercreatePageMetadataapplies its brand-suffix rule. Descriptions marked (unchanged) were left exactly as they were, per the brief./orm —
apps/site/src/app/orm/page.tsxPrisma ORM→Prisma ORM | Type-Safe ORM for TypeScript and Node.jsGive your agent database access it can't get wrong.→Prisma ORM is a type-safe ORM for TypeScript and Node.js. Model your data, run migrations, and query your database, with access your agent can't get wrong./postgres —
apps/site/src/app/postgres/page.tsxPrisma Postgres→Prisma Postgres | Serverless PostgreSQL for TypeScript AppsProduction-ready Postgres, already wired to your stack.→Prisma Postgres is a production-ready serverless PostgreSQL database with instant setup, built-in connection pooling, automated backups, and usage-based pricing, already wired to your stack./compute —
apps/site/src/app/compute/page.tsxPrisma Compute→Prisma Compute | Deploy TypeScript Apps and AI Agents on BunOne platform for your app and its database.→Prisma Compute deploys TypeScript apps, APIs, and AI agents from your repo as long-lived Bun processes next to Prisma Postgres, with long-running requests and streaming. One platform for your app and its database./pricing —
apps/site/src/app/pricing/page.tsxPricing | Prisma→Prisma Pricing | Usage-Based Plans for Postgres and ComputeUsage-based pricing for your whole stack — Prisma Compute app hosting and Prisma Postgres databases. …/enterprise —
apps/site/src/app/enterprise/page.tsxEnterprise | Prisma→Prisma Enterprise | ORM Support and Database Workflows for TeamsEnterprise-level support, security, and guidance for teams running Prisma in production./support —
apps/site/src/app/support/page.tsxSupport | Prisma→Prisma Support | Get Help, Report Bugs, and Request FeaturesGet help with Prisma. Search for answers, report bugs, request features, or contact the Prisma support team./studio —
apps/site/src/app/studio/page.tsxPrisma Studio→Prisma Studio | Visual Database Browser and EditorExplore, edit, and understand your data with a visual database browser for Prisma, locally or in Prisma Console./stack —
apps/site/src/app/stack/page.tsxThe Prisma Stack→The Prisma Stack | ORM, Postgres, and Compute for TypeScriptORM, Postgres, and Compute, one platform for your app and its database, with one shared context across your stack.Note the three titles that used to be brand-suffixed (
Pricing | Prisma,Enterprise | Prisma,Support | Prisma) now carry the brand at the front, socreatePageMetadataadds no suffix. Every rendered title is exactly the approved string: no double suffix, no missing suffix. Homepage title/description untouched.llms.txt / llms-full.txt (
apps/site/src/app/llms-content.ts)This file is an independent, divergent transcription of the same titles and descriptions. Its entries for the eight pages now match the page metadata exactly:
/orm:Prisma | Next-generation ORM for Node.js & TypeScript→ the new title; description replaced with the approved one./postgres:Prisma Postgres | Instant Global Databases→ the new title; description replaced (the index entry and the## Prisma Postgresblock had two different old descriptions; both now carry the approved one)./studio:Prisma Studio — Visual Database Browser & Editor→ the new title; description replaced (again, index and block had diverged)./pricing:Pricing — Prisma Compute & Prisma Postgres→ the new title; description replaced with the page's current one./enterprise:Streamline your enterprise development workflow with Prisma→ the new title; description replaced with the page's current one./stack:Prisma Stack: a complete and flexible tech stack→ the new title; description replaced with the page's current one, in the index entry and in the "Stack and ecosystem" section (which now also carries aStack title:line)./computeand/supporthad no entries at all, so they were added tositePageswith the new title and description. They therefore also appear in llms-full.txt's "Key page index"./,/changelog,/mcp,/ecosystementries are untouched.Other places these titles are referenced, and what I did
app/sitemap.xml/route.ts,app/sitemap-site.xml/route.ts): URLs and lastmod only, no titles. Nothing to change.createPageMetadata, soog:titleandtwitter:titlenow carry the full new titles automatically. Asserted in the test.lib/og-card.ts→app/og/card.png) printsogKickeras an eyebrow above the raw title. With the new titles the /orm card would have read "Prisma ORM" over "Prisma ORM | Type-Safe ORM for TypeScript and Node.js" — the product name twice.createPageMetadatanow passes the card a headline with that leading segment removed when it is exactly what the eyebrow already says (lead === kicker, orlead === "Prisma " + kicker, which covers Pricing/Enterprise/Support). Cards now read e.g. kicker "Prisma ORM" + headline "Type-Safe ORM for TypeScript and Node.js". Titles that don't repeat their kicker (every other page, including/changelog/[slug]) are untouched, and the<title>/og:title/twitter:titlealways keep the full string. This was a low-stakes, reversible call I made rather than asking; if you'd rather the card repeat the product name, revertogCardHeadlineand the corresponding test.<meta name="description">tags carry the full text./studiohas aSoftwareApplicationnode with its ownname: "Prisma Studio"and description, and the root layout has Organization/WebSite nodes built fromSITE_NAMEand the homepage copy. Left unchanged on purpose — schema.orgnameshould be the product/brand name, not the SEO title.components/product/content/{orm,postgres,compute}.ts) still carry the old taglines ("One platform for your app and its database"). That's on-page content, not metadata, and out of scope here.Guardrail test
apps/site/scripts/seo-page-metadata.test.ts(node:test, run withtsx). Newtestscript inapps/site/package.json, appended to the site'scheckscript, so it runs as part ofpnpm checkat the root. 26 assertions across the eight pages:title/descriptionin eachpage.tsxequal the approved copy (a copy edit has to be deliberate).createPageMetadataactually resolves:title.absolute,description,openGraph.title,twitter.titleand the canonical URL. This is the bit that pins the suffix behaviour — a future refactor ofcreatePageMetadatathat re-strips or double-appends " | Prisma" fails here.buildLlmsIndexContentandbuildLlmsFullContentrender the same eight titles and descriptions.The page modules themselves can't be imported outside Next (server components pulling in CSS, fonts, image assets), so the test reads the
createPageMetadata({ … })literals out of the page source and feeds them through the real helper — which pins both the copy and the helper.Testing
pnpm check→ exit 0 (26 existing root tests + the 26 new site tests).pnpm types:check→ exit 0.Prisma ORMfails 3 tests; changing the helper to emit a non-absolute title (so the layout template would append a second suffix) fails 8.<title>lengths: 50–64 chars.next build/next devfor apps/blog or apps/docs (sandbox constraint); verification here is static plus the metadata the helper actually returns.Assumptions and follow-ups
page.tsxdescriptions are byte-identical to before./computeand/supportwere missing fromllms-content.tsentirely; I added index entries rather than leaving them out. I did not write full narrative blocks (## Prisma Compute,## Support, with feature bullets) for them, since that needs body copy nobody has approved. Follow-up if you want llms-full.txt to cover them properly.pnpm checkat the root rewrites unrelated files (apps/blog/scripts/lint.ts,apps/blog/src/app/(blog)/[slug]/page.tsx,apps/docs/scripts/lint-links.ts,packages/ui/scripts/generate-search-index.mjs,packages/ui/src/lib/search-index.ts) becauseoxfmt --writefinds pre-existing formatting drift onmain. I reverted all of it to keep this diff scoped, but it means the pre-commit hook dirties unrelated files for everyone.pnpm types:checkfails until@prisma/eclipseis built (Cannot find module '@prisma/eclipse'frompackages/ui) andNEXT_DOCS_ORIGIN/NEXT_BLOG_ORIGINare set (next typegenthrows otherwise). Both reproduce onmainwithout this branch; I built the package and set the two vars to run the gate.🤖 Generated with Claude Code