Skip to main content

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

GroupLayoutUse for
(marketing)/Header + Footer + AdBannerPublic pages — blog, pricing, FAQ, about
(dashboard)/Header + user dashboard layoutLogged-in user pages
(admin)/admin/Admin sidebar layoutAdmin-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

app/(marketing)/roadmap/page.tsx
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>
  );
}

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:

  1. Create content/docs/<section>/<page>.mdx with frontmatter
  2. Add an entry to lib/docs/navigation.ts

With AI

AI Prompt· Add a new page

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 db singleton 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).

See also