Configuration
Complete guide to environment variables, configuration files, and system setup for the YouTube Analyzer application.
Configuration
This document provides comprehensive information about configuring the YouTube Analyzer application, including environment variables, configuration files, deployment settings, and integration setup.
Environment Variables
The application uses a type-safe environment variable system with validation via @t3-oss/env-nextjs. All environment variables are defined and validated in env.mjs.
Required Environment Variables
Core Application
# Application URL (used for redirects, webhooks, etc.)
NEXT_PUBLIC_APP_URL=https://vidsgenius.com
# Authentication secret (generate with: openssl rand -base64 32)
AUTH_SECRET=your-secret-key-here
# Optional: NextAuth URL (only needed in development)
NEXTAUTH_URL=http://localhost:3000Database Configuration
# PostgreSQL database connection string
DATABASE_URL=postgresql://username:password@hostname:port/database
# Example for Neon
DATABASE_URL=postgresql://user:pass@ep-example.us-east-2.aws.neon.tech/database?sslmode=require
# Example for Supabase
DATABASE_URL=postgresql://postgres:password@db.example.supabase.co:5432/postgresOAuth Providers
# Google OAuth (for user authentication)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# GitHub OAuth token (for additional integrations)
GITHUB_OAUTH_TOKEN=your-github-tokenEmail Configuration
# Resend API key for email delivery
RESEND_API_KEY=re_your-resend-api-key
# From email address for notifications
EMAIL_FROM=noreply@vidsgenius.com
RESEND_FROM=VidsGenius <noreply@vidsgenius.com>Payment Processing (Stripe)
# Stripe secret key
STRIPE_API_KEY=sk_live_your-stripe-secret-key
# Stripe webhook secret for webhook verification
STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret
# Stripe Price IDs for subscription plans
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID=price_pro_monthly
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID=price_pro_yearly
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID=price_business_monthly
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID=price_business_yearlyYouTube Integration
# YouTube Data API v3 key
YOUTUBE_API_KEY=your-youtube-api-key
# Optional: Mock YouTube data for testing
MOCK_YOUTUBE=1AI Integration
# OpenAI API key for content analysis
OPENAI_API_KEY=sk-your-openai-api-key
# Optional: OpenAI organization (if applicable)
OPENAI_ORG_ID=org-your-organization-idAnalysis Workflow
# N8N webhook URL for analysis processing
N8N_WEBHOOK_URL=https://your-n8n-instance.com/webhook/youtube-process
# N8N webhook secret for security
N8N_WEBHOOK_SECRET=your-n8n-webhook-secretOptional Configuration
# Maintenance mode toggle
MAINTENANCE_MODE=false
# Vercel analytics (if using Vercel)
VERCEL_ANALYTICS=true
# Production database URL (for scripts)
PROD_DATABASE_URL=postgresql://prod-connection-stringEnvironment Variable Validation
The application validates all environment variables at startup:
// env.mjs
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
// Server-side only variables
NEXTAUTH_URL: z.string().url().optional(),
AUTH_SECRET: z.string().min(1),
GOOGLE_CLIENT_ID: z.string().min(1),
GOOGLE_CLIENT_SECRET: z.string().min(1),
DATABASE_URL: z.string().min(1),
RESEND_API_KEY: z.string().min(1),
EMAIL_FROM: z.string().min(1),
STRIPE_API_KEY: z.string().min(1),
STRIPE_WEBHOOK_SECRET: z.string().min(1),
YOUTUBE_API_KEY: z.string().min(1),
OPENAI_API_KEY: z.string().min(1),
},
client: {
// Client-side accessible variables (NEXT_PUBLIC_ prefix)
NEXT_PUBLIC_APP_URL: z.string().min(1),
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID: z.string().min(1),
},
runtimeEnv: {
// Map environment variables to schema
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
AUTH_SECRET: process.env.AUTH_SECRET,
// ... other mappings
},
});Configuration Files
Site Configuration (config/site.ts)
Central site configuration including branding, metadata, and external links:
import { SiteConfig } from "types";
export const siteConfig: SiteConfig = {
name: "VidsGenius",
description: "Powerful analytics platform for YouTube creators and marketers...",
url: env.NEXT_PUBLIC_APP_URL,
ogImage: `${env.NEXT_PUBLIC_APP_URL}/_static/og.jpg`,
links: {
twitter: "https://twitter.com/vidsgenius",
github: "https://github.com/your-org/youtube-analyzer",
},
mailSupport: "admin@vidsgenius.com",
};
export const footerLinks: SidebarNavItem[] = [
{
title: "Company",
items: [
{ title: "About", href: "/about" },
{ title: "Terms", href: "/terms" },
{ title: "Privacy", href: "/privacy" },
],
},
];Subscription Plans (config/subscriptions.ts)
Defines subscription tiers, features, and pricing. The system has been simplified to focus on core use cases:
import { SubscriptionPlan } from "types";
export const pricingData: SubscriptionPlan[] = [
{
title: "Free",
description: "Get started with basic video analysis",
benefits: [
"5 credits per month",
"Video summaries",
"Basic analysis types",
"Community support",
],
prices: {
monthly: 0,
yearly: 0,
},
stripeIds: {
monthly: null,
yearly: null,
},
},
{
title: "Starter",
description: "Perfect for individual creators and small channels",
benefits: [
"50 credits per month",
"All analysis types",
"Automation subscriptions",
"Email notifications",
"Priority support",
],
prices: {
monthly: 19,
yearly: 190,
},
stripeIds: {
monthly: env.NEXT_PUBLIC_STRIPE_STARTER_MONTHLY_PLAN_ID,
yearly: env.NEXT_PUBLIC_STRIPE_STARTER_YEARLY_PLAN_ID,
},
},
{
title: "Pro",
description: "For serious creators and growing channels",
benefits: [
"200 credits per month",
"All analysis types",
"Unlimited automation",
"Advanced email features",
"Priority support",
"Early access to new features",
],
prices: {
monthly: 49,
yearly: 490,
},
stripeIds: {
monthly: env.NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID,
yearly: env.NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID,
},
},
];
export const plansColumns: PlansRow[] = [
{
feature: "Monthly Credits",
Free: "5",
Starter: "50",
Pro: "200",
tooltip: "Credits are consumed based on analysis type complexity.",
},
{
feature: "Analysis Types",
Free: "Basic",
Starter: "All",
Pro: "All",
tooltip: "Access to video summaries, lecture summaries, and more.",
},
{
feature: "Automation",
Free: "❌",
Starter: "✅",
Pro: "✅",
tooltip: "Automatic analysis when new videos are posted.",
},
{
feature: "Email Notifications",
Free: "❌",
Starter: "✅",
Pro: "✅",
tooltip: "Get notified when analyses complete.",
},
];
// Feature flags for plan capabilities
export const PLAN_FEATURES = {
free: {
allowsAutomation: false,
allowsEmailNotifications: false,
},
starter: {
allowsAutomation: true,
allowsEmailNotifications: true,
},
pro: {
allowsAutomation: true,
allowsEmailNotifications: true,
},
} as const;Analysis Types (config/analysis-types.ts)
Defines available analysis types and their configurations. Each analysis type corresponds to a prompt file in the /prompts directory and includes feature flags for subscription gating.
export type AnalysisTypeKey = 'video-summary' | 'lecture-summary' | 'automation' | 'email-digest' | string;
export interface AnalysisTypeConfig {
key: AnalysisTypeKey; // Must match filename in /prompts directory
label: string; // Display name in UI
description: string; // User-facing description
detailedDescription?: string; // Extended description for help modal
useCase?: string; // When to use this analysis type
whatToExpect?: string; // What users can expect from results
creditCost: number; // Credits consumed per analysis
requiresSentiment: boolean; // Whether sentiment analysis is needed
active: boolean; // Whether available to users
allowsAutomation: boolean; // Can be used in automation subscriptions
allowsEmailNotifications: boolean; // Supports email notifications
}
export const ANALYSIS_TYPES: AnalysisTypeConfig[] = [
{
key: 'video-summary',
label: 'Video Summary',
description: 'Quick summary of individual YouTube videos',
detailedDescription: 'Get concise, actionable summaries of any YouTube video...',
useCase: 'Perfect for quick content review, research, or staying updated...',
whatToExpect: 'A structured summary including key points, main topics...',
creditCost: 1,
requiresSentiment: false,
active: true,
allowsAutomation: true,
allowsEmailNotifications: true,
},
{
key: 'lecture-summary',
label: 'Lecture Summary',
description: 'Educational content summaries optimized for learning',
detailedDescription: 'Specialized summaries for educational videos...',
useCase: 'Ideal for students, researchers, and educational content...',
whatToExpected: 'Learning objectives, key concepts, important details...',
creditCost: 2,
requiresSentiment: false,
active: true,
allowsAutomation: true,
allowsEmailNotifications: true,
},
{
key: 'automation',
label: 'Automation',
description: 'Automated analysis when new videos are posted',
detailedDescription: 'Set up automatic analysis subscriptions...',
useCase: 'Stay updated on channels you monitor without manual work...',
whatToExpect: 'Automatic analysis of new videos with configurable triggers...',
creditCost: 0, // Variable based on chosen analysis type
requiresSentiment: false,
active: true,
allowsAutomation: false, // Automation itself doesn't support automation
allowsEmailNotifications: true,
},
{
key: 'email-digest',
label: 'Email Digest',
description: 'Weekly summary emails of completed analyses',
detailedDescription: 'Receive organized email summaries...',
useCase: 'Perfect for busy professionals who want periodic updates...',
whatToExpect: 'Clean, organized email with your recent analysis results...',
creditCost: 1,
requiresSentiment: false,
active: true,
allowsAutomation: false,
allowsEmailNotifications: false, // Email digest IS the notification
},
];
// Helper functions for feature checking
export function getAnalysisType(key: AnalysisTypeKey): AnalysisTypeConfig | undefined {
return ANALYSIS_TYPES.find(type => type.key === key);
}
export function getActiveAnalysisTypes(): AnalysisTypeConfig[] {
return ANALYSIS_TYPES.filter(type => type.active);
}
export function getAutomationEnabledTypes(): AnalysisTypeConfig[] {
return ANALYSIS_TYPES.filter(type => type.active && type.allowsAutomation);
}Prompt File System
How it works:
- Analysis type
keymust match a.txtfile in/promptsdirectory lib/prompts.tsdynamically loads the correct prompt based onanalysisType- Variables in prompts use
{{variableName}}syntax - Available variables:
channelName,videoCount,combinedTranscripts,videosString,videoLinksWithData,performanceData,chartData
Adding a new analysis type:
- Add configuration to
ANALYSIS_TYPESarray with required fields:key: Must match filename in/promptsdirectorylabel,description: User-facing textdetailedDescription,useCase,whatToExpect: For the help modalcreditCost: Credits consumed per analysisrequiresSentiment: Whether sentiment analysis is neededactive: Whether available to users
- Create corresponding prompt file:
/prompts/{key}.txt - Use variable placeholders:
{{channelName}},{{videoCount}}, etc. - Test with different channel types and video counts
The help modal (AnalysisTypeHelpModal) automatically displays all analysis types with their detailed information to help users choose the right option.
Example prompt structure:
You are analyzing {{videoCount}} videos from {{channelName}}.
VIDEO TRANSCRIPTS:
{{combinedTranscripts}}
VIDEO DATA:
{{videosString}}
Create a summary that...Dashboard Navigation (config/dashboard.ts)
Configures the dashboard sidebar navigation:
import { UserRole } from "@prisma/client";
import { SidebarNavItem } from "types";
export const sidebarLinks: SidebarNavItem[] = [
{
title: "MENU",
items: [
{
href: "/admin",
icon: "laptop",
title: "Admin Panel",
authorizeOnly: UserRole.ADMIN,
},
{ href: "/dashboard", icon: "dashboard", title: "Dashboard" },
{
href: "/dashboard/analysis",
icon: "search",
title: "Analysis",
},
{
href: "/dashboard/subscriptions",
icon: "billing",
title: "Subscriptions",
},
{
href: "/dashboard/history",
icon: "bookOpen",
title: "History",
},
{
href: "/dashboard/billing",
icon: "billing",
title: "Billing",
},
],
},
];Documentation Configuration (config/docs.ts)
Organizes documentation navigation and structure:
import { DocsConfig } from "types";
export const docsConfig: DocsConfig = {
mainNav: [
{
title: "Documentation",
href: "/docs",
},
{
title: "Guides",
href: "/guides",
},
{
title: "Developer Docs",
href: "/developer-docs",
},
],
sidebarNav: [
{
title: "Getting Started",
items: [
{
title: "Introduction",
href: "/docs",
},
{
title: "Installation",
href: "/docs/installation",
},
],
},
{
title: "Developer Documentation",
items: [
{
title: "Introduction",
href: "/developer-docs",
},
{
title: "Architecture Overview",
href: "/developer-docs/architecture",
},
// Additional developer docs...
],
},
],
};Marketing Configuration (config/marketing.ts)
Configures public marketing site navigation:
import { MarketingConfig } from "types";
export const marketingConfig: MarketingConfig = {
mainNav: [
{
title: "Pricing",
href: "/pricing",
},
{
title: "Features",
href: "/features",
},
{
title: "Documentation",
href: "/docs",
},
],
};Authentication Configuration
Auth.js Configuration (auth.config.ts)
Configures OAuth providers and authentication methods:
import type { NextAuthConfig } from "next-auth";
import Google from "next-auth/providers/google";
import Resend from "next-auth/providers/resend";
export default {
providers: [
Google({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
}),
Resend({
apiKey: env.RESEND_API_KEY,
from: env.EMAIL_FROM,
sendVerificationRequest: customEmailHandler,
}),
],
} satisfies NextAuthConfig;Full Auth Configuration (auth.ts)
Complete authentication setup with callbacks and session handling:
import NextAuth from "next-auth";
import { PrismaAdapter } from "@auth/prisma-adapter";
export const { handlers: { GET, POST }, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
session: { strategy: "jwt" },
pages: {
signIn: "/login",
error: "/auth/error",
},
callbacks: {
async session({ token, session }) {
if (token) {
session.user.id = token.id;
session.user.role = token.role;
}
return session;
},
async jwt({ token }) {
if (!token.sub) return token;
const existingUser = await getUserById(token.sub);
if (!existingUser) return token;
token.role = existingUser.role;
return token;
},
},
...authConfig,
});Integration Configurations
YouTube API Setup
-
Create Google Cloud Project
# Visit: https://console.cloud.google.com/ # Create new project or select existing -
Enable YouTube Data API v3
# Navigate to APIs & Services > Library # Search for "YouTube Data API v3" # Click "Enable" -
Create API Key
# APIs & Services > Credentials # Create Credentials > API Key # Restrict key to YouTube Data API v3 -
Configure API Key Restrictions
# Application restrictions: HTTP referrers # API restrictions: YouTube Data API v3 # Set quotas and usage limits
Stripe Configuration
-
Create Stripe Account
# Visit: https://dashboard.stripe.com/register -
Create Products and Prices
# Products > Add Product # Set recurring billing for subscriptions # Copy Price IDs for environment variables -
Configure Webhooks
# Developers > Webhooks > Add endpoint # Endpoint URL: https://yourdomain.com/api/webhooks/stripe # Events: checkout.session.completed, invoice.payment_succeeded -
API Keys
# Developers > API Keys # Copy Secret key for STRIPE_API_KEY # Copy Webhook signing secret
OpenAI Configuration
-
Create OpenAI Account
# Visit: https://platform.openai.com/signup -
Generate API Key
# API Keys > Create new secret key # Set usage limits and monitoring -
Configure Organization (Optional)
# Settings > Organization # Copy Organization ID if needed
Resend Email Configuration
-
Create Resend Account
# Visit: https://resend.com/signup -
Verify Domain
# Domains > Add Domain # Add DNS records for verification -
Create API Key
# API Keys > Create API Key # Set appropriate permissions
Database Configuration
Connection Setup
Neon (Recommended)
# 1. Create Neon account: https://neon.tech/
# 2. Create new project
# 3. Copy connection string
DATABASE_URL=postgresql://username:password@ep-example.us-east-2.aws.neon.tech/database?sslmode=requireSupabase
# 1. Create Supabase project: https://supabase.com/
# 2. Navigate to Settings > Database
# 3. Copy connection string
DATABASE_URL=postgresql://postgres:password@db.example.supabase.co:5432/postgresLocal PostgreSQL
# Install PostgreSQL locally
brew install postgresql # macOS
sudo apt-get install postgresql # Ubuntu
# Create database
createdb youtube_analyzer
DATABASE_URL=postgresql://username:password@localhost:5432/youtube_analyzerMigration Commands
# Initialize Prisma
npx prisma init
# Generate Prisma client
npx prisma generate
# Create and apply migration
npx prisma migrate dev --name init
# Deploy to production
npx prisma migrate deploy
# Reset database (development only)
npx prisma migrate reset
# View database
npx prisma studioDeployment Configuration
Vercel Deployment
-
Project Setup
# Install Vercel CLI npm i -g vercel # Deploy vercel --prod -
Environment Variables
# Set in Vercel dashboard or CLI vercel env add AUTH_SECRET vercel env add DATABASE_URL # ... other variables -
Build Configuration (
vercel.json){ "framework": "nextjs", "buildCommand": "npm run build", "devCommand": "npm run dev", "installCommand": "npm install", "functions": { "app/api/**/*.ts": { "maxDuration": 30 } }, "crons": [{ "path": "/api/cron/auto-analysis", "schedule": "*/30 * * * *" }] }
Environment-Specific Configuration
Development
# .env.local
DATABASE_URL=postgresql://localhost:5432/youtube_analyzer_dev
NEXT_PUBLIC_APP_URL=http://localhost:3000
MOCK_YOUTUBE=1Staging
# Environment variables in deployment platform
DATABASE_URL=postgresql://staging-connection-string
NEXT_PUBLIC_APP_URL=https://staging.vidsgenius.com
MOCK_YOUTUBE=0Production
# Environment variables in deployment platform
DATABASE_URL=postgresql://production-connection-string
NEXT_PUBLIC_APP_URL=https://vidsgenius.com
MOCK_YOUTUBE=0
MAINTENANCE_MODE=falseFeature Flags and Toggles
Environment-Based Features
// lib/feature-flags.ts
export const featureFlags = {
autoAnalysis: process.env.NODE_ENV === 'production',
advancedAnalytics: process.env.ENABLE_ADVANCED_ANALYTICS === 'true',
maintenanceMode: process.env.MAINTENANCE_MODE === 'true',
mockYouTube: process.env.MOCK_YOUTUBE === '1',
};
// Usage in components
if (featureFlags.autoAnalysis) {
// Render auto-analysis features
}Plan-Based Features
// lib/subscription-features.ts
export const getSubscriptionFeatures = (plan: string) => {
const features = {
starter: {
creditsPerMonth: 5,
maxVideosPerAnalysis: 5,
autoAnalysis: false,
advancedAnalytics: false,
},
creator: {
creditsPerMonth: 200,
maxVideosPerAnalysis: 50,
autoAnalysis: true,
advancedAnalytics: true,
},
};
return features[plan] || features.starter;
};Subscription Feature Access (lib/subscription-features.ts)
Centralized system for checking subscription feature access with admin bypasses. This is the single source of truth for all feature gating throughout the application.
import { UserPlan } from "types";
import { ANALYSIS_TYPES } from "config/analysis-types";
import { PLAN_FEATURES } from "config/subscriptions";
// Core feature checking functions
export function canUseAutomation(
userPlan: UserPlan | null,
isAdmin: boolean = false
): boolean {
if (isAdmin) return true; // Admin bypass
if (!userPlan || userPlan.planName === 'free') return false;
return PLAN_FEATURES[userPlan.planName]?.allowsAutomation ?? false;
}
export function canUseEmailNotifications(
userPlan: UserPlan | null,
isAdmin: boolean = false
): boolean {
if (isAdmin) return true; // Admin bypass
if (!userPlan || userPlan.planName === 'free') return false;
return PLAN_FEATURES[userPlan.planName]?.allowsEmailNotifications ?? false;
}
export function canUseAnalysisType(
analysisType: string,
userPlan: UserPlan | null,
isAdmin: boolean = false
): boolean {
if (isAdmin) return true; // Admin bypass
const typeConfig = ANALYSIS_TYPES.find(t => t.key === analysisType);
if (!typeConfig?.active) return false;
// Free plan users can only use basic analysis types
if (!userPlan || userPlan.planName === 'free') {
return ['video-summary'].includes(analysisType);
}
return true; // Paid plans can use all active types
}
export function hasEnoughCredits(
analysisType: string,
userPlan: UserPlan | null,
isAdmin: boolean = false
): boolean {
if (isAdmin) return true; // Admin bypass
if (!userPlan) return false;
const typeConfig = ANALYSIS_TYPES.find(t => t.key === analysisType);
const creditCost = typeConfig?.creditCost ?? 1;
const availableCredits = userPlan.credits - userPlan.reservedCredits;
return availableCredits >= creditCost;
}Key Features:
- Admin Bypass: All functions accept an
isAdminparameter that bypasses restrictions - Centralized Logic: Single place to change feature access rules
- Type Safety: Uses TypeScript types from config files
- Consistent API: All functions follow the same pattern for easy usage
Usage Examples:
// In a React component
const canAutomation = canUseAutomation(userPlan, user?.role === 'ADMIN');
// In an API route
if (!canUseEmailNotifications(userPlan, isAdmin)) {
return NextResponse.json({ error: "Email notifications not available" }, { status: 403 });
}
// In the frontend with admin check
const showAutomationUI = canUseAutomation(userPlan, user?.role === 'ADMIN');Integration Points:
- Frontend components use these functions to show/hide features
- API routes validate access before processing requests
- Admin users can access all features regardless of subscription
- Notification system respects email notification permissions
Security Configuration
Content Security Policy
// next.config.js
const nextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline' *.vercel-insights.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' *.youtube.com *.googleapis.com;
`.replace(/\s{2,}/g, ' ').trim()
}
]
}
];
}
};Rate Limiting Configuration
// lib/rate-limit.ts
export const rateLimitConfig = {
analysis: {
requests: 10,
window: '1h',
},
api: {
requests: 100,
window: '1h',
},
auth: {
requests: 5,
window: '15m',
},
};Monitoring and Analytics
Error Tracking
// lib/monitoring.ts
export const monitoringConfig = {
sentry: {
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
},
vercel: {
analytics: process.env.VERCEL_ANALYTICS === 'true',
},
};Performance Monitoring
// lib/performance.ts
export const performanceConfig = {
webVitals: true,
apiMonitoring: process.env.NODE_ENV === 'production',
databaseQueryLogging: process.env.NODE_ENV === 'development',
};This configuration guide provides everything needed to set up and customize the YouTube Analyzer application. For additional help with specific integrations, refer to the respective service documentation or contact support.
Related Documentation
For a complete walkthrough of how all subscription system files work together, see:
SUBSCRIPTION-ARCHITECTURE.md: Comprehensive guide to the subscription system with file-by-file explanations, examples, and troubleshooting tips.