From afa4fbcd3880a0087bbc15fc1e086ee262fd5cb5 Mon Sep 17 00:00:00 2001 From: jeromehardaway Date: Thu, 11 Jun 2026 12:40:24 -0400 Subject: [PATCH] docs(env): Reconcile .env.example with variables actually read Audit of process.env reads across src/, scripts/, prisma/, and root configs. Adds missing variables (Cloudinary server-side cloud name, Mailchimp, Slack form webhook IDs, GA ID, site URL, generator-script keys), annotates each with required/optional, secret/public, and consuming files, and removes advertised-but-unused variables (LMS_DEV_BYPASS, GITHUB_PAT, SHOPIFY_ADMIN_ACCESS_TOKEN, commented Google OAuth pair). --- .env.example | 206 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 152 insertions(+), 54 deletions(-) diff --git a/.env.example b/.env.example index bcce661c3..e6d3c50d6 100644 --- a/.env.example +++ b/.env.example @@ -1,96 +1,194 @@ -# Database -# For local development, use SQLite: -# DATABASE_URL="file:./dev.db" -# For production, use PostgreSQL (Vercel Postgres, Railway, Supabase, etc.): +# ============================================================================= +# Vets Who Code — environment variables +# +# Copy to .env.local for local development. Never commit real values. +# Every variable below is read by the running app, a config file, or a +# generator script — the consuming file(s) are noted per variable. +# +# "Required" means core app/auth breaks without it. Feature-scoped variables +# are required only when that feature is exercised. +# +# NODE_ENV and CI are also read (next.config.js, postcss.config.js, +# playwright.config.ts, src/lib/prisma.ts) but are set by Node/Next/CI +# tooling — do not set them here. +# ============================================================================= + +# --- Database ---------------------------------------------------------------- + +# Required | Secret | prisma/schema.prisma, src/pages/api/health.ts +# Local development can use SQLite: DATABASE_URL="file:./dev.db" DATABASE_URL="postgresql://username:password@hostname:port/database" -# LMS Development Access - Set to 'true' to bypass auth in development ONLY -# WARNING: Never enable in production! -LMS_DEV_BYPASS=false +# --- NextAuth / GitHub ------------------------------------------------------- -# NextAuth.js +# Required | Secret | src/pages/api/auth/options.ts, src/pages/api/health.ts, +# playwright.config.ts (test fallback) NEXTAUTH_SECRET="your-secret-key-here" + +# Required | Not secret | read internally by NextAuth, checked by +# src/pages/api/health.ts (Vercel sets this automatically in deployments) NEXTAUTH_URL="http://localhost:3000" -# GitHub OAuth (for authentication) +# Required | Not secret | src/pages/api/auth/options.ts GITHUB_CLIENT_ID="your-github-client-id" + +# Required | Secret | src/pages/api/auth/options.ts GITHUB_CLIENT_SECRET="your-github-client-secret" -# GitHub API Access (for fetching org data, repos, etc.) -GITHUB_PAT="your-github-personal-access-token" -GITHUB_TOKEN="your-github-token" +# Required | Not secret | src/pages/api/auth/options.ts — sign-in is gated on +# membership in this GitHub org GITHUB_ORG="Vets-Who-Code" -# Admin allowlist — comma-separated GitHub usernames that bypass org-membership -# check on sign-in. Keep this list minimal (founders/external admins only). +# Optional | Secret | src/lib/git-api-client.ts — GitHub API reads (org data, +# repos, PRs); requests may fail without it +GITHUB_TOKEN="your-github-token" + +# Optional | Not secret | src/pages/api/auth/options.ts — comma-separated +# GitHub usernames that bypass the org-membership check on sign-in. Keep this +# list minimal (founders/external admins only). ADMIN_GITHUB_LOGINS="" -# Dev-only escape hatch. Set to "true" ONLY when running locally with -# NODE_ENV=development to allow any GitHub user to sign in. NEVER set in -# production or preview deployments. +# Optional, dev-only | Not secret | src/pages/api/auth/options.ts — set "true" +# ONLY when running locally with NODE_ENV=development to allow any GitHub user +# to sign in. NEVER set in production or preview deployments. ALLOW_ANY_GITHUB_USER="false" -# Google Maps API (for location features) -NEXT_PUBLIC_GOOGLE_MAPS_KEY="your-google-maps-api-key" +# --- AI providers ------------------------------------------------------------ +# src/lib/ai-provider.ts picks the first configured provider (gemini | azure | +# openai | phi3). Configure at least one for AI features. -# Optional: Other OAuth providers -# GOOGLE_CLIENT_ID="your-google-client-id" -# GOOGLE_CLIENT_SECRET="your-google-client-secret" - -# AI Teaching Assistant (J0d!e) - Phase 5 -# Primary AI provider: gemini | azure | openai | phi3 +# Optional | Not secret | src/lib/ai-provider.ts — force a provider instead of +# auto-detection PRIMARY_AI_PROVIDER="gemini" -# Google Gemini (recommended for cost-effectiveness) +# Optional* | Secret | src/lib/ai-provider.ts, +# src/pages/api/api-helpers/classify-contact.ts, scripts/generate-*.ts +# (*one Gemini key — this or GEMINI_API_KEY — is needed for Gemini features) GOOGLE_GENERATIVE_AI_API_KEY="your-google-ai-api-key" -# Contact Form Spam Filter (Gemini) +# Optional* | Secret | same consumers as GOOGLE_GENERATIVE_AI_API_KEY GEMINI_API_KEY="your-gemini-api-key" + +# Optional | Not secret | src/pages/api/api-helpers/classify-contact.ts — +# contact-form spam-filter model (has a default in code) GEMINI_MODEL="gemini-2.5-flash" -# Azure OpenAI (GPT-4) +# Optional | Secret | src/lib/ai-provider.ts AZURE_OPENAI_API_KEY="your-azure-openai-key" +# Optional | Not secret | src/lib/ai-provider.ts AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com" +# Optional | Not secret | src/lib/ai-provider.ts AZURE_OPENAI_DEPLOYMENT="your-gpt4-deployment-name" -# OpenAI (GPT-4) +# Optional | Secret | src/lib/ai-provider.ts OPENAI_API_KEY="your-openai-api-key" -# Phi-3 (optional - for local/Azure AI Studio deployment) +# Optional | Not secret | src/lib/ai-provider.ts PHI3_ENDPOINT="your-phi3-endpoint" +# Optional | Secret | src/lib/ai-provider.ts PHI3_API_KEY="your-phi3-api-key" -# Lightcast (Emsi) - labor market data: salary by SOC, demand, top skills -# Both required for live data; without these, scripts fall back to Census/curated. -# Used by: src/lib/lightcast-client.ts, scripts/generate-tech-pathways.ts -LIGHTCAST_CLIENT_ID="your-lightcast-client-id" -LIGHTCAST_CLIENT_SECRET="your-lightcast-client-secret" +# --- J0dI3 AI backend -------------------------------------------------------- +# Server-side only — never prefix with NEXT_PUBLIC_. -# US Census ACS - fallback salary data when Lightcast is unavailable -CENSUS_API_KEY="your-census-api-key" +# Required for J0dI3 features | Not secret | src/lib/j0di3-client.ts +J0DI3_API_URL= +# Required for J0dI3 features | Secret | src/lib/j0di3-client.ts +J0DI3_API_KEY= -# Shopify Storefront API (for browsing products/cart) -SHOPIFY_STORE_DOMAIN="your-store.myshopify.com" -SHOPIFY_STOREFRONT_ACCESS_TOKEN="your-storefront-access-token" +# --- Cloudinary -------------------------------------------------------------- -# Shopify Admin API (optional - for making API calls to Shopify) -SHOPIFY_ADMIN_ACCESS_TOKEN="your-admin-access-token" +# Required for media | Public (client bundle) | src/lib/cloudinary.ts, +# src/lib/cloudinary-helpers.ts, src/lib/blog.ts, +# src/pages/api/upload/signature.ts, scripts/ +NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your-cloud-name" -# Shopify Webhook/API Secrets (REQUIRED for order webhooks - the API Secret Key from API credentials) -# The webhook handler will check for any of these names: -SHOPIFY_WEBHOOK_SECRET="your-webhook-secret" # Primary option -SHOPIFY_API_SECRET="your-api-secret-key" # Alternative name -SHOPIFY_CLIENT_SECRET="your-client-secret" # Alternative name +# Required for LMS media | Not secret | src/pages/api/lms/progress/index.ts, +# src/pages/api/lms/certificates/generate.ts — same value as above, read +# without the NEXT_PUBLIC_ prefix server-side +CLOUDINARY_CLOUD_NAME="your-cloud-name" -# Cloudinary (for image uploads and management) -NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your-cloud-name" +# Required for media | Not secret | src/lib/cloudinary.ts, +# src/pages/api/upload/signature.ts, src/pages/api/lms/*, scripts/ CLOUDINARY_API_KEY="your-api-key" + +# Required for media | Secret | same consumers as CLOUDINARY_API_KEY CLOUDINARY_API_SECRET="your-api-secret" -# Email Service (Resend - for sending certificate emails) +# --- Email (Resend) ---------------------------------------------------------- + +# Required for email features | Secret | src/lib/email.ts RESEND_API_KEY="your-resend-api-key" -EMAIL_FROM="noreply@vetswhocode.io" # Optional: Custom from address (requires domain verification) -# J0dI3 AI Backend (server-side only — never prefix with NEXT_PUBLIC_) -J0DI3_API_URL= -J0DI3_API_KEY= \ No newline at end of file +# Optional | Not secret | src/lib/email.ts — defaults to noreply@vetswhocode.io +# (custom address requires domain verification in Resend) +EMAIL_FROM="noreply@vetswhocode.io" + +# --- Shopify ----------------------------------------------------------------- + +# Required for store | Not secret | src/lib/shopify.ts, playwright.config.ts +SHOPIFY_STORE_DOMAIN="your-store.myshopify.com" + +# Required for store | Secret | src/lib/shopify.ts, playwright.config.ts +SHOPIFY_STOREFRONT_ACCESS_TOKEN="your-storefront-access-token" + +# Required for order webhooks | Secret | +# src/pages/api/shopify/webhooks/orders/create.ts — the handler accepts any +# one of these three names; set whichever matches your credential naming +SHOPIFY_WEBHOOK_SECRET="your-webhook-secret" +SHOPIFY_API_SECRET="your-api-secret-key" +SHOPIFY_CLIENT_SECRET="your-client-secret" + +# --- Slack form webhooks ----------------------------------------------------- +# Path segment after https://hooks.slack.com/services/ for each form. + +# Required for contact form | Secret | src/pages/api/contact.ts +CONTACT_WEBHOOK_ID="" +# Required for application form | Secret | src/pages/api/apply.ts +APPLY_WEBHOOK_ID="" +# Required for mentor/mentee forms | Secret | src/pages/api/mentor.ts, +# src/pages/api/mentee.ts +MENTOR_WEBHOOK_ID="" + +# --- Mailchimp (newsletter) -------------------------------------------------- + +# Required for newsletter signup | Secret | src/pages/api/newsletter.ts +MAILCHIMP_API_KEY="your-mailchimp-api-key" +# Required for newsletter signup | Not secret | src/pages/api/newsletter.ts +MAILCHIMP_LIST_ID="your-mailchimp-list-id" + +# --- Labor market data ------------------------------------------------------- + +# Optional | Secret | src/lib/lightcast-client.ts, +# scripts/generate-tech-pathways.ts — both needed for live Lightcast data; +# without them, code falls back to Census/curated data +LIGHTCAST_CLIENT_ID="your-lightcast-client-id" +LIGHTCAST_CLIENT_SECRET="your-lightcast-client-secret" + +# Optional | Secret | src/lib/census-client.ts — fallback salary data when +# Lightcast is unavailable +CENSUS_API_KEY="your-census-api-key" + +# --- Maps, analytics, site --------------------------------------------------- + +# Required for map components | Public (client bundle) | +# src/components/ui/google-map/index.tsx +NEXT_PUBLIC_GOOGLE_MAPS_KEY="your-google-maps-api-key" + +# Optional | Public (client bundle) | src/pages/_document.tsx — Google +# Analytics loads only when set +NEXT_PUBLIC_GOOGLE_ANALYTICS_ID="" + +# Optional | Public | next-sitemap.config.js — defaults to +# https://vetswhocode.io +NEXT_PUBLIC_SITE_URL="https://vetswhocode.io" + +# --- Content generator scripts (npm run generate:*) -------------------------- + +# Optional | Secret | scripts/generate-*.ts — legacy-named fallback Gemini API +# key, read when GEMINI_API_KEY is unset +GOOGLE_PRIVATE_KEY="" + +# Optional | Not secret | scripts/generate-tech-pathways.ts — Gemini model +# override for the tech-pathways generator +TECH_PATHWAYS_MODEL=""