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
npm run dev (or npx next build && npx next start).
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
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).
curl -sS http://localhost:3000/sitemap.xml → public routes and blog/use-case URLs; no /login, /create, /profile, or /monitor.
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).
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 main2026-09-09 22:48:12 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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
%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).canonical: /. Each route setsalternates.canonicalfrom its path viarouteMetadata.app/robots.ts: staging, local, and unknown hostsDisallow: /;communityrule.comandcommunityrule.infoallow crawling and advertise the sitemap. Optional override:SITE_INDEXING=true|false.app/sitemap.tslisting public marketing, blog, and use-case URLs (not/create,/login,/profile, or/monitor).noindex.messages/en/metadata.json. Helpers and tests:lib/siteMetadata.ts,lib/publicSitemap.ts.Screenshots
How to Test
npm run dev(ornpx next build && npx next start)./→ homepage title (not the template)./about→About — CommunityRule/learn→Learn — CommunityRule/templates→Templates — CommunityRule/create/informational→Create — CommunityRule/login→Log in — CommunityRule<link rel="canonical">matches the path, resolved againsthttps://communityrule.com(e.g./about→https://communityrule.com/about, not the site root).curl -sS http://localhost:3000/robots.txt→User-Agent: */Disallow: /on localhost.curl -sS http://localhost:3000/sitemap.xml→ public routes and blog/use-case URLs; no/login,/create,/profile, or/monitor./loginand/create/*includenoindex, nofollow.Notes
meta name="robots"on marketing pages still saysindex, followin the built image (staging and production share a build). Crawl blocking on staging is via/robots.txtfrom the request host (andCLOUDRON_APP_ORIGINbehind Cloudron’s proxy).SITE_INDEXING=trueorfalseif a restore-drill or other host needs an explicit override.https://communityrule.com. Published/rules/[id]pages are not listed (ids are not known without the database).