AI SaaS Template Docs
AI SaaS Template Docs
AI SaaS Template简介快速开始项目架构
配置管理项目结构数据库开发指南API 开发指南
认证系统文件管理支付和账单
自定义主题

配置管理

AI SaaS Template 采用现代化的环境变量管理和配置系统,确保在不同环境下的安全性和灵活性。所有配置通过类型安全的方式管理,并支持运行时验证。

概述

配置系统特性:

  • 环境变量管理: 统一的环境变量配置和验证
  • 类型安全: 基于 Zod 的环境变量类型推断
  • 多环境支持: 开发、测试、生产环境配置
  • 配置验证: 启动时自动验证所有必需配置
  • 敏感信息保护: 服务器端和客户端变量分离

环境变量结构

环境文件

.env.local          # 本地开发环境(不提交到版本控制)
.env.example        # 环境变量模板(可提交)
.env.production     # 生产环境变量(部署平台管理)

核心环境变量

# === 应用基本配置 ===
NODE_ENV=development
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME="AI SaaS Template"

# === 数据库配置 ===
DATABASE_URL="postgresql://username:password@localhost:5432/ai_saas_template"

# === Clerk 认证配置 ===
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_..."
CLERK_SECRET_KEY="sk_test_..."
NEXT_PUBLIC_CLERK_SIGN_IN_URL="/auth/sign-in"
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/auth/sign-up"
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL="/dashboard"
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL="/dashboard"

# === AI 服务配置 ===
# OpenAI
OPENAI_API_KEY="sk-..."
OPENAI_ORGANIZATION="org-..."

# Anthropic Claude
ANTHROPIC_API_KEY="sk-ant-..."

# Google AI
GOOGLE_AI_API_KEY="AIza..."

# XAI
XAI_API_KEY="xai-..."

# === 支付配置 (Stripe) ===
STRIPE_SECRET_KEY="sk_test_..."
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."

# === 缓存配置 (Upstash Redis) ===
UPSTASH_REDIS_REST_URL="https://..."
UPSTASH_REDIS_REST_TOKEN="..."

# === 文件存储配置 (可选) ===
CLOUDFLARE_R2_ACCESS_KEY_ID="..."
CLOUDFLARE_R2_SECRET_ACCESS_KEY="..."
CLOUDFLARE_R2_BUCKET_NAME="..."
CLOUDFLARE_R2_ENDPOINT="https://..."

# === 邮件服务配置 (可选) ===
RESEND_API_KEY="re_..."
RESEND_FROM_EMAIL="[email protected]"

# === 监控和分析 (可选) ===
SENTRY_DSN="https://..."
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID="G-..."

环境变量验证

项目使用 Zod 进行环境变量的类型验证和转换,确保启动时所有必需的配置都正确设置。

// env.ts
import { createEnv } from '@t3-oss/env-nextjs'
import { z } from 'zod'

export const env = createEnv({
  // 服务器端环境变量
  server: {
    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
    DATABASE_URL: z.string().url(),
    
    // Clerk 认证
    CLERK_SECRET_KEY: z.string().min(1),
    
    // AI 服务
    OPENAI_API_KEY: z.string().optional(),
    ANTHROPIC_API_KEY: z.string().optional(),
    GOOGLE_AI_API_KEY: z.string().optional(),
    XAI_API_KEY: z.string().optional(),
    
    // 支付
    STRIPE_SECRET_KEY: z.string().optional(),
    STRIPE_WEBHOOK_SECRET: z.string().optional(),
    
    // 缓存
    UPSTASH_REDIS_REST_URL: z.string().url().optional(),
    UPSTASH_REDIS_REST_TOKEN: z.string().optional(),
    
    // 存储
    CLOUDFLARE_R2_ACCESS_KEY_ID: z.string().optional(),
    CLOUDFLARE_R2_SECRET_ACCESS_KEY: z.string().optional(),
    CLOUDFLARE_R2_BUCKET_NAME: z.string().optional(),
    CLOUDFLARE_R2_ENDPOINT: z.string().url().optional(),
    
    // 邮件
    RESEND_API_KEY: z.string().optional(),
    RESEND_FROM_EMAIL: z.string().email().optional(),
    
    // 监控
    SENTRY_DSN: z.string().url().optional(),
  },
  
  // 客户端环境变量(必须以 NEXT_PUBLIC_ 开头)
  client: {
    NEXT_PUBLIC_APP_URL: z.string().url(),
    NEXT_PUBLIC_APP_NAME: z.string().default('AI SaaS Template'),
    
    // Clerk 认证
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
    NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.string().default('/auth/sign-in'),
    NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.string().default('/auth/sign-up'),
    NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: z.string().default('/dashboard'),
    NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL: z.string().default('/dashboard'),
    
    // 支付
    NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().optional(),
    
    // 分析
    NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: z.string().optional(),
  },
  
  // 共享环境变量
  shared: {
    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  },
  
  // 运行时环境变量
  runtimeEnv: {
    NODE_ENV: process.env.NODE_ENV,
    DATABASE_URL: process.env.DATABASE_URL,
    
    // 服务器端变量
    CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
    OPENAI_API_KEY: process.env.OPENAI_API_KEY,
    ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
    GOOGLE_AI_API_KEY: process.env.GOOGLE_AI_API_KEY,
    XAI_API_KEY: process.env.XAI_API_KEY,
    STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
    STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
    UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL,
    UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN,
    CLOUDFLARE_R2_ACCESS_KEY_ID: process.env.CLOUDFLARE_R2_ACCESS_KEY_ID,
    CLOUDFLARE_R2_SECRET_ACCESS_KEY: process.env.CLOUDFLARE_R2_SECRET_ACCESS_KEY,
    CLOUDFLARE_R2_BUCKET_NAME: process.env.CLOUDFLARE_R2_BUCKET_NAME,
    CLOUDFLARE_R2_ENDPOINT: process.env.CLOUDFLARE_R2_ENDPOINT,
    RESEND_API_KEY: process.env.RESEND_API_KEY,
    RESEND_FROM_EMAIL: process.env.RESEND_FROM_EMAIL,
    SENTRY_DSN: process.env.SENTRY_DSN,
    
    // 客户端变量
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    NEXT_PUBLIC_APP_NAME: process.env.NEXT_PUBLIC_APP_NAME,
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
    NEXT_PUBLIC_CLERK_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL,
    NEXT_PUBLIC_CLERK_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL,
    NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL,
    NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL,
    NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
    NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID,
  },
  
  // 跳过环境变量验证的条件
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
})

