Skip to content

fix(seo): restore descriptive titles and meta descriptions on the priority platform pages (audit WP2) - #8216

Merged
sneub merged 2 commits into
mainfrom
program/01M1XNVVS259C5DBM6D5P7QRTD
Sep 8, 2026
Merged

fix(seo): restore descriptive titles and meta descriptions on the priority platform pages (audit WP2)#8216
sneub merged 2 commits into
mainfrom
program/01M1XNVVS259C5DBM6D5P7QRTD

Conversation

@prisma-robot

@prisma-robot prisma-robot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

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 in llms-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. after createPageMetadata applies its brand-suffix rule. Descriptions marked (unchanged) were left exactly as they were, per the brief.

/orm — apps/site/src/app/orm/page.tsx

  • title: Prisma ORMPrisma ORM | Type-Safe ORM for TypeScript and Node.js
  • description: Give 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.tsx

  • title: Prisma PostgresPrisma Postgres | Serverless PostgreSQL for TypeScript Apps
  • description: Production-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.tsx

  • title: Prisma ComputePrisma Compute | Deploy TypeScript Apps and AI Agents on Bun
  • description: One 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.tsx

  • title: Pricing | PrismaPrisma Pricing | Usage-Based Plans for Postgres and Compute
  • description: (unchanged) Usage-based pricing for your whole stack — Prisma Compute app hosting and Prisma Postgres databases. …

/enterprise — apps/site/src/app/enterprise/page.tsx

  • title: Enterprise | PrismaPrisma Enterprise | ORM Support and Database Workflows for Teams
  • description: (unchanged) Enterprise-level support, security, and guidance for teams running Prisma in production.

/support — apps/site/src/app/support/page.tsx

  • title: Support | PrismaPrisma Support | Get Help, Report Bugs, and Request Features
  • description: (unchanged) Get help with Prisma. Search for answers, report bugs, request features, or contact the Prisma support team.

/studio — apps/site/src/app/studio/page.tsx

  • title: Prisma StudioPrisma Studio | Visual Database Browser and Editor
  • description: (unchanged) Explore, edit, and understand your data with a visual database browser for Prisma, locally or in Prisma Console.

/stack — apps/site/src/app/stack/page.tsx

  • title: The Prisma StackThe Prisma Stack | ORM, Postgres, and Compute for TypeScript
  • description: (unchanged) ORM, 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, so createPageMetadata adds 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 Postgres block 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 a Stack title: line).
  • /compute and /support had no entries at all, so they were added to sitePages with the new title and description. They therefore also appear in llms-full.txt's "Key page index".
  • /, /changelog, /mcp, /ecosystem entries are untouched.

