Improve crawl budget and path geo hubs - #262
Conversation
Google indexed ~45 of ~2600 sitemap URLs, mostly stuck as
Discovered-not-indexed. Trim thin dive logs from the sitemap, add
indexable /dive-sites/{country}/{region} hubs that reuse the existing
list/search UI, and prerender /map so crawlers get unique HTML instead
of an empty SPA shell.
Keep query-param filters for UI while canonicalizing hubs to path URLs
to avoid duplicate indexing. Include design/plan docs and SEO tests.
PR Reviewer Guide 🔍(Review updated until commit f0ebdde)Here are some key observations to aid the review process:
|
Stop /dive-sites/{country} from wiping itself before path
filters hydrate, and return country with each region so a
region-only pick can set both and build the hub URL. Align
UI and JSON-LD breadcrumbs with navbar labels and the current
page. Keep empty or thin curated lists out of the sitemap so
crawl budget is not spent on low-value URLs.
b244a22 to
f3afada
Compare
|
/review |
|
Persistent review updated to latest commit f0ebdde |
Align frontend geoSlug with backend NFKD folding so accented country hubs round-trip instead of bouncing to /dive-sites. Push substantial-dive filters into SQL, batch region lookups, and keep dives.md on all public logs. Harden unknown-region hydration, clear orphan region filters, lazy-split PathGate, and rename the regions handler to bust the stale string[] cache.
f0ebdde to
4116682
Compare
Summary
Google Search Console showed roughly 45 indexed URLs vs ~2600
discovered-not-indexed. This PR shrinks low-value sitemap noise,
adds indexable path-based dive-site geo hubs, prerenders
/map,and tightens breadcrumbs / curated-list inclusion so crawl budget
goes to pages that can actually rank.
Changes Made
Sitemap and crawl budget
quality gates via
query_substantial_public_dives)dive sites (
MIN_SITEMAP_LIST_ITEMS,query_substantial_public_lists)filters to path hubs instead
Path geo hubs
/dive-sites/{country}and/dive-sites/{country}/{region}routes that reuse the existingDive Sites list/search UI (
DiveSitePathGate,geoHubs.js)so hubs do not snap back to
/dive-sitesafter remount{region, country}fromGET /api/v1/dive-sites/regionsso a region-only selection can set both filters and build the
correct hub URL
/mapin the SEO router; includemapinnginx prerender paths
Breadcrumbs and labeling
Dive Routes, etc.)
Docs
docs/superpowers/Breaking changes
GET /api/v1/dive-sites/regionsresponse shape changed fromstring[]to[{ region, country }]. Frontend consumers in thisPR are updated; any external client of that endpoint must adapt.
Testing
Automated
backend/tests/test_seo_geo.py(substantialdives/lists, geo helpers)
test_seo_router.py(geo hub + map prerender, Dive Loglabeling)
test_dive_sites.pyfor regions response schemacd backend && ./docker-test-github-actions.sh tests/test_seo_geo.py tests/test_seo_router.py tests/test_dive_sites.pyManual
survives remount (no snap-back to
/dive-sites)match navbar labels and include the current page
include public profile lists with ≥3 sites
(local
sitemap.xmlis stale until regenerated)Related Issues
(~45 indexed / ~2606 not indexed, mostly Discovered – currently
not indexed)
docs/superpowers/specs/2026-09-25-seo-indexing-fixes-design.mddocs/superpowers/plans/2026-09-25-seo-indexing-fixes.mdAdditional Notes
Deployment
llm_content/sitemap.xml(static content job / R2publish) is required for thin-list and thin-dive exclusions to
take effect in production
/mapand geo hubsFollow-up
filter (validated: localhost still listed empty/thin favorites)
/dive-sites,country hub, and region hub (called out in the plan)
Notes for reviewers
crumbs / thin-list sitemap filter
?filters for UX whilecanonicalizing hub URLs to paths to avoid duplicate indexing