Automated SEO
The Verbiage
The Core Logic: Zero-Maintenance SEO
Our sitemap is automatically generated from the same source of truth that powers the entire library: library-mapping.ts. This creates a zero-maintenance SEO engine that stays in sync with the library structure without manual updates.
The Single Source of Truth: library-mapping.ts defines all volumes and chapters. When we add a new volume or chapter to this file, it automatically appears in:
- The Library Index page (/library)
- The Sidebar navigation
- The Volume Switcher dropdown
- The Sitemap (/sitemap.xml)
How It Works: The sitemap.ts file imports libraryVolumes and uses flatMap to generate URLs for every volume and chapter. This means:
- No Manual Updates: Adding a chapter to library-mapping.ts automatically adds it to the sitemap
- Always Accurate: The sitemap can never be out of sync with the actual library structure
- Zero Maintenance: No need to remember to update the sitemap when adding content
The Implementation: The sitemap generator:
1. Starts with static routes: / and /library
2. Maps over libraryVolumes to generate volume index pages: /library/[volume-id]
3. Maps over each volume's chapters to generate chapter pages: /library/[volume-id]/[chapter-slug]
4. Sets appropriate priorities and metadata for each route
Verification: You can view the live sitemap at /sitemap.xml to see the automated output. Every volume and chapter from library-mapping.ts is automatically included. Visit [https://cjs.codes/sitemap.xml](https://cjs.codes/sitemap.xml) to see the generated XML.
The Benefits
SEO Optimization: Search engines can discover all library content automatically. When we add a new chapter, it's immediately available for indexing without manual sitemap updates.
Consistency: The sitemap structure matches the actual site structure. There's no risk of the sitemap listing pages that don't exist or missing pages that do exist.
Scalability: As the library grows, the sitemap grows automatically. Adding 10 new chapters requires zero sitemap maintenance—just add them to library-mapping.ts.
Developer Experience: Developers don't need to remember to update the sitemap. The system enforces consistency automatically.
The Pattern
This pattern—using a single source of truth for both content and SEO—is the "Bible" way. We don't maintain separate lists for navigation, routing, and SEO. Instead, we have one authoritative source (library-mapping.ts) that drives everything.
The Rule: Never manually update a sitemap. Always extend the sitemap.ts logic to include new dynamic route segments. If you need to add a new route type, update the sitemap generator, not a static XML file.
The Blueprint
// ============================================
// Automated Sitemap Generator (app/sitemap.ts)
// ============================================
import { type MetadataRoute } from "next";
import { libraryVolumes } from "@/config/library-mapping";
const baseUrl = "https://cjs.codes";
/**
* Automated Sitemap Generator
*
* Generates a sitemap that stays in sync with the library structure.
* Automatically includes:
* - Static routes: /, /library
* - Dynamic routes: All volume and chapter pages from library-mapping.ts
*
* This ensures the sitemap is always up-to-date when new volumes or chapters are added.
*/
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
// Static routes
const staticRoutes: MetadataRoute.Sitemap = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 1.0,
},
{
url: `${baseUrl}/library`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.9,
},
];
// Dynamic routes: Generate paths for all volumes and chapters
// This pulls from the single source of truth: library-mapping.ts
const dynamicRoutes: MetadataRoute.Sitemap = libraryVolumes.flatMap((volume) => {
const volumeRoutes: MetadataRoute.Sitemap = [];
// Volume index page: /library/[volume-id]
volumeRoutes.push({
url: `${baseUrl}/library/${volume.id}`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.8,
});
// Chapter pages: /library/[volume-id]/[chapter-slug]
const chapterRoutes: MetadataRoute.Sitemap = volume.chapters.map((chapter) => ({
url: `${baseUrl}/library/${volume.id}/${chapter.slug}`,
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.7,
}));
return [...volumeRoutes, ...chapterRoutes];
});
// Combine all routes
return [...staticRoutes, ...dynamicRoutes];
}
// ============================================
// How It Works
// ============================================
// 1. Imports libraryVolumes from the single source of truth
// 2. Generates static routes (/, /library)
// 3. Uses flatMap to iterate over all volumes
// 4. For each volume, generates:
// - Volume index page: /library/[volume-id]
// - All chapter pages: /library/[volume-id]/[chapter-slug]
// 5. Returns combined array of all routes
// ============================================
// Adding New Routes
// ============================================
// To add a new route type (e.g., /blog/[slug]):
// 1. Update the sitemap.ts logic to include the new route segment
// 2. Never manually edit a static sitemap.xml file
// 3. Always extend the generator function, not create static entries
// Example: Adding blog posts
// const blogRoutes: MetadataRoute.Sitemap = blogPosts.map((post) => ({
// url: `${baseUrl}/blog/${post.slug}`,
// lastModified: post.updatedAt,
// changeFrequency: "weekly",
// priority: 0.6,
// }));
// return [...staticRoutes, ...dynamicRoutes, ...blogRoutes];The AI Context
cjs.codes uses an automated sitemap generator (app/sitemap.ts) that pulls from library-mapping.ts to create a zero-maintenance SEO engine. The sitemap automatically includes all volumes and chapters from the library structure, ensuring it stays in sync without manual updates. The sitemap is available at /sitemap.xml and includes static routes (/, /library) and dynamic routes for all volume and chapter pages. This pattern uses a single source of truth for both content and SEO, eliminating the need for manual sitemap maintenance.Directive for AI Agents
Copy and paste this directive to instruct an AI assistant on how to maintain this specific pattern:
## Directive for AI Agents
When working on SEO or sitemap functionality for cjs.codes:
**Sitemap Management:**
- **NEVER manually update a sitemap.xml file**
- **ALWAYS extend the sitemap.ts logic to include new dynamic route segments**
- The sitemap is automatically generated from `library-mapping.ts`
- Adding a volume or chapter to `library-mapping.ts` automatically adds it to the sitemap
**The Single Source of Truth:**
- `library-mapping.ts` is the authoritative source for all library content
- The sitemap, navigation, and routing all pull from this same file
- Never create separate lists for SEO that duplicate this structure
**Adding New Route Types:**
1. Update `sitemap.ts` to include the new route segment logic
2. Use the same pattern: import data source, map over it, generate URLs
3. Never create static XML entries or manual sitemap updates
4. Always use dynamic generation from a data source
**Verification:**
- The sitemap is available at `/sitemap.xml`
- Users can verify the live output to see all included routes
- The sitemap should always match the actual site structure
**The Rule**: If you need to add a new route type to the sitemap, extend the `sitemap.ts` generator function. Never create or edit a static sitemap.xml file. The sitemap must always be generated dynamically from a data source to maintain consistency.