export type Env = typeof env

应用配置结构

项目采用模块化的配置管理方式,将不同类型的配置分别管理,确保可维护性和扩展性。

应用基础配置

// src/config/app.ts
import { env } from '@/env'

export const appConfig = {
  name: env.NEXT_PUBLIC_APP_NAME,
  url: env.NEXT_PUBLIC_APP_URL,
  description: '基于 Next.js 15 和现代技术栈构建的 AI SaaS 应用模板',
  
  // 应用元数据
  meta: {
    title: 'AI SaaS Template - 现代化 AI SaaS 解决方案',
    description: '使用 Next.js 15、React 19、tRPC 和 Clerk Auth 构建现代 AI SaaS 应用',
    keywords: ['AI', 'SaaS', 'Next.js', 'TypeScript', 'tRPC', 'Clerk', 'OpenAI'],
    author: 'AI SaaS Template',
    version: '2.0.0',
  },

  // 社交媒体链接
  social: {
    github: 'https://github.com/geallenboy/ai-saas-template',
    twitter: '@ai_saas_template',
  },

  // 联系方式
  contact: {
    email: '[email protected]',
    support: '[email protected]',
  },

  // 默认设置
  defaults: {
    locale: 'zh',
    theme: 'system',
    currency: 'USD',
    timezone: 'UTC',
  },

  // 功能开关
  features: {
    auth: true,
    payments: env.STRIPE_SECRET_KEY ? true : false,
    ai: env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY ? true : false,
    analytics: env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID ? true : false,
    redis: env.UPSTASH_REDIS_REST_URL ? true : false,
  },
} as const

export type AppConfig = typeof appConfig

tRPC 配置

// src/lib/trpc/server.ts
import { z } from 'zod'
import { createTRPCRouter, protectedProcedure, publicProcedure } from './trpc'
import { env } from '@/env'

// tRPC 服务器配置
export const trpcConfig = {
  // API 路径
  apiPath: '/api/trpc',
  
  // 超时设置
  timeout: 30000,
  
  // 限流配置
  rateLimit: {
    enabled: env.NODE_ENV === 'production',
    requests: 100,
    window: '15m',
  },
  
  // 错误处理
  errorHandling: {
    includeStack: env.NODE_ENV === 'development',
    logErrors: true,
  },
} as const

Clerk 认证配置

// src/lib/clerk.ts
import { ClerkProvider } from '@clerk/nextjs'
import { env } from '@/env'

export const clerkConfig = {
  publishableKey: env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
  secretKey: env.CLERK_SECRET_KEY,
  
  // 路由配置
  signInUrl: env.NEXT_PUBLIC_CLERK_SIGN_IN_URL,
  signUpUrl: env.NEXT_PUBLIC_CLERK_SIGN_UP_URL,
  afterSignInUrl: env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL,
  afterSignUpUrl: env.NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL,
  
  // 主题配置
  appearance: {
    elements: {
      formButtonPrimary: 'bg-primary text-primary-foreground hover:bg-primary/90',
      card: 'bg-card',
      headerTitle: 'text-foreground',
      headerSubtitle: 'text-muted-foreground',
    },
  },
  
  // 本地化配置
  localization: {
    locale: 'zh-CN',
  },
} as const

