> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsabo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Project Structure

> Understand how Sabo's codebase is organized, from routes and components to libraries and content.

<Info>
  Sabo uses Next.js 16 App Router with route groups for clean organization. This guide explains every major folder and file, helping you understand where to find and modify code.
</Info>

## High-Level Overview

```bash theme={null}
sabo/
├── src/                  # Application source code
│   ├── app/             # Next.js App Router (routes)
│   ├── components/      # React components
│   ├── lib/             # Libraries and utilities
│   ├── hooks/           # Custom React hooks
│   ├── content/         # MDX content (blog, changelog, legal)
│   └── proxy.ts         # Top-level middleware
├── supabase/            # Database migrations
├── tests/               # Playwright E2E tests
├── public/              # Static assets
└── [config files]       # next.config.ts, tsconfig.json, etc.
```

<Tip>
  Sabo follows Next.js conventions for file naming: `page.tsx` for routes, `layout.tsx` for layouts, `route.ts` for API endpoints.
</Tip>

***

## Application Routes (`src/app/`)

Next.js App Router uses folders for routes. Sabo organizes routes with **route groups** (folders wrapped in parentheses) that don't affect the URL structure:

### Route Groups Explained

```bash theme={null}
src/app/
├── (auth)/              # Authentication pages (public)
├── (dashboard)/         # Protected app area (requires login)
├── (marketing)/         # Public marketing pages
├── (legal)/             # Legal documents
├── blog/                # Blog system
├── changelog/           # Changelog system
├── api/                 # API endpoints
├── layout.tsx           # Root layout (applies to all pages)
└── not-found.tsx        # 404 page
```

<Note>
  Route groups like `(auth)` organize files without adding `/auth` to the URL. For example, `(auth)/sign-in/page.tsx` becomes `/sign-in`, not `/auth/sign-in`.
</Note>

***

### Authentication Routes (`(auth)/`)

**Purpose:** User authentication flows (sign-up, sign-in, password reset)

```bash theme={null}
(auth)/
├── actions.ts                  # Server actions for auth (signIn, signUp, etc.)
├── sign-in/
│   ├── page.tsx               # /sign-in
│   └── confirm/
│       └── page.tsx           # /sign-in/confirm (magic link confirmation)
├── sign-up/
│   ├── page.tsx               # /sign-up
│   └── confirm/
│       └── page.tsx           # /sign-up/confirm (email verification prompt)
├── forgot-password/
│   └── page.tsx               # /forgot-password
└── reset-password/
    └── page.tsx               # /reset-password
```

**Key Files:**

* `actions.ts` - Server actions called by auth forms (handles Supabase API calls)
* Each `page.tsx` - React Server Component rendering the auth UI
* `/confirm` pages - Post-submission confirmation screens

<Tip>
  Auth pages use `src/components/auth/auth-page-layout.tsx` for consistent styling.
</Tip>

***

### Dashboard Routes (`(dashboard)/`)

**Purpose:** Protected application area (requires authentication)

```bash theme={null}
(dashboard)/
└── dashboard/
    ├── layout.tsx              # Dashboard layout with sidebar
    ├── page.tsx                # /dashboard (main dashboard page)
    ├── data.json               # Sample chart/table data
    └── settings/
        ├── general/
        │   └── page.tsx        # /dashboard/settings/general
        ├── account/
        │   └── page.tsx        # /dashboard/settings/account
        ├── billing/
        │   └── page.tsx        # /dashboard/settings/billing
        └── notifications/
            └── page.tsx        # /dashboard/settings/notifications
```

**Key Files:**

* `layout.tsx` - Sidebar layout wrapping all dashboard pages (uses `SidebarProvider` from shadcn/ui)
* `page.tsx` - Dashboard homepage with sample cards, chart, and data table
* `settings/*` - User settings pages connected to `user_profiles` and `user_subscriptions` tables

<Check>
  All routes under `(dashboard)/` are protected by middleware. Unauthenticated users are redirected to `/sign-in`.
