Project Structure

How DirectoryKit's codebase is organized.

Directory overview

├── config/           # Centralized configuration
├── lib/              # Business logic and utilities
│   ├── supabase/     # Database client, auth helpers
│   ├── payments/     # Stripe integration
│   └── validations/  # Zod schemas (source of truth for types)
├── components/
│   ├── ui/           # shadcn/ui primitives
│   ├── admin/        # Admin-specific components
│   ├── directory/    # Product cards, category selectors
│   ├── forms/        # Image upload, newsletter signup
│   ├── layout/       # Header, Footer, MainLayout
│   ├── marketing/    # Promo banners, pricing cards
│   └── shared/       # Providers, pagination, error boundary
├── hooks/            # React hooks (use-user, use-features)
├── types/            # TypeScript types
├── app/
│   ├── (admin)/      # Admin route group
│   ├── (dashboard)/  # User dashboard route group
│   ├── (marketing)/  # Public pages route group
│   ├── auth/         # Authentication routes
│   └── api/          # API routes
├── scripts/          # Utility scripts
├── supabase/         # Database schema
└── messages/         # Translation files (i18n)

Route groups

DirectoryKit uses Next.js route groups (parenthesized directories) to organize pages with shared layouts:

(marketing) — Public pages

The main customer-facing pages:

  • / — Homepage with project listings
  • /categories — Browse by category
  • /project/[slug] — Project detail page
  • /blog — Blog listing and posts
  • /pricing, /faq, /help, /contact
  • /promote, /sponsor — Monetization pages
  • /privacy, /terms, /cookies — Legal pages

(dashboard) — User pages (protected)

Pages that require authentication:

  • /dashboard — User's project overview
  • /submit — Multi-step project submission
  • /edit/[slug] — Edit an existing project
  • /profile — User profile page
  • /settings — Account settings

(admin) — Admin panel

Administrative pages (requires admin role):

  • /admin — Analytics dashboard
  • /admin/projects — Manage submissions
  • /admin/categories — Category & sphere management
  • /admin/users — User management
  • /admin/sponsors — Sponsor management
  • /admin/promotions — Promotion management
  • /admin/theme — Theme customization

Config files

All customization lives in the config/ directory:

FileControls
site.config.tsBrand name, tagline, URLs, social links, contact emails
features.config.tsFeature flags — disabling hides UI and returns 404 from API
plans.config.tsPricing tiers, features per plan, Stripe price IDs
themes.config.ts14 color themes with HSL values
directory.config.tsPage size, sort options, pricing filters
advertising.config.tsSponsor/promotion pricing and placement
email.config.tsEmail provider (Resend) settings
analytics.config.tsGA and PostHog integration
payments.config.tsPayment provider selection
marketing.config.tsAd banner content
ai.config.tsAI provider and model settings
i18n.config.tsSupported locales and detection settings

Key patterns

Path alias

All imports use the @/* alias which maps to the project root:

import { siteConfig } from '@/config/site.config'
import { db } from '@/lib/supabase/database'
import { Button } from '@/components/ui/button'
import type { User } from '@/types'

Database access

All data access goes through the db singleton from lib/supabase/database.ts:

import { db } from '@/lib/supabase/database'
 
await db.find("apps", { status: "live" }, { sort: { upvotes: -1 }, limit: 10 })
await db.findOne("apps", { slug: "example" })
await db.insertOne("apps", { name: "...", slug: "..." })
await db.updateOne("apps", { id }, { $set: { status: "approved" } })

See Database Layer API for the full reference.

Type system

Zod schemas in lib/validations/schemas.ts are the source of truth. Types are derived using z.infer<> and re-exported from types/index.ts:

import type { User, App, Category } from '@/types'

Feature flags

Features are toggled in config/features.config.ts and checked via:

// API routes
import { featureGuard } from '@/lib/features'
const guard = featureGuard('partners')
if (guard) return guard // Returns 404 if disabled
 
// Client components
import { useFeatures } from '@/hooks/use-features'
const { isEnabled } = useFeatures()
if (isEnabled('ratings')) { /* show ratings UI */ }

Next steps

Ready to build? Follow the Quick Start tutorial to customize and launch your directory.