Give each route its own title and canonical, and add robots.txt plus a sitemap. #72

Merged
an.di merged 1 commits from adilallo/fix/CR-177-site-metadata into main 2026-09-09 22:48:12 +00:00
Owner

Overview

Every public page was inheriting the homepage document title and a canonical URL that pointed at the production root. Tabs and search results could not tell routes apart, and staging was fully crawlable because there was no robots.txt or sitemap.

This pass puts titles, canonicals, robots, and sitemap on the same Next.js metadata layer: one title template, a canonical from each route’s path, robots that disallow non-production hosts, and a sitemap of public marketing URLs.

Changes

  • Root layout uses a shared title template (%s — CommunityRule). Home keeps its full default title; other routes supply a page segment (About, Learn, Templates, Create, Blog, legal pages, use cases, login, profile).
  • Removed the inherited canonical: /. Each route sets alternates.canonical from its path via routeMetadata.
  • Added app/robots.ts: staging, local, and unknown hosts Disallow: /; communityrule.com and communityrule.info allow crawling and advertise the sitemap. Optional override: SITE_INDEXING=true|false.
  • Added app/sitemap.ts listing public marketing, blog, and use-case URLs (not /create, /login, /profile, or /monitor).
  • Product, admin, and dev layouts stay noindex.
  • Copy for titles lives in messages/en/metadata.json. Helpers and tests: lib/siteMetadata.ts, lib/publicSitemap.ts.

Screenshots

How to Test

  1. npm run dev (or npx next build && npx next start).
  2. Confirm document titles:
    • / → homepage title (not the template).
    • /aboutAbout — CommunityRule
    • /learnLearn — CommunityRule
    • /templatesTemplates — CommunityRule
    • /create/informationalCreate — CommunityRule
    • /loginLog in — CommunityRule
  3. View source (or curl) and check <link rel="canonical"> matches the path, resolved against https://communityrule.com (e.g. /abouthttps://communityrule.com/about, not the site root).
  4. curl -sS http://localhost:3000/robots.txtUser-Agent: * / Disallow: / on localhost.
  5. curl -sS http://localhost:3000/sitemap.xml → public routes and blog/use-case URLs; no /login, /create, /profile, or /monitor.
  6. Confirm /login and /create/* include noindex, nofollow.

Notes

  • HTML meta name="robots" on marketing pages still says index, follow in the built image (staging and production share a build). Crawl blocking on staging is via /robots.txt from the request host (and CLOUDRON_APP_ORIGIN behind Cloudron’s proxy).
  • Set SITE_INDEXING=true or false if a restore-drill or other host needs an explicit override.
  • Sitemap URLs always use https://communityrule.com. Published /rules/[id] pages are not listed (ids are not known without the database).
## Overview Every public page was inheriting the homepage document title and a canonical URL that pointed at the production root. Tabs and search results could not tell routes apart, and staging was fully crawlable because there was no robots.txt or sitemap. This pass puts titles, canonicals, robots, and sitemap on the same Next.js metadata layer: one title template, a canonical from each route’s path, robots that disallow non-production hosts, and a sitemap of public marketing URLs. ## Changes - Root layout uses a shared title template (`%s — CommunityRule`). Home keeps its full default title; other routes supply a page segment (About, Learn, Templates, Create, Blog, legal pages, use cases, login, profile). - Removed the inherited `canonical: /`. Each route sets `alternates.canonical` from its path via `routeMetadata`. - Added `app/robots.ts`: staging, local, and unknown hosts `Disallow: /`; `communityrule.com` and `communityrule.info` allow crawling and advertise the sitemap. Optional override: `SITE_INDEXING=true|false`. - Added `app/sitemap.ts` listing public marketing, blog, and use-case URLs (not `/create`, `/login`, `/profile`, or `/monitor`). - Product, admin, and dev layouts stay `noindex`. - Copy for titles lives in `messages/en/metadata.json`. Helpers and tests: `lib/siteMetadata.ts`, `lib/publicSitemap.ts`. ## Screenshots ## How to Test 1. `npm run dev` (or `npx next build && npx next start`). 2. Confirm document titles: - `/` → homepage title (not the template). - `/about` → `About — CommunityRule` - `/learn` → `Learn — CommunityRule` - `/templates` → `Templates — CommunityRule` - `/create/informational` → `Create — CommunityRule` - `/login` → `Log in — CommunityRule` 3. View source (or curl) and check `<link rel="canonical">` matches the path, resolved against `https://communityrule.com` (e.g. `/about` → `https://communityrule.com/about`, not the site root). 4. `curl -sS http://localhost:3000/robots.txt` → `User-Agent: *` / `Disallow: /` on localhost. 5. `curl -sS http://localhost:3000/sitemap.xml` → public routes and blog/use-case URLs; no `/login`, `/create`, `/profile`, or `/monitor`. 6. Confirm `/login` and `/create/*` include `noindex, nofollow`. ## Notes - HTML `meta name="robots"` on marketing pages still says `index, follow` in the built image (staging and production share a build). Crawl blocking on staging is via `/robots.txt` from the request host (and `CLOUDRON_APP_ORIGIN` behind Cloudron’s proxy). - Set `SITE_INDEXING=true` or `false` if a restore-drill or other host needs an explicit override. - Sitemap URLs always use `https://communityrule.com`. Published `/rules/[id]` pages are not listed (ids are not known without the database).
an.di added 1 commit 2026-09-09 22:47:53 +00:00
The root layout was stamping the homepage title and production root onto every page. Routes now supply a page segment through one em-dash template, canonicals follow the request path, and non-production hosts disallow crawlers.

Co-authored-by: Cursor <cursoragent@cursor.com>
an.di self-assigned this 2026-09-09 22:48:02 +00:00
an.di merged commit aecb890cc8 into main 2026-09-09 22:48:12 +00:00
an.di deleted branch adilallo/fix/CR-177-site-metadata 2026-09-09 22:48:13 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: CommunityRule/community-rule#72