Skip to content

Francesco-Fera/next-starter

Repository files navigation

Next Starter ReadMe

Tech Stack

  • Frontend: Next.js 15 with React 19.0
  • Styling: TailwindCSS with shadcn/ui components
  • Authentication: Supabase Auth
  • Database: Supabase
  • Payments: Stripe
  • Email: Mailgun

Getting Started

  1. Clone the repository:

    git clone https://github.com/Francesco-Fera/next-starter.git
    cd next-starter
  2. Install dependencies:

    npm install --legacy-peer-deps
  3. Set up environment variables:

    • Create a .env.local file in the root directory.
    • Add the following variables, ensuring they match your Supabase, Stripe, and Mailgun credentials:
    NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
    SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
    STRIPE_SECRET_KEY=your_stripe_secret_key
    MAILGUN_API_KEY=your_mailgun_api_key
    MAILGUN_DOMAIN=your_mailgun_domain
  4. Start the development server:

    npm run dev

Authentication

Environment Variables

Ensure you have added your Supabase credentials in .env.local:

NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key

Project Structure

src/
├── app/
│   ├── (auth)/
│   │   ├── callback/     # OAuth callback handling
│   │   ├── login/        # Login page
│   │   ├── register/     # Registration page
│   │   └── layout.tsx    # Auth layout with session check
├── components/
│   ├── login-form.tsx    # Login form component
│   └── register-form.tsx # Registration form component
└── lib/
    └── supabase/
        ├── client.ts     # Browser client initialization
        └── server.ts     # Server client initialization

Authentication Methods

1. Email/Password Authentication

// Login
const { error } = await supabase.auth.signInWithPassword({
  email,
  password,
});

// Registration
const { error } = await supabase.auth.signUp({
  email,
  password,
});

2. Magic Link Authentication

const { error } = await supabase.auth.signInWithOtp({
  email,
});

3. OAuth (Google) Authentication

const { error } = await supabase.auth.signInWithOAuth({
  provider: "google",
  options: {
    redirectTo: `${window.location.origin}/auth/callback`,
  },
});

Sign Out

const handleSignOut = async () => {
  "use server";
  const supabase = createClient();
  await supabase.auth.signOut();
  redirect("/auth/login");
};

Checking Authentication Status

const supabase = createClient();
const {
  data: { user },
} = await supabase.auth.getUser();

if (user) {
  // User is authenticated
} else {
  // User is not authenticated
}

SEO Features

Basic Meta Tags

// app/layout.tsx
export const metadata: Metadata = {
  title: "Your App Name",
  description: "Your app description",
  keywords: ["keyword1", "keyword2"],
};

OpenGraph Support

export const metadata: Metadata = {
  openGraph: {
    type: "website",
    locale: "en_US",
    url: "https://yourdomain.com",
    siteName: "Your App Name",
    images: [
      {
        url: "https://yourdomain.com/og-image.jpg",
        width: 1200,
        height: 630,
        alt: "Your App Name",
      },
    ],
  },
};

Sitemap Generation

Static Sitemap

// app/sitemap.ts
export default async function sitemap() {
  const routes = ["", "/about", "/features", "/pricing"];
  return routes.map((route) => ({
    url: `https://yourdomain.com${route}`,
    lastModified: new Date(),
  }));
}

Dynamic Sitemap

export default async function sitemap() {
  const posts = await fetchPosts();
  const postUrls = posts.map((post) => ({
    url: `https://yourdomain.com/blog/${post.slug}`,
    lastModified: post.updatedAt,
  }));
  return [...postUrls];
}

Stripe Integration

Configuration

Ensure the following environment variables are set:

STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...

Features

1. Payment Processing

import { stripe } from "@/lib/stripe";

const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000,
  currency: "usd",
  payment_method_types: ["card"],
});

2. Subscription Management

const subscription = await stripe.subscriptions.create({
  customer: customerId,
  items: [{ price: "price_H5ggYwtDq4fbrJ" }],
  payment_behavior: "default_incomplete",
  payment_settings: { save_default_payment_method: "on_subscription" },
  expand: ["latest_invoice.payment_intent"],
});

3. Webhook Handling

// app/api/webhooks/stripe/route.ts
import { stripe } from "@/lib/stripe";
import { headers } from "next/headers";

export async function POST(req: Request) {
  const body = await req.text();
  const signature = headers().get("Stripe-Signature") as string;
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      body,
      signature,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    return new Response(`Webhook Error: ${err.message}`, { status: 400 });
  }
  return new Response(null, { status: 200 });
}

License

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published