APP_NAME="AI Exam Success API" ENVIRONMENT="development" # PostgreSQL target for production/local DB work. # If DATABASE_URL is not set, the app falls back to a local SQLite file so the # mock backend can run immediately during early development. DATABASE_URL="postgresql+psycopg://postgres:postgres@localhost:5432/exam_success" # Production recovery controls. Development does not require these. DATABASE_BACKUP_STRATEGY="" DATABASE_BACKUP_RETENTION_DAYS="14" DATABASE_RESTORE_TESTED_AT="" DATABASE_BACKUP_DIR="" CORS_ORIGINS="http://localhost:3000,http://127.0.0.1:3000,http://localhost:3003,http://127.0.0.1:3003" UPLOAD_DIR="uploads" # AI provider settings. # Use AI_PROVIDER="mock" for local free development without an API key. # Use AI_PROVIDER="sarvam" with SARVAM_API_KEY for real AI outputs (recommended). # Use AI_PROVIDER="openrouter" with OPENROUTER_API_KEY for OpenRouter models. AI_PROVIDER="sarvam" SARVAM_API_KEY="" SARVAM_BASE_URL="https://api.sarvam.ai/v1" SARVAM_MODEL_MAIN="sarvam-30b" SARVAM_MODEL_HEAVY="sarvam-105b" SARVAM_MODEL_NOTES="sarvam-30b" SARVAM_MODEL_QUIZ="sarvam-30b" SARVAM_MODEL_FLASHCARDS="sarvam-30b" SARVAM_MODEL_EXAM_MODE="sarvam-105b" SARVAM_MODEL_PYQ_ANALYSIS="sarvam-105b" SARVAM_MODEL_VIDEO_SCRIPT="sarvam-105b" SARVAM_TIMEOUT_SECONDS="90" SARVAM_MAX_RETRIES="2" AI_FALLBACK_TO_MOCK="true" MOCK_AI_MODEL_NAME="mock-exam-tutor-v1" # Exa is used only when the student explicitly asks to search the web or asks # for current/latest information. Keep this backend-only; never use NEXT_PUBLIC_. EXA_API_KEY="" EXA_BASE_URL="https://api.exa.ai" EXA_SEARCH_TIMEOUT_SECONDS="15" EXA_SEARCH_MAX_RESULTS="6" # Legacy OpenRouter settings (set AI_PROVIDER="openrouter" to use) OPENROUTER_API_KEY="" OPENROUTER_BASE_URL="https://openrouter.ai/api/v1" OPENROUTER_MODEL_MAIN="deepseek/deepseek-v4-flash" OPENROUTER_MODEL_LLAMA="qwen/qwen3-next-80b-a3b-instruct" AI_MAX_RETRIES="2" AI_TIMEOUT_SECONDS="120" # Learn Anything lesson authoring (OpenAI-compatible chat via Groq). # Server-side only — never put this in NEXT_PUBLIC_*. GROQ_API_KEY="" # Z.AI / GLM free Flash models (text + vision). Server-side only. # Text: glm-4.7-flash Vision: glm-4.6v-flash # https://docs.z.ai/ base: https://api.z.ai/api/paas/v4/ ZAI_API_KEY="" ZAI_BASE_URL="https://api.z.ai/api/paas/v4" ZAI_MODEL_TEXT="glm-4.7-flash" ZAI_MODEL_VISION="glm-4.6v-flash" ZAI_TIMEOUT_SECONDS="90" # Scale knobs for ~1k concurrent students (raise in production Postgres deploys). DATABASE_POOL_SIZE="10" DATABASE_MAX_OVERFLOW="20" RATE_LIMIT_ENABLED="true" RATE_LIMIT_AI_REQUESTS_PER_DAY="80" # TTS provider settings. # AI4Bharat Indic Parler is the local Indian-English + Malayalam teacher voice. # Accept its free Hugging Face access terms once, then set HUGGINGFACE_API_KEY. # Use TTS_PROVIDER="mock" only for silent timing tests. TTS_PROVIDER="ai4bharat" TTS_DEFAULT_PROVIDER="ai4bharat" VIDEO_TTS_PROVIDER="ai4bharat" TTS_DEFAULT_VOICE="nila" TTS_OUTPUT_DIR="public/generated/audio" AI4BHARAT_TTS_MODEL="ai4bharat/indic-parler-tts" AI4BHARAT_TTS_SPEAKER="Anjali" AI4BHARAT_TTS_ENGLISH_SPEAKER="Mary" AI4BHARAT_TTS_DEVICE="auto" AI4BHARAT_TTS_PRECISION="float32" AUDIO_SCENE_TIMEOUT_SECONDS="45" AUDIO_TOTAL_TIMEOUT_SECONDS="300" AUDIO_MAX_RETRIES="2" AUDIO_MAX_CONCURRENCY="3" KOKORO_VOICE="af_heart" KOKORO_SPEED="0.95" INDIC_TTS_MODEL="" INDIC_TTS_LANGUAGE="ml" EDGE_TTS_VOICE_EN="en-US-JennyNeural" EDGE_TTS_VOICE_ML="ml-IN-SobhanaNeural" EDGE_TTS_RATE="+15%" ELEVENLABS_API_KEY="" ELEVENLABS_VOICE_ID="" AUDIO_NORMALIZE="true" # Local Remotion final render settings. GENERATED_VIDEO_JOBS_DIR="generated-video-jobs" GENERATED_VIDEO_OUTPUT_DIR="generated-videos" VIDEO_RENDER_TIMEOUT_SECONDS="420" VIDEO_MIN_OUTPUT_BYTES="4096" VIDEO_BETA_MAX_SCENES="5" VIDEO_BETA_MAX_DURATION_SECONDS="90" VIDEO_SCENE_TEXT_MAX_CHARS="700" VIDEO_MAX_CONCURRENT_RENDER_JOBS_PER_USER="1" VIDEO_ENFORCE_BETA_LIMITS_IN_DEVELOPMENT="false" # Storage provider settings. # Local generated media is delivered through authenticated /generated routes. # Use STORAGE_PROVIDER="r2" or "s3" with an S3-compatible bucket for cloud media. STORAGE_PROVIDER="local" STORAGE_BUCKET="" STORAGE_REGION="" STORAGE_ENDPOINT_URL="" STORAGE_ACCESS_KEY_ID="" STORAGE_SECRET_ACCESS_KEY="" STORAGE_PUBLIC_BASE_URL="" STORAGE_UPLOAD_PREFIX="uploads" STORAGE_AUDIO_PREFIX="generated-audio" STORAGE_VIDEO_PREFIX="generated-videos" # Auth settings. # Demo auth is permitted only when explicitly enabled for localhost development. AUTH_ENABLED="false" AUTH_PROVIDER="dev" ALLOW_INSECURE_DEV_AUTH="true" FRONTEND_BASE_URL="http://127.0.0.1:3000" JWT_SECRET_KEY="change-this-before-real-users" JWT_ALGORITHM="HS256" ACCESS_TOKEN_EXPIRE_MINUTES="10080" SUPABASE_URL="" SUPABASE_JWT_SECRET="" SUPABASE_ANON_KEY="" # Backend only. Required to fully remove Supabase Auth identities when # AUTH_PROVIDER="supabase". Never copy this into a NEXT_PUBLIC_* variable. SUPABASE_SERVICE_ROLE_KEY="" # Transactional account email. Required for password recovery when # AUTH_PROVIDER="jwt" in production. EMAIL_PROVIDER="disabled" # disabled | resend RESEND_API_KEY="" EMAIL_FROM="DocDoe " PASSWORD_RESET_TOKEN_MINUTES="30" PASSWORD_RESET_REQUEST_COOLDOWN_SECONDS="60" # Optional Google sign-in. # Create OAuth credentials in Google Cloud and add this redirect URI: # http://127.0.0.1:8000/auth/google/callback GOOGLE_CLIENT_ID="" GOOGLE_CLIENT_SECRET="" GOOGLE_OAUTH_REDIRECT_URI="http://127.0.0.1:8000/auth/google/callback" # Beta invite gate. # Set BETA_ACCESS_ENABLED=true and a strong BETA_INVITE_CODE to require an invite # code at signup. Leave BETA_ACCESS_ENABLED=false for open signup (dev/demo). BETA_ACCESS_ENABLED="false" BETA_INVITE_CODE="" # Per-user AI rate limiting. # Set RATE_LIMIT_ENABLED=true outside local development. It prevents a single # user from exhausting credits and applies per user (JWT sub) or server-observed # client IP when no token is present. Resets every 24 hours from first request. RATE_LIMIT_ENABLED="false" RATE_LIMIT_AI_REQUESTS_PER_DAY="50" # --- Stripe Billing (Popular 299 + Premium 599 subscriptions) --- # Prefer a restricted TEST key (rk_test_...) with only the Checkout, Customers, # Subscriptions, and Billing Portal permissions this backend needs. # Create recurring test Prices for both active plans. Checkout stays disabled # until the key, webhook secret, and requested Price are all present. # Example: # STRIPE_PRICE_IDS=popular_299=price_sub_abc,premium_599=price_sub_def # For webhook testing: `stripe listen --forward-to http://127.0.0.1:8000/billing/webhook` # (this prints a local whsec_... you paste here; in prod use the dashboard endpoint secret). STRIPE_SECRET_KEY="" STRIPE_WEBHOOK_SECRET="" STRIPE_PRICE_IDS="" # ── Observability + scaling (optional; A+ when set) ─────────────────────────── # Shared rate-limit + prompt cache across replicas (e.g. Upstash free tier): REDIS_URL= # Error tracking — paste a Sentry project DSN to capture backend + frontend errors: SENTRY_DSN= SENTRY_TRACES_SAMPLE_RATE=0.1