Project Structure

indiegoon follows a clear, predictable structure. Once you understand it, you'll always know where to find things and where to put new code.

Top-Level Overview

my-saas/
ā”œā”€ā”€ src/                    # All application code
│   ā”œā”€ā”€ app/                # Next.js App Router (pages + API)
│   ā”œā”€ā”€ components/         # React components
│   ā”œā”€ā”€ config/             # App configuration
│   └── lib/                # Core libraries (auth, db, payments, email)
ā”œā”€ā”€ content/                # MDX content (blog posts)
ā”œā”€ā”€ drizzle/                # Database migrations
ā”œā”€ā”€ tests/                  # E2E tests (Playwright)
ā”œā”€ā”€ public/                 # Static assets
ā”œā”€ā”€ .goon/                  # CLI manifest and AI rules
ā”œā”€ā”€ .env                    # Environment variables (never commit)
ā”œā”€ā”€ drizzle.config.ts       # Database config
ā”œā”€ā”€ next.config.ts          # Next.js config (security headers)
└── package.json            # Dependencies and scripts

The src/app/ Directory

Next.js App Router uses file-based routing with route groups:

src/app/
ā”œā”€ā”€ (app)/                  # Authenticated pages (requires login)
│   ā”œā”€ā”€ dashboard/          # Main dashboard
│   ā”œā”€ā”€ billing/            # Subscription management
│   ā”œā”€ā”€ settings/           # User settings
│   ā”œā”€ā”€ teams/              # Team management
│   ā”œā”€ā”€ admin/              # Admin panel (restricted)
│   └── layout.tsx          # App shell (sidebar + header)
│
ā”œā”€ā”€ (auth)/                 # Auth pages (no chrome, centered layout)
│   ā”œā”€ā”€ sign-in/
│   ā”œā”€ā”€ sign-up/
│   ā”œā”€ā”€ forgot-password/
│   ā”œā”€ā”€ reset-password/
│   ā”œā”€ā”€ verify-email/
│   └── layout.tsx          # Minimal auth layout
│
ā”œā”€ā”€ (marketing)/            # Public pages (navbar + footer)
│   ā”œā”€ā”€ page.tsx            # Landing page
│   ā”œā”€ā”€ pricing/
│   ā”œā”€ā”€ blog/
│   ā”œā”€ā”€ changelog/
│   ā”œā”€ā”€ privacy/
│   ā”œā”€ā”€ terms/
│   └── layout.tsx          # Marketing layout
│
ā”œā”€ā”€ api/                    # API routes
│   ā”œā”€ā”€ auth/[...all]/      # Better Auth handler (catch-all)
│   ā”œā”€ā”€ billing/            # Checkout, portal, invoices
│   ā”œā”€ā”€ teams/              # Team CRUD + invitations
│   ā”œā”€ā”€ webhooks/           # Payment webhooks
│   ā”œā”€ā”€ lead/               # Email lead capture
│   └── og/                 # Dynamic OG image generation
│
ā”œā”€ā”€ layout.tsx              # Root layout (fonts, metadata)
ā”œā”€ā”€ globals.css             # Design tokens + theme
└── not-found.tsx           # 404 page

The src/lib/ Directory

This is where the business logic lives:

src/lib/
ā”œā”€ā”€ auth/
│   ā”œā”€ā”€ index.ts            # Better Auth server config
│   └── client.ts           # Client-side auth hooks
│
ā”œā”€ā”€ db/
│   ā”œā”€ā”€ index.ts            # Drizzle connection (Neon HTTP)
│   └── schema/
│       ā”œā”€ā”€ auth.ts         # users, sessions, accounts, verifications
│       ā”œā”€ā”€ subscriptions.ts # subscriptions table
│       ā”œā”€ā”€ teams.ts        # teams, members, invitations
│       ā”œā”€ā”€ leads.ts        # email leads
│       └── index.ts        # Barrel export
│
ā”œā”€ā”€ payments/
│   ā”œā”€ā”€ index.ts            # Provider factory (reads PAYMENT_PROVIDER env)
│   ā”œā”€ā”€ types.ts            # PaymentProvider interface
│   ā”œā”€ā”€ sync.ts             # Webhook → database subscription sync
│   └── providers/
│       ā”œā”€ā”€ stripe.ts
│       ā”œā”€ā”€ polar.ts
│       ā”œā”€ā”€ lemon.ts
│       └── dodo.ts
│
ā”œā”€ā”€ email/
│   ā”œā”€ā”€ index.ts            # Provider factory (reads EMAIL_PROVIDER env)
│   ā”œā”€ā”€ types.ts            # EmailProvider interface
│   ā”œā”€ā”€ templates/
│   │   └── auth.ts         # Verify, reset, welcome, magic link emails
│   └── providers/
│       ā”œā”€ā”€ resend.ts
│       ā”œā”€ā”€ postmark.ts
│       ā”œā”€ā”€ sendgrid.ts
│       ā”œā”€ā”€ mailgun.ts
│       └── nodemailer.ts
│
ā”œā”€ā”€ teams/
│   └── index.ts            # Team CRUD, invitations, roles
│
ā”œā”€ā”€ admin/
│   └── index.ts            # Admin stats, user management
│
ā”œā”€ā”€ i18n/
│   ā”œā”€ā”€ config.ts           # Supported locales
│   ā”œā”€ā”€ index.ts            # Server-side translations
│   ā”œā”€ā”€ client.tsx          # React context + hooks
│   └── locales/            # JSON translation files
│
ā”œā”€ā”€ seo/
│   ā”œā”€ā”€ metadata.ts         # buildMeta() helper
│   └── structured-data.tsx # JSON-LD generators
│
ā”œā”€ā”€ blog.ts                 # MDX reader + frontmatter parser
└── utils.ts                # Shared utilities (cn, formatDate, etc.)

The src/components/ Directory

src/components/
ā”œā”€ā”€ ui/                     # Primitives (button, card, input, dialog...)
ā”œā”€ā”€ layout/                 # App shell (sidebar, header)
ā”œā”€ā”€ sections/               # Marketing page sections (hero, pricing, FAQ...)
└── blog/                   # Blog components (MDX, code copy, callouts)

The .goon/ Directory

The CLI's brain. Tracks your project state:

{
  "framework": "next",
  "tier": "pro",
  "database": "neon",
  "features": ["blog", "admin"],
  "providers": {
    "payments": "stripe",
    "email": "resend"
  }
}

The goon CLI reads this to know what's installed, what tier you're on, and which providers you're using.

Key Design Principles

  1. •

    Provider-agnostic — Payments and email use abstract interfaces. Swap providers by changing one env var. Zero code changes.

  2. •

    Route groups — (app), (auth), and (marketing) keep concerns separated. Each has its own layout.

  3. •

    Colocation — Related files live together. The billing page, billing actions, and billing API are all nearby.

  4. •

    Progressive disclosure — Start simple. Add features as you need them via goon add.

  5. •

    AI-friendly — .goon/rules.md and CLAUDE.md give AI agents the context to modify your project correctly.

Next Steps