Skip to main content

Configuration Overview

TalentG uses environment variables and configuration files to manage different settings across development, staging, and production environments.

Environment Variables

Required Variables

Create a .env.local file in your project root:
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key

# Application Configuration
NEXT_PUBLIC_APP_URL=http://localhost:3000
NODE_ENV=development

# Database Configuration
DATABASE_URL=your_database_connection_string

# Email Configuration
BREVO_API_KEY=your_brevo_api_key
BREVO_TEMPLATE_ID_STRENGTH_REPORT=your_template_id
EMAIL_FROM=TalentG <contact@talentg.io>
QUEUE_CRON_SECRET=your_cron_secret_for_email_processing

# File Upload Configuration
UPLOADTHING_SECRET=your_uploadthing_secret
UPLOADTHING_APP_ID=your_uploadthing_app_id

# Analytics Configuration
NEXT_PUBLIC_GA_ID=your_google_analytics_id

Optional Variables

# Payment Configuration (Production only)
STRIPE_PUBLISHABLE_KEY=your_stripe_publishable_key
STRIPE_SECRET_KEY=your_stripe_secret_key
STRIPE_WEBHOOK_SECRET=your_stripe_webhook_secret

# AI Services
OPENAI_API_KEY=your_openai_api_key
ANTHROPIC_API_KEY=your_anthropic_api_key

# Monitoring
SENTRY_DSN=your_sentry_dsn
LOG_LEVEL=info

Supabase Configuration

Project Setup

  1. Create Supabase Project:
    • Go to supabase.com
    • Create new project
    • Note down URL and anon key
  2. Database Schema:
    -- Enable necessary extensions
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
    CREATE EXTENSION IF NOT EXISTS "pgcrypto";
    
    -- Create profiles table
    CREATE TABLE profiles (
      id UUID PRIMARY KEY REFERENCES auth.users(id),
      first_name TEXT,
      last_name TEXT,
      role TEXT CHECK (role IN ('admin', 'manager', 'telecaller', 'user')),
      created_at TIMESTAMPTZ DEFAULT now(),
      updated_at TIMESTAMPTZ DEFAULT now()
    );
    
  3. Row Level Security:
    -- Enable RLS
    ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
    
    -- Create policies
    CREATE POLICY "Users can view own profile" ON profiles
      FOR SELECT USING (auth.uid() = id);
    

Authentication Setup

  1. Configure Auth Providers:
    • Go to Authentication > Providers
    • Enable Email/Password
    • Configure OAuth providers (Google, GitHub)
  2. Email Templates:
    • Customize confirmation emails
    • Set up password reset templates
    • Configure magic link templates

Next.js Configuration

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
  },
  images: {
    domains: ['supabase.co', 'your-cdn-domain.com'],
  },
  env: {
    CUSTOM_KEY: process.env.CUSTOM_KEY,
  },
  async headers() {
    return [
      {
        source: '/api/:path*',
        headers: [
          { key: 'Access-Control-Allow-Origin', value: '*' },
          { key: 'Access-Control-Allow-Methods', value: 'GET, POST, PUT, DELETE, OPTIONS' },
          { key: 'Access-Control-Allow-Headers', value: 'Content-Type, Authorization' },
        ],
      },
    ]
  },
}

module.exports = nextConfig

