Apps Docs
SEO review: apps/docs
Date: 2026-07-01
Scope#
Reviewed apps/docs SEO readiness across App Router metadata, docs route templates, canonical/Open Graph/Twitter tags, robots/sitemap behavior, OpenAPI/generated reference content, structured data, headings/content semantics, and public assets.
Executive summary#
apps/docs has a solid SEO foundation for guide content: the root layout defines site metadata, guide routes derive per-page titles/descriptions/canonicals/social cards from MDX frontmatter, guide pages render one visible <h1>, and guide JSON-LD includes TechArticle and breadcrumb data. The main risks are deployment/indexability drift and incomplete discovery for generated reference content: the HTML robots flag depends on a Vercel-specific environment variable, the sitemap is generated after build and omits reference/API pages, and some reference metadata constructs incorrect or partial canonicals.
Findings by severity#
High#
H1. Production indexability depends on NEXT_PUBLIC_VERCEL_ENV#
Evidence: IS_PRODUCTION is true only when NEXT_PUBLIC_VERCEL_ENV === 'production' (apps/docs/lib/constants.ts:10), and root metadata uses that flag for robots.index and robots.follow (apps/docs/app/layout.tsx:29-31). At the same time, the static robots file allows crawling (apps/docs/public/robots.txt:1-3) and deployment headers allow indexing on production hosts (apps/docs/public/_headers:1-12, apps/docs/next.config.mjs:144-165).
Impact: A non-Vercel production deployment, or a production build missing this public env var, can emit page-level noindex,nofollow while robots.txt and headers invite crawling. Search engines generally honor the more specific page-level noindex.
Recommended fix: Replace the Vercel-specific production test with an explicit docs indexing env var or host/deployment contract that is set in every production deployment. Keep robots metadata, X-Robots-Tag, and robots.txt aligned from the same source of truth.
Medium#
M1. Sitemap is postbuild-generated, absent from source, and omits reference/API routes#
Evidence: apps/docs/public/sitemap.xml is not present in the checked tree, while robots.txt points crawlers to https://www.assistance.bg/docs/sitemap.xml (apps/docs/public/robots.txt:3). The sitemap script only globs guide and troubleshooting MDX (apps/docs/internals/generate-sitemap.ts:22-50) and writes public/sitemap.xml (apps/docs/internals/generate-sitemap.ts:77-82). It does not include /reference, /reference/api, /reference/cli, SDK pages, crawler pages, or other generated reference routes, even though reference routes are statically enumerated (apps/docs/features/docs/Reference.utils.ts:99-127). The script is only called by postbuild (apps/docs/package.json:37).
Impact: Fresh clones and partial deployments can lack the advertised sitemap, and generated reference/API content has weak discovery signals compared with guide pages.
Recommended fix: Generate sitemap content through Next's App Router app/sitemap.ts or make sitemap generation a required predeploy artifact. Extend the route list with generateReferenceStaticParams() output plus the reference index, API, CLI, and any crawler-friendly reference detail URLs that should be indexed.
M2. SDK reference canonical metadata can be malformed or incomplete#
Evidence: SDK metadata builds url from [BASE_PATH, 'reference', sdkId, path[0]].filter(Boolean).join('/') (apps/docs/features/docs/Reference.utils.ts:153) and only emits alternates.canonical when slug.length > 0 (apps/docs/features/docs/Reference.utils.ts:163-168). This drops the SDK version segment for versioned pages, omits deeper section paths, and produces a relative string without a leading slash such as docs/reference/... when BASE_PATH is /docs. Open Graph uses the same value (apps/docs/features/docs/Reference.utils.ts:170-174).
Impact: Reference pages can publish inconsistent canonical/OG URLs, consolidating versioned or deep reference pages onto the wrong URL or emitting non-absolute social URLs.
Recommended fix: Reuse absoluteDocsUrl()/resolveCanonicalUrl() for reference metadata, include version and full path segments, and emit canonicals for all indexable reference pages including reference roots.
M3. CLI/API/self-hosting reference pages lack canonical, Open Graph, and Twitter overrides#
Evidence: generateReferenceMetadata() returns only title and description for CLI and API pages (apps/docs/features/docs/Reference.utils.ts:176-185) and only a title for self-hosting pages (apps/docs/features/docs/Reference.utils.ts:186-189). These pages therefore inherit only root-level OG/Twitter defaults from apps/docs/app/layout.tsx:33-44.
Impact: Important generated reference landing pages have weaker search and share previews than guide pages, and canonical signals are less explicit.
Recommended fix: Add alternates.canonical, openGraph.title/description/url/images, and twitter.title/description/images for CLI, API, and self-hosting branches, using the same URL helper as guides.
Low#
L1. Open Graph image generation can emit an empty-host URL#
Evidence: MISC_URL defaults to an empty string (apps/docs/lib/constants.ts:13), while generateOpenGraphImageMeta() concatenates it directly into /functions/v1/og-images?... (apps/docs/features/seo/openGraph.ts:12-16). Guide and reference metadata use that helper for dynamic social images (apps/docs/features/docs/GuidesMdx.utils.tsx:226-247, apps/docs/features/docs/Reference.utils.ts:155-174).
Impact: If NEXT_PUBLIC_MISC_URL is missing in production, OG/Twitter image metadata becomes a relative function URL that may not exist on the docs origin.
Recommended fix: Make MISC_URL required for production docs builds or fall back intentionally to the static DEFAULT_OG_IMAGE absolute URL.
L2. Public manifest copy and icon paths are stale for Assistance docs#
Evidence: The favicon manifest still describes “The Postgres Development Platform.” (apps/docs/public/favicon/manifest.json:2-5) and uses root-relative icon URLs such as /favicon/android-icon-36x36.png (apps/docs/public/favicon/manifest.json:10). The docs app runs under basePath: '/docs' (apps/docs/next.config.mjs:61-63), while root metadata generates favicons with BASE_PATH (apps/docs/app/layout.tsx:27-28).
Impact: If the manifest is exposed to crawlers or install surfaces, it can show stale product copy and broken icon URLs under the /docs base path.
Recommended fix: Update manifest copy to Assistance Docs and use /docs/favicon/... paths or generate the manifest through the same base-path-aware favicon helper.
Positive controls#
- Root layout defines
metadataBase, description, favicons, Open Graph, Twitter, and robots metadata (apps/docs/app/layout.tsx:22-44). - Guide metadata derives title, description, keywords, canonical URL, Open Graph image, and Twitter card from validated MDX frontmatter (
apps/docs/features/docs/GuidesMdx.utils.tsx:217-247; frontmatter validation inapps/docs/lib/docs.ts:19-49). - Guide page templates render one primary
<h1>from frontmatter and includeTechArticleplusBreadcrumbListJSON-LD (apps/docs/features/docs/GuidesMdx.template.tsx:63-107; JSON-LD builder inapps/docs/lib/seo.ts:50-90). - Homepage metadata has an explicit canonical for
/docs(apps/docs/app/page.tsx:12-27) and emitsWebSite/SearchActionJSON-LD (apps/docs/app/page.tsx:10,apps/docs/lib/seo.ts:93-104). - Reference pages are statically constrained with
dynamicParams = false(apps/docs/app/reference/[...slug]/page.tsx:15) and crawler-specific reference HTML includes title, description, canonical, and image tags (apps/docs/app/api/crawlers/route.ts:67-85). - Preview deployment headers block indexing for
*.pages.devand*.vercel.apphosts (apps/docs/public/_headers:14-23; equivalent Next headers inapps/docs/next.config.mjs:156-165).
Verification notes#
- File inspection confirmed no checked-in
apps/docs/public/sitemap.xmlexists whilerobots.txtreferences it. mise exec -- pnpm --filter docs run build:sitemapwas attempted for generator verification, but failed because this isolated worktree has no installednode_modulesforglobby(ERR_MODULE_NOT_FOUND: Cannot find package 'globby'). No generated files were left behind.