Pages Guide - Baldr Template
Quick Reference | For comprehensive routing documentation, see ROUTING_GUIDE.md
This is a quick-start guide for creating and managing pages in your Baldr website. For detailed architecture and advanced topics, refer to the complete Routing Guide.
Quick Overview
The Baldr template uses a database-driven routing system where:
- Database stores page metadata, SEO, and configuration
- Page Registry maps URLs to React components (single source of truth)
- Catchall Route handles all dynamic pages automatically
Database Page (/produits) → pageRegistry → React Component → Rendered Page
For the complete architecture, see ROUTING_GUIDE.md → Architecture Overview
Step 1: Create the Page in Admin (Baldr-Bo)
- Navigate to SEO → Pages in your admin panel
- Click Create New Page
- Fill in the form:
- Title: Admin reference name (e.g., "About Us")
- Path: URL path (e.g.,
/about) - Page Type: Select the appropriate type
- SEO Tab: Add meta title, description, keywords
- Sitemap Tab: Configure sitemap settings
- Publication Tab: Set as active when ready
Step 2: Create the Component File
Create a new file in app/pages/ directory:
# Example: For path /about
app/pages/about.page.tsx
Template:
/**
* About Page Component
*
* Mapped to the /about route in the database.
*/
export default function AboutPage() {
return (
<div className="space-y-8">
<section>
<h2 className="text-3xl font-bold mb-4">About Us</h2>
<p className="text-lg text-gray-600">
Your content here...
</p>
</section>
{/* Add more sections as needed */}
</div>
);
}
Step 3: Register in Page Registry
Important: The Page Registry is the single source of truth for routing and sitemap generation.
Update app/config/pageRegistry.ts:
import { lazy } from "react";
import type { PageConfig } from "../config/pageRegistry";
const AboutPage = lazy(() => import("../pages/about.page"));
export const pageRegistry: Record<string, PageConfig> = {
"/": { component: HomePage },
// Add your new page
"/about": {
component: AboutPage
},
// For module pages (that display lists of content)
"/produits": {
component: ProduitsPage,
moduleType: "products" // ← Enables automatic sitemap subpage generation
},
};
About moduleType:
- Add this ONLY for pages that display module content (products, news, etc.)
- This automatically generates sitemap subpages (e.g.,
/produits/product-slug) - See ROUTING_GUIDE.md → Module Pages for details
Step 4: Test Your Page
- Start the development server:
npm run dev - Visit:
http://localhost:5173/about - Your component should render with SEO metadata from the database
Component Props
Each page component receives a page prop with metadata:
interface PageProps {
page: {
_id: string;
path: string;
title: string;
seo: {
metaTitle?: string;
metaDescription?: string;
metaKeywords?: string[];
// ... more SEO fields
};
active: boolean;
indexed: boolean;
// ... more fields
};
}
export default function MyPage({ page }: PageProps) {
// Use page metadata if needed
console.log(page.seo.metaTitle);
return <div>...</div>;
}
File Naming Convention
Follow these conventions for consistency:
- File location:
app/pages/ - File naming:
[name].page.tsx - Component naming: PascalCase + "Page" suffix
Examples:
app/pages/
├── test.page.tsx → TestPage
├── about.page.tsx → AboutPage
├── contact.page.tsx → ContactPage
├── services.page.tsx → ServicesPage
└── privacy-policy.page.tsx → PrivacyPolicyPage
Nested Routes
For nested routes like /services/web-development:
- Database: Create page with path
/services/web-development - Component: Create file
app/pages/services-web-development.page.tsx - Registry: Register as
"/services/web-development": ServicesWebDevelopmentPage
Styling
The template uses Tailwind CSS. Common patterns:
export default function MyPage() {
return (
<div className="space-y-8">
{/* Hero Section */}
<section className="bg-blue-600 text-white rounded-lg p-12">
<h2 className="text-4xl font-bold mb-4">Hero Title</h2>
<p className="text-xl">Hero description</p>
</section>
{/* Content Section */}
<section className="prose prose-lg max-w-none">
<h3>Content Title</h3>
<p>Content goes here...</p>
</section>
</div>
);
}
SEO & Meta Tags
Division of Responsibilities
Database (Managed in Baldr-BO):
- Meta title, description, keywords
- Open Graph tags (social sharing)
- Twitter cards
- Canonical URLs
- Indexing directives (
robots) - Sitemap configuration
- Scheduled publishing
Component (Developer Code):
- Page content and structure
- Layout and styling
- Interactive elements
- Client-side functionality
For complete SEO implementation details, see ROUTING_GUIDE.md → SEO & Meta Tags
Module Pages & Sitemap
Module pages display lists of content and automatically generate sitemap subpages.
Example: Products page at /produits
// In pageRegistry.ts
"/produits": {
component: ProduitsPage,
moduleType: "products" // ← Automatically generates /produits/product-slug in sitemap
}
Sitemap will include:
/produits(main page)/produits/product-1,/produits/product-2, etc. (individual products)
For complete implementation details, see ROUTING_GUIDE.md → Module Pages
SEO Features
Alternate URLs (hreflang)
For complete hreflang and internationalization documentation, see ROUTING_GUIDE.md → SEO & Meta Tags
Quick Reference:
Alternate URLs tell search engines about different language versions of your page:
English Page (/en/about):
{
{ "lang": "en", "url": "https://mysite.com/en/about" },
{ "lang": "fr", "url": "https://mysite.com/fr/about" },
{ "lang": "es", "url": "https://mysite.com/es/about" },
{ "lang": "x-default", "url": "https://mysite.com/en/about" }
]
}
French Page (/fr/about):
{
"alternateUrls": [
{ "lang": "en", "url": "https://mysite.com/en/about" },
{ "lang": "fr", "url": "https://mysite.com/fr/about" },
{ "lang": "es", "url": "https://mysite.com/es/about" },
{ "lang": "x-default", "url": "https://mysite.com/en/about" }
]
}
Important: Each language version should reference ALL other versions, including itself.
Canonical URLs
Canonical URLs tell search engines which version of a page is the "master" copy when you have duplicate or similar content.
When to use:
- Multiple URLs showing the same content
- HTTP vs HTTPS versions
- With/without www
- Pagination or filtered content
Example:
Canonical URL: https://example.com/products/item
Renders as:
<link rel="canonical" href="https://example.com/products/item" />
Best Practices
✅ Do:
- Keep components focused on content and layout
- Use Tailwind classes for styling
- Lazy load page components (already configured)
- Test pages on different screen sizes
- Use semantic HTML elements
❌ Don't:
- Put SEO metadata in components (use database)
- Duplicate SEO data
- Create huge single-file components
- Forget to register new pages
- Hard-code URLs (use Link component)
Component Organization
For larger pages, organize into sections:
// app/pages/about/
├── index.page.tsx // Main component
├── HeroSection.tsx
├── TeamSection.tsx
└── TimelineSection.tsx
// In about/index.page.tsx
import HeroSection from './HeroSection';
import TeamSection from './TeamSection';
import TimelineSection from './TimelineSection';
export default function AboutPage() {
return (
<div className="space-y-12">
<HeroSection />
<TeamSection />
<TimelineSection />
</div>
);
}
Troubleshooting
Page shows "Component Not Found"
- Check if the component is registered in
pageRegistry.ts - Verify path in database matches registry key exactly (case-sensitive!)
- Ensure component file exists and exports default
SEO metadata not showing
- Verify page is
active: truein database - Check SEO fields are filled in Baldr-BO
- Clear browser cache
- View page source to inspect
<head>tags
Module page not generating subpages
- Verify
moduleTypeis set in pageRegistry - Check module items exist in database with
active: true - Visit
/sitemap.xmlto verify subpages are included - Restart backend server after changes
For more troubleshooting, see ROUTING_GUIDE.md → Troubleshooting
Example: Complete Page Creation
Let's create a "Contact" page:
1. Admin (Baldr-Bo):
Title: Contact Us
Path: /contact
Page Type: standard
SEO Title: Contact Us - Get in Touch
SEO Description: Have questions? Reach out to our team.
Active: ✓
2. Component (app/pages/contact.page.tsx):
export default function ContactPage() {
return (
<div className="space-y-8">
<section>
<h2 className="text-3xl font-bold mb-4">Get in Touch</h2>
<p className="text-gray-600">We'd love to hear from you!</p>
</section>
<section className="bg-white p-8 rounded-lg shadow">
<form className="space-y-4">
<input type="text" placeholder="Name" className="w-full p-3 border rounded" />
<input type="email" placeholder="Email" className="w-full p-3 border rounded" />
<textarea placeholder="Message" className="w-full p-3 border rounded h-32" />
<button className="bg-blue-600 text-white px-6 py-3 rounded">
Send Message
</button>
</form>
</section>
</div>
);
}
3. Registry (app/config/pageRegistry.ts):
const ContactPage = lazy(() => import("../pages/contact.page"));
export const pageRegistry = {
"/test": TestPage,
"/contact": ContactPage, // Add this
};
4. Visit: http://localhost:5173/contact
Happy coding! 🚀