App Pages
App pages are the authenticated parts of your application where users interact with your product.
What This System Does
The app pages system provides:
- Protected route structure for authenticated pages
- Automatic authentication checks via layout wrapper
- Consistent page patterns and layouts
- Integration with entitlement-based feature gating
- Header component for navigation
Why It Exists
App pages separate your product functionality from marketing pages. They provide a secure, consistent structure for building authenticated user experiences with automatic protection and entitlement checking.
When You Need to Care About It
You'll interact with app pages when:
- Building your main product dashboard
- Creating new feature pages for authenticated users
- Adding pages that require specific entitlements
- Customizing the protected route structure
Key Concepts
Protected Route Structure
All authenticated pages live in /app/(protected)/. The layout at this level automatically calls requireAuth(), protecting all child pages.
Route Groups
The (protected) folder is a Next.js route group - it doesn't appear in the URL. Pages inside are accessible at their folder path (e.g., /product, /billing).
Entitlement Checking
Pages can require specific entitlements using requireEntitlement() or use the FeatureGate component for inline paywalls.
Protected Route Structure
All authenticated pages live in /app/(protected)/:
src/app/(protected)/
├── layout.tsx # Auth check wrapper
├── billing/
│ ├── layout.tsx # Billing metadata
│ └── page.tsx # Subscription management
├── product/
│ └── page.tsx # Main dashboard
└── pro-feature/
└── page.tsx # Demo paywall pageHow Protection Works
The layout at /app/(protected)/layout.tsx calls requireAuth():
export default async function ProtectedLayout({ children }) {
await requireAuth(); // Redirects to /auth if not logged in
return <div className="min-h-screen bg-gray-50">{children}</div>;
}All pages inside (protected)/ automatically inherit this check.
Existing Pages
Product Dashboard (`/product`)
Location: /app/(protected)/product/page.tsx
This is your main dashboard. Currently shows:
- User info
- Email test button
- Placeholder content
This is where you build your product.
Billing Page (`/billing`)
Location: /app/(protected)/billing/page.tsx
Shows:
- Current subscription plan
- Entitlements list
- Upgrade options
- Refresh button
Don't modify - This is core billing functionality.
Pro Feature Demo (`/pro-feature`)
Location: /app/(protected)/pro-feature/page.tsx
Demonstrates paywall usage:
- Gated feature (requires `pro_features`)
- Free feature (always visible)
Use this as a reference for your own paywalls.
Important Files
/app/(protected)/layout.tsxAuth check wrapper for all protected pages
🔒 CORE - Do not modify
/app/(protected)/product/page.tsxMain dashboard - build your product here
🏗️ EDITABLE
/app/(protected)/billing/page.tsxSubscription management
🔒 CORE - Do not modify
/components/Header.tsxNavigation header component
🏗️ EDITABLE
Adding New Pages
Basic Protected Page
1. Create folder and page:
/app/(protected)/your-page/page.tsx2. Add content:
import Header from "@/components/Header";
import { createStaticPageMetadata } from "@/lib/seo";
export const metadata = createStaticPageMetadata(
"Your Page",
"Page description"
);
export default function YourPage() {
return (
<div className="min-h-screen bg-gray-50">
<Header />
<main className="max-w-7xl mx-auto py-6 px-4">
<h1>Your Page</h1>
</main>
</div>
);
}Page with Entitlement Check
import { requireEntitlement } from "@/lib/auth-utils";
import Header from "@/components/Header";
export default async function ProPage() {
await requireEntitlement("pro_features"); // Redirects if missing
return (
<div className="min-h-screen bg-gray-50">
<Header />
<main>Pro-only content</main>
</div>
);
}Page with Inline Paywalls
import Header from "@/components/Header";
import { FeatureGate } from "@/components/FeatureGate";
export default function MixedPage() {
return (
<div className="min-h-screen bg-gray-50">
<Header />
<main className="max-w-7xl mx-auto py-6 px-4">
<FreeSection />
<FeatureGate entitlement="pro_features">
<ProSection />
</FeatureGate>
</main>
</div>
);
}Header Component
Use the Header component for consistent navigation:
import Header from "@/components/Header";It includes:
- Logo/brand link to `/product`
- Billing link (or back button when on billing)
- User avatar and name
- Sign out button
Page Patterns
Consistent Layout
<div className="min-h-screen bg-gray-50">
<Header />
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="px-4 py-6 sm:px-0">
{/* Your content */}
</div>
</main>
</div>With Cards
<main className="max-w-7xl mx-auto py-6 px-4">
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
</CardHeader>
<CardContent>
Content here
</CardContent>
</Card>
</main>What You Can Customize
- Your product dashboard in
/product - Additional feature pages
- Settings pages
- Any authenticated user experiences
- Header component styling and layout
What NOT to Change
/app/(protected)/layout.tsx- Auth wrapper/app/(protected)/billing/- Billing system- The auth check pattern
Related Sections
- Authentication - Understanding auth checks
- Entitlements - Feature gating
- Dashboard - Protected routes