Skip to content

TigerSEO: sitemap.xml + robots.txt (routes) + a public-URL registry#11

Merged
WebTigers merged 1 commit into
mainfrom
feat/seo-sitemap
Jul 17, 2026
Merged

TigerSEO: sitemap.xml + robots.txt (routes) + a public-URL registry#11
WebTigers merged 1 commit into
mainfrom
feat/seo-sitemap

Conversation

@WebTigers

Copy link
Copy Markdown
Owner

Implements "map every public (guest) URL and tell Google" — the discovery layer beneath sitelinks/rich-results.

Tiger_Sitemap — a core public-URL registry

Any module declares the URLs it owns from its Bootstrap: Tiger_Sitemap::register($key, fn($ctx): array). Core owns the registry (like Tiger_Dashboard), so declaring public URLs never depends on the SEO module — a search index or link checker could read it too. collect() runs every provider, de-dupes by loc, and drops a throwing provider (fail-soft). Each provider is org/locale-scoped via $ctx.

Routes, never files

/sitemap.xml + /robots.txt are served by public Seo_SitemapController / Seo_RobotsController (guest ACL, raw XML/text, layout+view off), wired through Tiger_Routing_Overrides in Seo_Bootstrap. A physical sitemap.xml in the docroot would silently shadow the route under cPanel's real-file-first .htaccess, so we never write one. Dotted paths survive the matcher; a real controller always wins (verified).

  • sitemap.xml — homepage + every provider's URLs (absolutized, org-scoped, <lastmod> from updated_at).
  • robots.txt — disallows the non-public app paths (tiger.seo.robots.disallow, per-org config; sane defaults) and points crawlers at the sitemap.

Providers (modules describe themselves)

  • seo registers pages (published CMS pages → /slug).
  • blog registers blog (published articles → /blog/slug — the blog owns its URL form; the SEO layer never learns content types).
  • A future TigerDocs / marketplace registers its own the same way (follow-up: wire TigerDocs).

Verified

Smoke now asserts /sitemap.xml returns 200 + lists the seeded page (the pages provider), and /robots.txt returns 200 + carries a Sitemap: line — CI coverage that the routes dispatch and the registry collects. Lint clean.

Per-request build for v1; a fingerprint cache (TigerDocs pattern) is the scale follow-up. Next: wire TigerDocs' public docs into the registry, then the JSON-LD schema PR (Organization/WebSite/BreadcrumbList/SiteNavigationElement).

🤖 Generated with Claude Code

"Map every public (guest) URL and tell Google." Implements the discovery layer:

- Tiger_Sitemap (core registry, like Tiger_Dashboard): any module declares its
  public URLs from its Bootstrap via register($key, fn($ctx): array). Core owns it
  so declaring public URLs never depends on the SEO module. collect() runs every
  provider, de-dupes by loc, fail-soft on a throwing provider.
- Seo_SitemapController / Seo_RobotsController — public (guest ACL), raw XML /
  text, layout+view disabled. /sitemap.xml lists the homepage + every provider's
  URLs (absolutized, org-scoped, with <lastmod>); /robots.txt disallows the
  non-public app paths (tiger.seo.robots.disallow, per-org config) and points at
  the sitemap.
- Both are ROUTES via Tiger_Routing_Overrides (Seo_Bootstrap), never docroot files
  — a physical sitemap.xml would shadow the route under cPanel's real-file-first
  .htaccess. Dotted paths survive the matcher; a real controller always wins.
- Providers: seo registers 'pages' (CMS, /slug); blog registers 'blog' (articles,
  /blog/slug — the blog owns its URL form, the resolver never learns "blog"). A
  future TigerDocs/marketplace registers its own the same way.

Smoke now asserts /sitemap.xml lists the seeded page and /robots.txt points at it.
Per-request build for v1; a fingerprint cache is the scale follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@WebTigers
WebTigers merged commit 16221fd into main Jul 17, 2026
5 checks passed
@WebTigers
WebTigers deleted the feat/seo-sitemap branch July 17, 2026 15:04
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