Content System Refactor - Docs/Posts Separation
Complete refactor of content infrastructure: separated docs from posts with type-based routing, added comprehensive metadata system, improved Navigator UX, and created ContentHeader component.
This commit represents a major refactor of how content is organized, routed, and displayed on the site. What started as a simple Navigator tweak evolved into a complete rethinking of the content system architecture.
Summary of Changes
- Separated documentation from blog posts using type-based routing (
/docs/vs/posts/) - Removed URL paths from Navigator search results for cleaner UX
- Added comprehensive metadata system with
author,feature, andtypefields - Created ContentHeader component for consistent metadata display across all content
- Updated Container component with proper vertical spacing
- Created multiple documentation pages explaining the system
The Problem
1. Navigator Showed Too Much Implementation Detail
The Navigator was displaying full URL paths like /posts/navigator-feature in search results. This violated a core UX principle: users don't care about URL structures. They just want to navigate to content. As the saying goes, "only nerds care about URLs."
2. Docs Were Masquerading as Posts
Technical documentation was being served at /posts/ URLs, which was misleading. Documentation isn't really a "post" - it's reference material. The URL structure didn't reflect the content type.
3. No Consistent Metadata Display
Content files had metadata but no standard way to display it. Important context like author, feature, and project associations wasn't visible to readers.
The Solution
1. Type-Based Content Routing
Added a type field to the PostMeta interface:
export interface PostMeta {
title: string;
slug: string;
date: string;
description: string;
type?: 'post' | 'doc'; // Default is 'post'
// ...other fields
}Files with type: 'doc' are now served at /docs/[slug], while regular posts (no type specified) remain at /posts/[slug]. This keeps the authoring simple - most content doesn't need to specify a type.
2. Parallel Route Handlers
Created separate but parallel routing infrastructure:
src/app/posts/[slug]/page.tsx- Renders postssrc/app/docs/[slug]/page.tsx- Renders docssrc/app/api/posts/[slug]/route.ts- API for post lookupssrc/app/api/docs/[slug]/route.ts- API for doc lookups
Both work identically - they fetch the filename via API, dynamically import the TSX file, and render it. The only difference is which type they filter for.
3. Enhanced Metadata System
Extended PostMeta with new fields for better organization:
export interface PostMeta {
// ...existing fields
author?: string; // "Jay Griffin", "Claude Sonnet 4.5"
feature?: string; // "Navigator", "Theme Editor"
projectId?: string; // "jaygriff", "locus"
type?: 'post' | 'doc';
}Removed relatedPosts field as it was redundant - you can already filter by feature, project, topics, and tags to find related content.
4. ContentHeader Component
Created a standardized header component (src/components/ContentHeader.tsx) that displays:
- Title (large, prominent)
- Author and publication date (traditional text format)
- Last updated date (when applicable)
- Metadata badges (docs badge, feature, project) as pill-style tags
- Description (larger, readable format)
This gives every page a Notion-like feel with clear, consistent metadata presentation.
5. Cleaned Up Navigator UX
Removed URL path display from Navigator search results. Now users just see:
- Title
- Description
No more /posts/navigator-feature cluttering the interface. Users don't need to understand our URL scheme to navigate the site.
Files Changed
New Files
src/app/docs/[slug]/page.tsx- Doc page handlersrc/app/api/docs/[slug]/route.ts- Doc API endpointsrc/components/ContentHeader.tsx- Metadata display componentsrc/posts/docs-routing.tsx- Documentation explaining the routing systemsrc/posts/commit-2026-01-17-content-system.tsx- This commit doc
Modified Files
src/types/post.ts- Added author, feature, type fields; removed relatedPostssrc/lib/posts.ts- Added getAllDocs() and getDocBySlug() functionssrc/lib/routes.ts- Updated to handle both /posts/ and /docs/ pathssrc/app/sitemap.ts- Generate sitemap entries for both posts and docssrc/app/posts/[slug]/page.tsx- Integrated ContentHeadersrc/components/Navigator.tsx- Removed URL path displaysrc/components/Primitives.tsx- Updated Container margins for better spacingsrc/posts/navigator-feature.tsx- Updated metadata with type, author, featuresrc/posts/site-summary.tsx- Converted to doc, rewrote content, updated metadatasrc/posts/programs-not-documents.tsx- Updated metadata
Technical Notes
Code Duplication
The posts and docs page components are nearly identical - they just call different APIs and use different filter functions. This could be refactored into a shared component, but for now the duplication is minimal and keeps things explicit. Each route handler is ~60 lines and easy to understand.
Default Behavior
Posts are "first-class" - they don't need to specify type: 'post'. Only docs need the explicit type: 'doc' marker. This keeps most metadata blocks clean.
Backwards Compatibility
Old content without the new metadata fields continues to work. The system gracefully handles missing author, feature, or type information.
Future Possibilities
- Filter Navigator results by type, feature, or project
- Create dedicated feature or project index pages that list all related content
- Add more content types beyond posts and docs (e.g., projects, demos)
- Refactor page handlers to reduce duplication
- Generate commit documentation automatically from git history
Why This Matters
This refactor establishes a scalable content architecture that:
- Separates concerns properly (docs vs posts have different purposes)
- Hides implementation details from users (no more URL clutter)
- Provides rich metadata without complexity
- Creates a foundation for feature-based organization
- Maintains the "programs not documents" philosophy while improving UX
The site now has a clear content model that can grow without becoming chaotic. Each piece of content knows what it is, who wrote it, what feature it documents, and where it belongs.