Other places these titles are referenced, and what I did

  • Sitemaps (app/sitemap.xml/route.ts, app/sitemap-site.xml/route.ts): URLs and lastmod only, no titles. Nothing to change.
  • OG / Twitter titles: come from createPageMetadata, so og:title and twitter:title now carry the full new titles automatically. Asserted in the test.
  • OG image text — one real problem, fixed. The generated card (lib/og-card.tsapp/og/card.png) prints ogKicker as 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. createPageMetadata now passes the card a headline with that leading segment removed when it is exactly what the eyebrow already says (lead === kicker, or lead === "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:title always 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, revert ogCardHeadline and the corresponding test.
  • OG image truncation: titles are clamped at 120 chars, the longest new one is 60 — no truncation. The card description is clamped at 200 chars, so /pricing (222) and /compute (213) ride on the card as an ellipsed prefix. That clamp is deliberate card design and /pricing already exceeded it before this PR, so I left it alone; the <meta name="description"> tags carry the full text.
  • JSON-LD: /studio has a SoftwareApplication node with its own name: "Prisma Studio" and description, and the root layout has Organization/WebSite nodes built from SITE_NAME and the homepage copy. Left unchanged on purpose — schema.org name should be the product/brand name, not the SEO title.
  • Page hero headlines (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 with tsx). New test script in apps/site/package.json, appended to the site's check script, so it runs as part of pnpm check at the root. 26 assertions across the eight pages:

  1. The literal title/description in each page.tsx equal the approved copy (a copy edit has to be deliberate).
  2. The metadata createPageMetadata actually resolves: title.absolute, description, openGraph.title, twitter.title and the canonical URL. This is the bit that pins the suffix behaviour — a future refactor of createPageMetadata that re-strips or double-appends " | Prisma" fails here.
  3. The OG card query string: headline is part of the title, is not ellipsed, and does not repeat the kicker.
  4. buildLlmsIndexContent and buildLlmsFullContent render 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.
  • Mutation-checked the guardrail: reverting the /orm title to Prisma ORM fails 3 tests; changing the helper to emit a non-absolute title (so the layout template would append a second suffix) fails 8.
  • Verified the eight titles and descriptions character-for-character against the approved table with a separate parser, including the ASCII apostrophe in "can't". Rendered <title> lengths: 50–64 chars.
  • Did not run next build/next dev for apps/blog or apps/docs (sandbox constraint); verification here is static plus the metadata the helper actually returns.

Assumptions and follow-ups

  • Assumption: for the five pages whose description is "keep unchanged", the llms-content entries were set to the page's current description, on the reading that the two copies should converge. Their page.tsx descriptions are byte-identical to before.
  • Assumption: /compute and /support were missing from llms-content.ts entirely; 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.
  • Follow-up, not touched: running pnpm check at 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) because oxfmt --write finds pre-existing formatting drift on main. I reverted all of it to keep this diff scoped, but it means the pre-commit hook dirties unrelated files for everyone.
  • Follow-up, not touched: on a clean clone pnpm types:check fails until @prisma/eclipse is built (Cannot find module '@prisma/eclipse' from packages/ui) and NEXT_DOCS_ORIGIN/NEXT_BLOG_ORIGIN are set (next typegen throws otherwise). Both reproduce on main without this branch; I built the package and set the two vars to run the gate.

🤖 Generated with Claude Code

builder (Program) and others added 2 commits September 7, 2026 10:23
…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>
@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
blog Ready Ready Preview Sep 7, 2026 10:30am UTC
docs Ready Ready Preview Sep 7, 2026 10:30am UTC
eclipse Ready Ready Preview Sep 7, 2026 10:30am UTC
site Building Building Preview Sep 7, 2026 10:30am UTC

Request Review

@prisma-robot

prisma-robot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Review clean at f6fab4e

What it does. Restores descriptive <title>s and meta descriptions on the eight priority marketing pages (/orm, /postgres, /compute, /pricing, /enterprise, /support, /studio, /stack), brings the llms-content.ts transcription of the same strings into line (adding the missing /compute and /support index entries), and adds a node:test guardrail (apps/site/scripts/seo-page-metadata.test.ts, wired into the site's check script) that pins the copy both as page literals and as what createPageMetadata actually resolves. One small helper change: ogCardHeadline drops the leading Product | segment from the OG card headline only when it exactly repeats the card's kicker, so the card doesn't print "Prisma ORM" twice; <title>, og:title, twitter:title keep the full string.

What I checked. Read the full diff and the code around it (page-metadata.ts, og-card.ts, the OG route and image component, root layout title template, llms routes). Ran the gates on a fresh clone: site tests 26/26, root pnpm check green (the only working-tree churn is the pre-existing oxfmt drift on unrelated files the PR body already flags; none of this PR's files were rewritten), @prisma/eclipse build + site types:check exit 0. Every new title contains the whole word "Prisma", so withSiteName passes it through and the absolute title stops the layout template stacking a second suffix. The ogCardHeadline rule is a no-op for every other caller: no other title carries |, and /changelog/[slug] (<post> | Changelog, kicker "Changelog") only trims if a post is literally titled "Changelog". The old pre-rebrand strings survive nowhere else in the repo except on-page hero copy, which is out of scope as stated. No secrets, no scope drift.

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

@sneub
sneub merged commit fc18ecc into main Sep 8, 2026
15 checks passed
@sneub
sneub deleted the program/01M1XNVVS259C5DBM6D5P7QRTD branch September 8, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant