Skip to main content
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.

High-Level Overview

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

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

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.

Authentication Routes ((auth)/)

Purpose: User authentication flows (sign-up, sign-in, password reset)
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
Auth pages use src/components/auth/auth-page-layout.tsx for consistent styling.

Dashboard Routes ((dashboard)/)

Purpose: Protected application area (requires authentication)
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
All routes under (dashboard)/ are protected by middleware. Unauthenticated users are redirected to /sign-in.

Marketing Routes ((marketing)/)

Purpose: Public marketing pages for your SaaS
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)
The marketing layout (layout.tsx) includes the site header and footer, applied to all marketing pages.

Purpose: Legal documents rendered from MDX
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
Content Source:
  • Blog posts in src/content/blog/*.mdx
  • Frontmatter: title, description, date, author, thumbnail, tags
  • Dynamic route [slug] matches MDX filename
To add a blog post, create a new .mdx file in src/content/blog/ with the required frontmatter.

Changelog Routes (changelog/)

Purpose: Version release notes
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
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)
API routes export HTTP method handlers: export async function POST(request: Request) { ... }

Auth Callback (auth/)

Purpose: Supabase authentication callback handler
Handles:
  • OAuth redirects (Google, GitHub, Apple)
  • Email verification links
  • Magic link authentication
  • Password reset confirmations
This route is critical for auth flows. Ensure /auth/callback is added to Supabase Redirect URLs.

Root Files

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:

UI Components (ui/)

50+ Components from shadcn/ui and Magic UI:
  • Button, Badge, Card, Separator, Skeleton
  • Avatar, Tabs, Toggle, Progress, Spinner, KBD
All UI components use Tailwind CSS with CSS variables for theming. Modify theme colors in app/globals.css.

Auth Components (auth/)

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/)

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/)

Customization:
  • Edit text and copy directly in each component
  • Modify pricing plans in src/lib/payments/plans.ts
These components are composed together in (marketing)/page.tsx to create the homepage.

Shared Components (shared/)

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:

Supabase Library (lib/supabase/)

Creates a Supabase client for use in Client Components:
Exports two functions:
  • createClient() - Cookie-based client for Server Components, Server Actions
  • createServiceClient() - Service role client (admin access, bypasses RLS)
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).
TypeScript interfaces mirroring database schema:
  • UserProfile - user_profiles table
  • UserSubscription - user_subscriptions table
  • PaymentHistory - payment_history table
Import these for type-safe queries:

Payments Library (lib/payments/)

Exports a configured Stripe instance:
Centralized plan definitions plus helper utilities:
Used by pricing page, Stripe API routes, and webhook handlers.
Centralized exports so other modules can import stripe, plans, and helper functions from "@/lib/payments".

Content (src/content/)

MDX files for blog, changelog, and legal pages:
MDX Frontmatter Examples:
Add new content by creating a new .mdx file with the appropriate frontmatter. No code changes needed!

Hooks (src/hooks/)

Custom React hooks:
Usage Example:

Database (supabase/)

Supabase database configuration:
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
Run this migration in your Supabase Dashboard (SQL Editor) or via Supabase CLI (supabase db push).

Tests (tests/e2e/)

Playwright end-to-end tests:
Run Tests:
Tests run across Chromium, Firefox, WebKit, and mobile viewports (Pixel 5, iPhone 12).

Static Assets (public/)

Images, logos, and Open Graph images:
Files in public/ are served at the root path. Reference as /logo.png in your code.

Configuration Files


File Naming Conventions

Sabo follows Next.js and React best practices:
TypeConventionExample
Routespage.tsx(dashboard)/dashboard/page.tsx
Layoutslayout.tsx(marketing)/layout.tsx
API Routesroute.tsapi/contact/route.ts
Componentskebab-case.tsxcontact-form.tsx
Hooksuse-*.tsuse-mobile.ts
Utilitieskebab-case.tsutils.ts
MDX Contentkebab-case.mdxgetting-started.mdx

Key Architectural Decisions

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.
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.
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
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.