also looking at this
fix(seo): ship a robots.txt so the production smoke test passes
#10
2 files
+46
-0
| @@ -0,0 +1,24 @@ | ||
| 1 | # https://commshq.org — crawl policy. | |
| 2 | # | |
| 3 | # The auth-walled routes below also send `robots: noindex, nofollow` from their | |
| 4 | # own useSeoMeta call, which is what keeps them out of an index once fetched. | |
| 5 | # This file stops well-behaved crawlers spending the request at all, and is the | |
| 6 | # only place that can speak for routes that never render HTML. | |
| 7 | # | |
| 8 | # No sitemap is published yet (sitemap.xml is a 404). Add a Sitemap: line here | |
| 9 | # when one exists rather than pointing crawlers at a missing file. | |
| 10 | ||
| 11 | User-agent: * | |
| 12 | ||
| 13 | Disallow: /dashboard | |
| 14 | Disallow: /login | |
| 15 | Disallow: /register | |
| 16 | ||
| 17 | # Landing pages reached from email links; nothing worth indexing. | |
| 18 | Disallow: /preferences-saved | |
| 19 | Disallow: /subscription-confirmed | |
| 20 | ||
| 21 | # The JSON API: no HTML, nothing to index. | |
| 22 | Disallow: /api/ | |
| 23 | ||
| 24 | Allow: / | |
| @@ -0,0 +1,22 @@ | ||
| 1 | import { describe, expect, it } from 'bun:test' | |
| 2 | import { readFileSync } from 'node:fs' | |
| 3 | import { join } from 'node:path' | |
| 4 | ||
| 5 | const robots = readFileSync(join(import.meta.dir, '../../public/robots.txt'), 'utf8') | |
| 6 | ||
| 7 | // scripts/smoke-deployment.ts fetches /robots.txt on production after every | |
| 8 | // deploy and fails the run if it is missing, names the wrong host, or leaks a | |
| 9 | // localhost URL. Checking the same things here keeps that gate from going red | |
| 10 | // only after the code is already live. | |
| 11 | describe('robots.txt', () => { | |
| 12 | it('names the production host and no local one', () => { | |
| 13 | expect(robots).toContain('commshq.org') | |
| 14 | expect(robots).not.toContain('localhost') | |
| 15 | }) | |
| 16 | ||
| 17 | it('keeps crawlers out of the auth-walled and API routes', () => { | |
| 18 | for (const path of ['/dashboard', '/login', '/register', '/api/']) | |
| 19 | expect(robots).toContain(`Disallow: ${path}`) | |
| 20 | expect(robots).toContain('Allow: /') | |
| 21 | }) | |
| 22 | }) | |