AI 服务配置

// src/lib/ai/config.ts
import { env } from '@/env'

export const aiConfig = {
  // OpenAI 配置
  openai: {
    enabled: !!env.OPENAI_API_KEY,
    apiKey: env.OPENAI_API_KEY,
    organization: env.OPENAI_ORGANIZATION,
    defaultModel: 'gpt-4-turbo-preview',
    maxTokens: 4000,
    temperature: 0.7,
  },
  
  // Anthropic Claude 配置
  anthropic: {
    enabled: !!env.ANTHROPIC_API_KEY,
    apiKey: env.ANTHROPIC_API_KEY,
    defaultModel: 'claude-3-sonnet-20240229',
    maxTokens: 4000,
    temperature: 0.7,
  },
  
  // Google AI 配置
  googleAI: {
    enabled: !!env.GOOGLE_AI_API_KEY,
    apiKey: env.GOOGLE_AI_API_KEY,
    defaultModel: 'gemini-pro',
    maxTokens: 4000,
    temperature: 0.7,
  },
  
  // XAI 配置
  xai: {
    enabled: !!env.XAI_API_KEY,
    apiKey: env.XAI_API_KEY,
    defaultModel: 'grok-beta',
    maxTokens: 4000,
    temperature: 0.7,
  },
  
  // 通用设置
  common: {
    defaultProvider: 'openai',
    timeout: 30000,
    retries: 3,
    streaming: true,
  },
} as const

export type AIConfig = typeof aiConfig

数据库配置

// src/lib/db/config.ts
import { env } from '@/env'
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'

// 数据库连接配置
export const dbConfig = {
  url: env.DATABASE_URL,
  
  // 连接池配置
  connection: {
    max: 20,
    idle_timeout: 20,
    connect_timeout: 10,
  },
  
  // SSL 配置
  ssl: env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
  
  // 日志配置
  logging: env.NODE_ENV === 'development',
  
  // 并行连接数
  prepare: false,
} as const

// 创建数据库实例
const client = postgres(env.DATABASE_URL, dbConfig.connection)
export const db = drizzle(client, {
  logger: dbConfig.logging,
})

export type Database = typeof db

Stripe 支付配置

// src/lib/stripe/config.ts
import { env } from '@/env'
import Stripe from 'stripe'

export const stripeConfig = {
  enabled: !!env.STRIPE_SECRET_KEY,
  secretKey: env.STRIPE_SECRET_KEY!,
  publishableKey: env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
  webhookSecret: env.STRIPE_WEBHOOK_SECRET!,
  
  // API 版本
  apiVersion: '2023-10-16' as Stripe.LatestApiVersion,
  
  // 货币配置
  currency: 'usd',
  
  // 订阅计划配置
  plans: {
    basic: {
      name: 'Basic Plan',
      price: 9.99,
      interval: 'month' as const,
      features: [
        'Up to 5 projects',
        '10GB storage',
        'Email support',
        'Basic analytics',
      ],
      limits: {
        projects: 5,
        storage: 10 * 1024 * 1024 * 1024, // 10GB
        aiRequests: 1000,
      },
    },
    pro: {
      name: 'Pro Plan',
      price: 29.99,
      interval: 'month' as const,
      features: [
        'Unlimited projects',
        '100GB storage',
        'Priority support',
        'Advanced analytics',
        'Team collaboration',
      ],
      limits: {
        projects: -1, // unlimited
        storage: 100 * 1024 * 1024 * 1024, // 100GB
        aiRequests: 10000,
      },
    },
  },
  
  // Webhook 事件配置
  webhookEvents: [
    'checkout.session.completed',
    'customer.subscription.created',
    'customer.subscription.updated',
    'customer.subscription.deleted',
    'invoice.payment_succeeded',
    'invoice.payment_failed',
  ],
} as const

export type StripeConfig = typeof stripeConfig

配置管理最佳实践

配置加载和验证

// src/lib/config/index.ts
import { env } from '@/env'
import { appConfig } from './app'
import { stripeConfig } from './stripe'
import { aiConfig } from './ai'

// 统一的配置导出
export const config = {
  app: appConfig,
  stripe: stripeConfig,
  ai: aiConfig,
  env,
} as const

// 配置验证工具
export function validateRequiredConfig() {
  const requiredEnvVars = [
    'DATABASE_URL',
    'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY',
    'CLERK_SECRET_KEY',
  ]
  
  const missing = requiredEnvVars.filter(
    (key) => !process.env[key]
  )
  
  if (missing.length > 0) {
    throw new Error(
      `Missing required environment variables: ${missing.join(', ')}`
    )
  }
}