</Check>

***

### Marketing Routes (`(marketing)/`)

**Purpose:** Public marketing pages for your SaaS

```bash theme={null}
(marketing)/
├── layout.tsx                  # Marketing layout (header + footer)
├── page.tsx                    # / (homepage)
├── pricing/
│   └── page.tsx               # /pricing
└── contact/
    └── page.tsx               # /contact
```

**Key Files:**

* `page.tsx` (root) - Homepage with hero, features, pricing, testimonials, FAQ, CTA
* `pricing/page.tsx` - Full pricing page with plan comparison
* `contact/page.tsx` - Contact form (submits to `/api/contact`)

<Note>
  The marketing layout (`layout.tsx`) includes the site header and footer, applied to all marketing pages.
</Note>

***

### Legal Routes (`(legal)/`)

**Purpose:** Legal documents rendered from MDX

```bash theme={null}
(legal)/
├── layout.tsx                  # Legal pages layout
├── privacy/
│   └── page.tsx               # /privacy
├── terms-of-service/
│   └── page.tsx               # /terms-of-service
└── cookie-policy/
    └── page.tsx               # /cookie-policy
```

**Content Source:**

* Pages fetch content from `src/content/legal/*.mdx`
* MDX files use frontmatter for metadata (title, lastUpdated)

***

### Blog Routes (`blog/`)

**Purpose:** MDX-based blog system

```bash theme={null}
blog/
├── layout.tsx                  # Blog layout (no route group, URLs are /blog/*)
├── page.tsx                    # /blog (list all posts)
├── blog-client.tsx             # Client component for tag filtering
└── [slug]/
    └── page.tsx               # /blog/[slug] (individual post)
```

**Content Source:**

* Blog posts in `src/content/blog/*.mdx`
* Frontmatter: title, description, date, author, thumbnail, tags
* Dynamic route `[slug]` matches MDX filename

<Tip>
  To add a blog post, create a new `.mdx` file in `src/content/blog/` with the required frontmatter.
</Tip>

***

### Changelog Routes (`changelog/`)

**Purpose:** Version release notes

```bash theme={null}
changelog/
├── layout.tsx                  # Changelog layout
├── page.tsx                    # /changelog (list all versions)
└── [slug]/
    └── page.tsx               # /changelog/[slug] (version details)
```

**Content Source:**

* Changelog entries in `src/content/changelog/*.mdx`
* Frontmatter: version, title, description, date
* Entries sorted by date (newest first)

***

### API Routes (`api/`)

**Purpose:** Backend API endpoints

```bash theme={null}
api/
├── contact/
│   └── route.ts               # POST /api/contact
├── checkout_sessions/
│   └── route.ts               # POST /api/checkout_sessions (Stripe Checkout)
├── customer_portal/
│   └── route.ts               # POST /api/customer_portal (Stripe portal)
└── webhooks/
    └── stripe/
        └── route.ts           # POST /api/webhooks/stripe
```

**Key Files:**

* `contact/route.ts` - Contact form submission handler
* `checkout_sessions/route.ts` - Creates Stripe Checkout session
* `customer_portal/route.ts` - Generates Stripe Customer Portal URL
* `webhooks/stripe/route.ts` - Handles Stripe webhook events (subscription lifecycle, invoices)

<Note>
  API routes export HTTP method handlers: `export async function POST(request: Request) { ... }`
</Note>

***

### Auth Callback (`auth/`)

**Purpose:** Supabase authentication callback handler

```bash theme={null}
auth/
└── callback/
    └── route.ts               # GET /auth/callback
```

**Handles:**

* OAuth redirects (Google, GitHub, Apple)
* Email verification links
* Magic link authentication
* Password reset confirmations

<Warning>
  This route is critical for auth flows. Ensure `/auth/callback` is added to Supabase **Redirect URLs**.
</Warning>

***

### Root Files

```bash theme={null}
app/
├── layout.tsx                  # Root layout (HTML, body, providers)
├── globals.css                 # Global Tailwind CSS styles
├── not-found.tsx               # 404 error page
├── favicon.ico                 # Site favicon
├── robots.ts                   # robots.txt generator
├── sitemap.ts                  # sitemap.xml generator
└── success/
    └── page.tsx               # /success (post-payment success page)
```

**Key Files:**

* `layout.tsx` - Wraps all pages, includes `<html>`, `<body>`, and global providers (theme, auth, PostHog)
* `globals.css` - Tailwind directives, CSS variables for theming, custom utilities
* `sitemap.ts` - Generates dynamic sitemap including blog/changelog posts

***

## Components (`src/components/`)

React components organized by feature:

```bash theme={null}
components/
├── ui/                         # shadcn/ui + Magic UI (50+ components)
├── auth/                       # Authentication components
├── dashboard/                  # Dashboard-specific components
├── marketing/                  # Marketing page components
├── shared/                     # Shared components (header, footer, etc.)
├── example/                    # Demo components (for UI gallery)
├── theme-provider.tsx          # next-themes provider
└── posthog-provider.tsx        # PostHog analytics provider
```

### UI Components (`ui/`)

**50+ Components** from shadcn/ui and Magic UI:

<Tabs>
  <Tab title="Base Components">
    * Button, Badge, Card, Separator, Skeleton
    * Avatar, Tabs, Toggle, Progress, Spinner, KBD
  </Tab>

  <Tab title="Form Components">
    * Input, Textarea, Select, Checkbox, Switch
    * Radio Group, Slider, Calendar, Label, Field
  </Tab>

  <Tab title="Overlays">
    * Dialog, Alert Dialog, Sheet, Drawer
    * Dropdown Menu, Popover, Tooltip
  </Tab>

  <Tab title="Data Display">
    * Table, Chart, Accordion, Collapsible, Scroll Area
  </Tab>

  <Tab title="Navigation">
    * Navigation Menu, Sidebar, Breadcrumb
  </Tab>

  <Tab title="Magic UI (Animated)">
    * Bento Grid, Marquee, Animated Beam, Animated List
    * Orbiting Circles, Number Ticker, Particles
    * Border Beam, Shine Border, Interactive Grid Pattern
  </Tab>
</Tabs>

<Tip>
  All UI components use Tailwind CSS with CSS variables for theming. Modify theme colors in `app/globals.css`.
</Tip>

***

### Auth Components (`auth/`)

```bash theme={null}
auth/
├── auth-context.tsx            # Auth context provider (user state)
├── auth-page-layout.tsx        # Consistent layout for auth pages
└── oauth-buttons.tsx           # OAuth provider buttons (Google, GitHub, Apple)
```

**Usage:**

* `auth-context.tsx` - Provides `useAuth()` hook for accessing user state
* `oauth-buttons.tsx` - Reusable OAuth buttons called from sign-in/sign-up pages

***

### Dashboard Components (`dashboard/`)

```bash theme={null}
dashboard/
├── app-sidebar.tsx             # Main sidebar with navigation
├── nav-main.tsx                # Primary navigation items
├── nav-projects.tsx            # Project switcher items
├── nav-secondary.tsx           # Secondary navigation items
├── nav-user.tsx                # User menu in sidebar footer
├── team-switcher.tsx           # Team/workspace selector
├── header-user-menu.tsx        # User dropdown in header
├── notifications-dropdown.tsx  # Notifications bell dropdown
├── section-cards.tsx           # Dashboard stat cards
├── chart-area-interactive.tsx  # Interactive area chart (Recharts)
└── data-table.tsx              # Advanced data table (@tanstack/react-table)
```

**Key Files:**

* `app-sidebar.tsx` - Composes all `nav-*` components into the full sidebar
* `data-table.tsx` - Includes sorting, filtering, column visibility, and drag-drop

***

### Marketing Components (`marketing/`)

```bash theme={null}
marketing/
├── hero.tsx                    # Hero section with CTA
├── features-grid.tsx           # Features in grid layout
├── features-bento-grid.tsx     # Features in bento grid layout
├── features-accordion.tsx      # Features in accordion layout
├── social-proof.tsx            # Logo carousel (partner logos)
├── pricing.tsx                 # Pricing plans comparison
├── testimonials.tsx            # Customer testimonials
├── faq.tsx                     # FAQ accordion
├── cta.tsx                     # Call-to-action section
└── contact-form.tsx            # Contact form (with Zod validation)
```

**Customization:**

* Edit text and copy directly in each component
* Modify pricing plans in `src/lib/payments/plans.ts`

<Note>
  These components are composed together in `(marketing)/page.tsx` to create the homepage.
</Note>

***

### Shared Components (`shared/`)

```bash theme={null}
shared/
├── header.tsx                  # Site header (marketing pages)
├── footer.tsx                  # Site footer
├── mobile-nav.tsx              # Mobile navigation drawer
├── logo.tsx                    # Site logo component
├── theme-toggle.tsx            # Dark/light mode toggle
├── mode-toggle.tsx             # Alternative theme toggle
├── status-badge.tsx            # Better Stack status badge
└── language-selector.tsx       # Language/locale selector
```

**Key Files:**

* `header.tsx` - Desktop navigation with links
* `mobile-nav.tsx` - Drawer navigation for mobile viewports
* `footer.tsx` - Includes links, social icons, and status badge

***

## Libraries (`src/lib/`)

Utility functions, clients, and integrations:

```bash theme={null}
lib/
├── supabase/                   # Supabase clients and types
│   ├── client.ts              # Browser client (createClient)
│   ├── server.ts              # Server client (createClient, createServiceClient)
│   ├── middleware.ts          # Auth middleware (updateSession, route protection)
│   └── types.ts               # TypeScript types (UserProfile, UserSubscription, PaymentHistory)
├── payments/                   # Stripe integration
│   ├── stripe.ts              # Stripe client instance
│   ├── plans.ts               # Plan configuration + helpers
│   └── index.ts               # Re-export entry point for payments module
├── posthog/                    # PostHog analytics
│   ├── index.ts               # Re-exports
│   └── server.ts              # Server-side PostHog client
├── posts.ts                    # Blog utilities (getAllPosts, getPostBySlug)
├── changelog.ts                # Changelog utilities (getAllChangelogs, getChangelogBySlug)
└── utils.ts                    # General utilities (cn for Tailwind classes)
```

### Supabase Library (`lib/supabase/`)

<AccordionGroup>
  <Accordion title="client.ts - Browser Client">
    Creates a Supabase client for use in Client Components:

    ```tsx theme={null}
    import { createClient } from "@/lib/supabase/client";

    export function MyComponent() {
      const supabase = createClient();
      // Use supabase.auth, supabase.from(), etc.
    }
    ```
  </Accordion>

  <Accordion title="server.ts - Server Clients">
    Exports two functions:

    * `createClient()` - Cookie-based client for Server Components, Server Actions
    * `createServiceClient()` - Service role client (admin access, bypasses RLS)

    ```tsx theme={null}
    import { createClient } from "@/lib/supabase/server";

    export default async function Page() {
      const supabase = await createClient();
      const { data } = await supabase.from('user_profiles').select();
      // ...
    }
    ```
  </Accordion>

  <Accordion title="middleware.ts - Auth Middleware">
    Exports `updateSession()` which:

    * Refreshes the user's Supabase session
    * Redirects unauthenticated users from protected routes
    * Redirects authenticated users away from auth pages

    Called from `src/proxy.ts` (top-level middleware).
  </Accordion>

  <Accordion title="types.ts - Database Types">
    TypeScript interfaces mirroring database schema:

    * `UserProfile` - user\_profiles table
    * `UserSubscription` - user\_subscriptions table
    * `PaymentHistory` - payment\_history table

    Import these for type-safe queries:

    ```tsx theme={null}
    import type { UserProfile } from "@/lib/supabase/types";
    ```
  </Accordion>
</AccordionGroup>

***

### Payments Library (`lib/payments/`)

<AccordionGroup>
  <Accordion title="stripe.ts - Stripe Client">
    Exports a configured Stripe instance:

    ```ts theme={null}
    import { stripe } from "@/lib/payments/stripe";

    const session = await stripe.checkout.sessions.create({ ... });
    ```
  </Accordion>

  <Accordion title="plans.ts - Plan Configuration">
    Centralized plan definitions plus helper utilities:

    ```ts theme={null}
    export const plans: Plan[] = [
      { id: "free", name: "Free", monthlyPrice: 0, ... },
      { id: "pro", name: "Pro", monthlyPrice: 12, ... },
      { id: "enterprise", name: "Enterprise", monthlyPrice: null, ... }
    ];

    export function getPlanById(planId: string): Plan | undefined
    export function getPlanByPriceId(priceId: string): Plan | undefined
    export function isYearlyPrice(priceId: string): boolean
    export function getBillingCycle(priceId: string): "month" | "year"
    export function formatPrice(amount: number): string
    ```

    Used by pricing page, Stripe API routes, and webhook handlers.
  </Accordion>

  <Accordion title="index.ts - Module Exports">
    Centralized exports so other modules can import `stripe`, `plans`, and helper functions from `"@/lib/payments"`.
  </Accordion>
</AccordionGroup>

***

## Content (`src/content/`)

MDX files for blog, changelog, and legal pages:

```bash theme={null}
content/
├── blog/                       # Blog posts
│   ├── getting-started.mdx
│   ├── technical-deep-dive.mdx
│   └── type-safe-forms-with-zod.mdx
├── changelog/                  # Version releases
│   ├── 0-1-0.mdx
│   ├── 0-2-0.mdx
│   └── 0-3-0.mdx
└── legal/                      # Legal documents
    ├── privacy.mdx
    ├── terms-of-service.mdx
    └── cookie-policy.mdx
```

**MDX Frontmatter Examples:**

<Tabs>
  <Tab title="Blog Post">
    ```yaml theme={null}
    ---
    title: "Getting Started with Sabo"
    description: "Learn how to set up and deploy your SaaS in minutes"
    date: "2024-01-15"
    author:
      name: "John Doe"
      picture: "/blog/authors/john-doe.png"
    thumbnail: "/blog/thumbnails/getting-started.png"
    tags: ["tutorial", "setup"]
    ---
    ```
  </Tab>

  <Tab title="Changelog">
    ```yaml theme={null}
    ---
    version: "0.3.0"
    title: "PostHog Integration"
    description: "Added analytics tracking with PostHog"
    date: "2024-11-15"
    ---
    ```
  </Tab>

  <Tab title="Legal">
    ```yaml theme={null}
    ---
    title: "Privacy Policy"
    lastUpdated: "2024-01-01"
    ---
    ```
  </Tab>
</Tabs>

<Tip>
  Add new content by creating a new `.mdx` file with the appropriate frontmatter. No code changes needed!
</Tip>

***

## Hooks (`src/hooks/`)

Custom React hooks:

```bash theme={null}
hooks/
├── use-media-query.ts          # Responsive breakpoint hook (SSR-safe)
└── use-mobile.ts               # Mobile viewport hook (768px breakpoint)
```

**Usage Example:**

```tsx theme={null}
import { useIsMobile } from "@/hooks/use-mobile";

export function MyComponent() {
  const isMobile = useIsMobile();

  return isMobile ? <MobileView /> : <DesktopView />;
}
```

***

## Database (`supabase/`)

Supabase database configuration:

```bash theme={null}
supabase/
├── migrations/
│   └── 20240101000000_create_user_profiles.sql
└── README.md
```

**Migration Creates:**

* `user_profiles` table (profile data, preferences)
* `user_subscriptions` table (Stripe subscription sync)
* `payment_history` table (payment records)
* `stripe_products` table (product catalog)
* RLS policies for all tables
* `profile-images` storage bucket

