Adding Pages
Add new routes inside DirectoryLaunch using Next.js route groups for marketing, dashboard, or admin layouts with the right auth guards in place.
DirectoryLaunch uses Next.js route groups (folders in parentheses) to apply shared layouts. Adding a new page = adding one page.tsx file under the right group.
Pick the right route group
| Group | Layout | Use for |
|---|---|---|
(marketing)/ | Header + Footer + AdBanner | Public pages — blog, pricing, FAQ, about |
(dashboard)/ | Header + user dashboard layout | Logged-in user pages |
(admin)/admin/ | Admin sidebar layout | Admin-only pages |
The parentheses in the folder name are stripped from the URL — they only exist to group by layout.
Example: add a public /roadmap page
1. Create the file
app/(marketing)/roadmap/page.tsx
2. Write the component
import type { Metadata } from 'next';
import { siteConfig } from '@/config/site.config';
export const metadata: Metadata = {
title: `Roadmap — ${siteConfig.name}`,
description: 'What we are building next.',
};
export default function RoadmapPage() {
return (
<div className="mx-auto max-w-3xl px-6 py-16">
<h1 className="text-4xl font-bold">Roadmap</h1>
<p className="mt-4 text-muted-foreground">
Features we're working on.
</p>
<ul className="mt-8 space-y-4">
<li>Q2: AI-powered search</li>
<li>Q3: Mobile app</li>
</ul>
</div>
);
}3. Add a nav link (optional)
If you want the page in the header or footer, edit components/layout/Header.tsx or components/layout/Footer.tsx and add your entry to the nav array.
Example: add a logged-in /invites page
1. Create the file
app/(dashboard)/invites/page.tsx
2. Protect it
import { requireAuth, getCurrentUser } from '@/lib/supabase/auth-helpers';
export default async function InvitesPage() {
const redirect = await requireAuth();
if (redirect) return redirect;
const user = await getCurrentUser();
return (
<div>
<h1>Your invites, {user!.email}</h1>
</div>
);
}Example: add an admin page
1. Create the file
app/(admin)/admin/reports/page.tsx
2. Protect it
import { isAdmin, requireAuth } from '@/lib/supabase/auth-helpers';
import { notFound } from 'next/navigation';
export default async function AdminReportsPage() {
const redirect = await requireAuth();
if (redirect) return redirect;
if (!(await isAdmin())) notFound();
return <div>Admin reports...</div>;
}Appears at /admin/reports. Won't show up for non-admins.
Pages that need data
Use the db helper for server-side data fetching:
import { db } from '@/lib/supabase/database';
export default async function LiveAppsPage() {
const apps = await db.find('apps',
{ status: 'live' },
{ sort: { upvotes: -1 }, limit: 20 }
);
return (
<ul>
{apps.map((app) => <li key={app.id}>{app.name}</li>)}
</ul>
);
}Adding an API route
If your page needs data mutations, pair it with an API route at app/api/your-thing/route.ts — see API Reference Overview for the template.
Docs page (this site)
If you want a new page in this documentation:
- Create
content/docs/<section>/<page>.mdxwith frontmatter - Add an entry to
lib/docs/navigation.ts
With AI
Add a new page at route
\{/your-url-path\}to this DirectoryLaunch project.Details:
- Purpose: {what the page is for — e.g. "a public roadmap", "a logged-in invites page", "an admin reports page"}
- Access: {public | logged-in-only | admin-only}
- Content sections: {list what the page shows — e.g. "a hero, a 3-column feature grid, a FAQ"}
- Data source: {static content | Supabase table "X" via db.find | Stripe API | none}
Follow CLAUDE.md conventions:
- Pick the right route group ((marketing) / (dashboard) / (admin)).
- Use @/ alias for imports.
- Use siteConfig for brand name in metadata.
- For protected pages, use
requireAuth()/isAdmin()from @/lib/supabase/auth-helpers. - For DB queries, use the
dbsingleton from @/lib/supabase/database. - Use shadcn/ui components from @/components/ui, not raw HTML.
Also add a nav link if appropriate (Header.tsx or Footer.tsx).