CoreMVP

Project Structure

Understanding the codebase organization.

Overview

This template is a single Next.js application with API routes handled by Route Handlers. Business logic lives in server-only service files.

Directory Structure

layout.tsx

Key Directories

src/app/

Next.js App Router pages and API routes.

PathPurpose
(marketing)/Landing and pricing pages
api/Route Handlers for backend logic
dashboard/Protected user dashboard
docs/Documentation pages
signin/, signup/Authentication pages

src/services/

Server-only business logic. These files use the "server-only" pragma to prevent client imports.

ServicePurpose
auth/Sign up, sign in, OAuth, and account updates
billing/Stripe checkout, portal, webhooks
user/User profile queries

src/hooks/

Client-side React hooks for data fetching and state.

HookPurpose
auth/Session management, auth mutations
billing/Checkout, user status

src/lib/

Shared utilities and client configurations.

LibraryPurpose
supabase/Browser and server Supabase clients
stripe/Stripe client configuration

src/content/

MDX content for documentation and blog posts.


Data Flow

Browser → Next.js Page → API Route → Service → Supabase/Stripe
  1. Browser makes request to Next.js page or calls API route
  2. API Route (app/api/*/route.ts) handles HTTP request
  3. Service (services/*/service.ts) contains business logic
  4. Database/Stripe for persistence and payments

Key Files

FilePurpose
src/app/layout.tsxRoot layout with providers
src/lib/supabase/server.tsServer-side Supabase client
src/lib/supabase/middleware.tsAuth middleware for protected routes
src/services/billing/service.tsStripe checkout and portal logic
src/lib/source.tsFumadocs content source configuration

Services Pattern

Services use the "server-only" pragma to ensure they only run on the server:

src/services/auth/service.ts
import "server-only";

import { createSupabaseServerClient } from "@/lib/supabase/server";

export async function signUp({ email, password }) {
  const supabase = await createSupabaseServerClient();
  const { data, error } = await supabase.auth.signUp({ email, password });
  // ...
}

API routes import and call these services:

src/app/api/auth/sign-up/route.ts
import { NextResponse } from 'next/server';
import { signUp } from '@/services/auth';

export async function POST(request: Request) {
  const body = await request.json();
  const result = await signUp(body);
  return NextResponse.json(result);
}

This pattern keeps business logic separate from HTTP handling while maintaining type safety.

Was this page helpful?

On this page