// 在应用启动时调用
if (typeof window === 'undefined') {
  validateRequiredConfig()
}

export type Config = typeof config

配置使用示例

// 在组件中使用配置
import { config } from '@/lib/config'
import { env } from '@/env'

// 检查功能是否启用
function PaymentButton() {
  if (!config.stripe.enabled) {
    return null
  }
  
  return (
    <button onClick={handlePayment}>
      Subscribe to {config.stripe.plans.basic.name}
    </button>
  )
}

// 在 API 路由中使用配置
import { env } from '@/env'
import { OpenAI } from 'openai'

export async function POST() {
  if (!env.OPENAI_API_KEY) {
    return new Response('OpenAI not configured', { status: 500 })
  }
  
  const openai = new OpenAI({
    apiKey: env.OPENAI_API_KEY,
  })
  
  // ... AI 调用逻辑
}

// 在服务器组件中使用配置
export default function HomePage() {
  return (
    <div>
      <h1>{config.app.meta.title}</h1>
      <p>{config.app.description}</p>
      
      {config.app.features.payments && (
        <PricingSection />
      )}
      
      {config.app.features.ai && (
        <AIFeaturesSection />
      )}
    </div>
  )
}

环境特定配置

// 开发环境配置
if (env.NODE_ENV === 'development') {
  // 启用详细日志
  console.log('Development mode enabled')
  
  // 禁用限流
  // 启用调试模式
}

// 生产环境配置
if (env.NODE_ENV === 'production') {
  // 启用错误监控
  // 启用性能监控
  // 启用限流
  
  // 禁用调试信息
  console.log = () => {}
  console.warn = () => {}
}

// 测试环境配置
if (env.NODE_ENV === 'test') {
  // 使用模拟数据
  // 禁用外部服务调用
  // 加速执行
}

常见配置问题

环境变量缺失

# 检查必需的环境变量是否设置
echo $DATABASE_URL
echo $NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
echo $CLERK_SECRET_KEY

# 复制模板文件
cp .env.example .env.local

# 编辑环境变量
vim .env.local

配置验证错误

// 在应用启动时检查配置
try {
  const env = createEnv({...})
  console.log('配置验证成功')
} catch (error) {
  console.error('配置验证失败:', error.message)
  process.exit(1)
}

生产环境部署

# Vercel 部署时设置环境变量
vercel env add DATABASE_URL
vercel env add CLERK_SECRET_KEY
vercel env add STRIPE_SECRET_KEY

# 或者在 Vercel 控制台设置
# Settings -> Environment Variables

安全最佳实践

环境变量安全

  1. 敏感信息保护

    • 绝不提交 .env.local 文件
    • 使用 .env.example 作为模板
    • 定期轮换 API 密钥
  2. 数据库安全

    • 使用强密码
    • 启用 SSL 连接
    • 限制数据库访问 IP
  3. API 密钥管理

    • 使用最小权限原则
    • 定期检查和更新 API 密钥
    • 监控 API 使用情况
// 安全的配置加载
const secretKeys = [
  'CLERK_SECRET_KEY',
  'STRIPE_SECRET_KEY',
  'OPENAI_API_KEY',
]

// 仅在服务器端使用敏感配置
if (typeof window === 'undefined') {
  // 服务器端配置
  const secrets = secretKeys.reduce((acc, key) => {
    if (process.env[key]) {
      acc[key] = process.env[key]
    }
    return acc
  }, {} as Record<string, string>)
}

维护和监控

配置更新流程

  1. 更新环境变量

    # 更新本地配置
    vim .env.local
    
    # 重启开发服务器
    npm run dev
  2. 更新生产配置

    • 在部署平台更新环境变量
    • 触发重新部署
    • 验证配置是否正常生效
  3. 配置监控

    // 监控关键配置状态
    export function checkConfigHealth() {
      const checks = {
        database: !!env.DATABASE_URL,
        auth: !!env.CLERK_SECRET_KEY,
        payments: !!env.STRIPE_SECRET_KEY,
        ai: !!(env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY),
      }
      
      return checks
    }

这个更新后的配置管理文档完全基于当前项目的技术架构,包括 Clerk Auth、tRPC、Stripe 支付、多 AI 服务提供商等现代化的配置管理方式。

On this page

概述环境变量结构环境文件核心环境变量环境变量验证应用配置结构应用基础配置tRPC 配置Clerk 认证配置AI 服务配置数据库配置Stripe 支付配置配置管理最佳实践配置加载和验证配置使用示例环境特定配置常见配置问题环境变量缺失配置验证错误生产环境部署安全最佳实践环境变量安全维护和监控配置更新流程