TypeScript Configuration

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/lib/*": ["./src/lib/*"],
      "@/types/*": ["./src/types/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

TailwindCSS Configuration

tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#f0fdf4',
          500: '#16a34a',
          600: '#15803d',
          700: '#166534',
        },
      },
      fontFamily: {
        sans: ['Inter', 'sans-serif'],
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
  ],
}

Database Configuration

Connection Pooling

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!

export const supabase = createClient(supabaseUrl, supabaseKey, {
  auth: {
    persistSession: true,
    autoRefreshToken: true,
  },
  db: {
    schema: 'public',
  },
  global: {
    headers: {
      'X-Client-Info': 'talentg-web',
    },
  },
})

Migration Management

# Install Supabase CLI
npm install -g supabase

# Initialize Supabase
supabase init

# Start local development
supabase start

# Create migration
supabase migration new add_new_table

# Apply migrations
supabase db push

Email Configuration

Brevo Setup

  1. Create Brevo Account:
    • Sign up at brevo.com
    • Verify your domain (talentg.io)
    • Get API key
  2. Email Templates:
    // lib/email.ts
    import { Brevo } from 'brevo'
    
    const brevo = new Brevo(process.env.BREVO_API_KEY)
    
    export const sendEmail = async (to: string, subject: string, html: string) => {
      const { data, error } = await brevo.emails.send({
        from: process.env.FROM_EMAIL!,
        to,
        subject,
        html,
      })
    
      if (error) {
        console.error('Email send error:', error)
        throw error
      }
    
      return data
    }
    
  3. Strength Finder Email System: The application includes an automated email system for Strength Finder PDF reports: How it works:
    • When a user completes an assessment and the PDF is generated, the system automatically enqueues an email
    • Emails are sent via Brevo with the PDF attached using stored templates
    • Daily rate limiting ensures compliance with Brevo’s 300 email/day free tier limit
    Rate Limiting:
    • Free Tier Limit: 300 emails per day
    • Over-limit handling: Excess emails are deferred to the next available time window
    • User deduplication: Only 1 strength report email per user per day
    Template Variables (for Strength Finder reports):
    {
      "FIRST_NAME": "User's first name or 'Valued User'",
      "REPORT_TITLE": "Your Strength Finder Assessment Report",
      "USER_EMAIL": "user@example.com",
      "GENERATED_DATE": "Current date in readable format",
      "ASSESSMENT_ID": "Unique assessment identifier"
    }
    
    Email Flow:
    1. User completes assessment → PDF generates
    2. PDF becomes “ready” → Email automatically enqueued
    3. Cron job processes queue hourly → Sends emails via Brevo
    4. User receives email with PDF attachment
    5. Success/failure logged in database
    Vercel Cron Setup (for production):
    // vercel.json
    {
      "crons": [
        {
          "path": "/api/email/process-queue",
          "schedule": "0 * * * *"
        }
      ]
    }
    

File Upload Configuration

UploadThing Setup

  1. Create UploadThing Account:
  2. Configure Upload Routes:
    // app/api/uploadthing/route.ts
    import { createUploadthing } from 'uploadthing/next'
    
    const f = createUploadthing()
    
    export const { POST } = f({
      image: {
        maxFileSize: '4MB',
        maxFileCount: 1,
      },
    })
    

Monitoring Configuration

Sentry Setup

// lib/sentry.ts
import * as Sentry from '@sentry/nextjs'

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: 1.0,
})

Google Analytics

// lib/analytics.ts
export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID

export const pageview = (url: string) => {
  if (typeof window !== 'undefined' && window.gtag) {
    window.gtag('config', GA_TRACKING_ID, {
      page_path: url,
    })
  }
}

Security Configuration

CORS Settings

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  
  response.headers.set('Access-Control-Allow-Origin', '*')
  response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
  response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  
  return response
}

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'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;",
          },
        ],
      },
    ]
  },
}

Environment-Specific Configs

Development

# .env.local
NODE_ENV=development
LOG_LEVEL=debug
ENABLE_ANALYTICS=false

Production

# .env.production
NODE_ENV=production
LOG_LEVEL=warn
ENABLE_ANALYTICS=true

Configuration Validation

// lib/config.ts
import { z } from 'zod'

const configSchema = z.object({
  supabaseUrl: z.string().url(),
  supabaseAnonKey: z.string().min(1),
  appUrl: z.string().url(),
  nodeEnv: z.enum(['development', 'staging', 'production']),
})

export const config = configSchema.parse({
  supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
  supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
  appUrl: process.env.NEXT_PUBLIC_APP_URL,
  nodeEnv: process.env.NODE_ENV,
})