<Note>
  Run this migration in your Supabase Dashboard (SQL Editor) or via Supabase CLI (`supabase db push`).
</Note>

***

## Tests (`tests/e2e/`)

Playwright end-to-end tests:

```bash theme={null}
tests/
└── e2e/
    ├── auth/                   # Authentication tests (3 files)
    ├── dashboard/              # Dashboard tests (5 files)
    ├── marketing/              # Marketing page tests (3 files)
    ├── blog/                   # Blog tests (2 files)
    ├── changelog/              # Changelog tests (2 files)
    ├── legal/                  # Legal page tests (1 file)
    └── helpers/
        └── auth.ts             # Test helpers (setupAuthenticatedUser)
```

**Run Tests:**

```bash theme={null}
pnpm test:e2e          # Headless mode
pnpm test:e2e:ui       # UI mode (interactive)
pnpm test:e2e:headed   # Browser visible
```

<Tip>
  Tests run across Chromium, Firefox, WebKit, and mobile viewports (Pixel 5, iPhone 12).
</Tip>

***

## Static Assets (`public/`)

Images, logos, and Open Graph images:

```bash theme={null}
public/
├── logo.png                    # Site logo
├── logos/                      # Tech stack logos (Stripe, Supabase, etc.)
├── blog/
│   ├── authors/               # Author profile pictures
│   └── thumbnails/            # Blog post thumbnails
└── og/                         # Open Graph images for social sharing
```

<Note>
  Files in `public/` are served at the root path. Reference as `/logo.png` in your code.
</Note>

***

## Configuration Files

```bash theme={null}
sabo/
├── next.config.ts              # Next.js configuration
├── tsconfig.json               # TypeScript configuration
├── eslint.config.mjs           # ESLint configuration
├── playwright.config.ts        # Playwright test configuration
├── postcss.config.mjs          # PostCSS configuration (Tailwind)
├── components.json             # shadcn/ui configuration
├── package.json                # Dependencies and scripts
└── pnpm-lock.yaml              # Lockfile
```

***

## File Naming Conventions

Sabo follows Next.js and React best practices:

| Type        | Convention       | Example                          |
| ----------- | ---------------- | -------------------------------- |
| Routes      | `page.tsx`       | `(dashboard)/dashboard/page.tsx` |
| Layouts     | `layout.tsx`     | `(marketing)/layout.tsx`         |
| API Routes  | `route.ts`       | `api/contact/route.ts`           |
| Components  | `kebab-case.tsx` | `contact-form.tsx`               |
| Hooks       | `use-*.ts`       | `use-mobile.ts`                  |
| Utilities   | `kebab-case.ts`  | `utils.ts`                       |
| MDX Content | `kebab-case.mdx` | `getting-started.mdx`            |

***

## Key Architectural Decisions

<AccordionGroup>
  <Accordion title="Why route groups?">
    Route groups (`(auth)`, `(dashboard)`, etc.) organize code without affecting URLs. This keeps the file structure clean while maintaining short, user-friendly paths like `/sign-in` instead of `/auth/sign-in`.
  </Accordion>

  <Accordion title="Why separate client and server Supabase clients?">
    Next.js Server Components and Client Components require different Supabase clients:

    * **Server client** (`server.ts`) uses cookies for SSR
    * **Browser client** (`client.ts`) works in Client Components

    This separation prevents hydration mismatches and ensures auth works correctly.
  </Accordion>

  <Accordion title="Why centralize plans in lib/payments/plans.ts?">
    Defining plans in one place makes it easy to:

    * Update pricing without touching multiple files
    * Add/remove plans
    * Sync plan data between UI, API, and webhooks
    * Type-check plan references
  </Accordion>

  <Accordion title="Why use Server Actions for auth?">
    Server Actions (`actions.ts`) provide a secure way to call Supabase APIs from Client Components without exposing API logic to the browser. They're called like regular functions but execute server-side.
  </Accordion>
</AccordionGroup>
