Sitemap generation

Walk public board resources and serve a bounded sitemap index and XML buckets.

Generate the same eight-bucket sitemap model as Cavuno’s hosted board. The walker handles feature gating, pagination, canonical paths, and the minimum-content rule for job taxonomy pages.

Prerequisites

  • A stateless public board client.
  • A canonical public origin.
  • Server routes for /sitemap.xml and /sitemap/:filename.
  • A cache independent from candidate or employer sessions.

Build the sitemap service

ts
// src/lib/sitemaps.ts
import {
SITEMAP_CHUNK_SIZE,
bucketFilename,
buildBucketUrls,
chunk,
listedBuckets,
parseBucketFilename,
renderSitemapIndex,
renderUrlset,
} from '@cavuno/board/sitemap';
import { board } from './board';
const origin = 'https://jobs.example.com';
export async function buildSitemapIndex() {
const entries: string[] = [];
for (const bucket of await listedBuckets(board)) {
const urls = await buildBucketUrls(board, origin, bucket);
const chunkCount = Math.max(
1,
chunk(urls, SITEMAP_CHUNK_SIZE).length,
);
for (let index = 0; index < chunkCount; index += 1) {
entries.push(`${origin}/sitemap/${bucketFilename(bucket, index)}`);
}
}
return renderSitemapIndex(entries);
}
export async function buildSitemapFile(filename: string) {
const parsed = parseBucketFilename(filename);
if (!parsed) return null;
const available = await listedBuckets(board);
if (!available.includes(parsed.bucket)) return null;
const urls = await buildBucketUrls(board, origin, parsed.bucket);
const chunks = chunk(urls, SITEMAP_CHUNK_SIZE);
const selected =
chunks[parsed.chunkIndex] ??
(parsed.chunkIndex === 0 && chunks.length === 0 ? [] : null);
return selected ? renderUrlset(selected) : null;
}

Return these strings with Content-Type: application/xml; charset=utf-8. Return your framework’s 404 for an unknown filename or chunk.

Understand what is emitted

The buckets cover marketing routes, job categories, skills, locations and details, companies, salaries, and blog content. The blog bucket is removed when the feature is disabled. Other empty buckets produce valid empty URL sets.

Job taxonomy pages need at least five matching jobs before they are emitted. This avoids indexing thin category, skill, and location pages.

Expected result

/sitemap.xml is a sitemap index whose entries point to valid bucket files. Each bucket route returns a standards-compliant URL set, including a valid empty set when an enabled bucket has no URLs.

Verify the result

bash
curl -fsS https://jobs.example.com/sitemap.xml
curl -fsS https://jobs.example.com/sitemap/jobs-details.xml

Confirm that:

  • Every <loc> uses the production HTTPS origin.
  • Disabled blog routes are absent.
  • Job detail URLs include both company and job slugs.
  • A non-existent bucket or chunk returns 404.
  • XML reserved characters are escaped by the renderer.

Submit /sitemap.xml to your search-console tooling only after it works at the final public domain.

Errors and edge cases

  • A catalog above the offset ceiling logs a truncation warning until bulk support is available. Monitor sitemap generation logs.
  • Cross-axis salary pages and combined location/taxonomy pages are not currently emitted because the public API cannot enumerate them without an N+1 crawl.
  • The walker can make many public reads. Do not run it during every ordinary page render.
  • An origin with a path or the wrong environment creates invalid canonical URLs.

Production cautions

  • Cache generated XML and revalidate often enough to remove expired jobs.
  • Generate with a stateless client; never attach candidate authorization.
  • Alert on truncation warnings and generation failures.
  • Keep robots.txt’s Sitemap: line aligned with board.seo().canonicalBase.

Next, apply board configuration with Theme and formatting.