Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 151 additions & 61 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,96 +1,186 @@
# 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
# =============================================================================
# Each entry is annotated with:
# [REQUIRED] — app fails or a critical surface breaks without it
# [OPTIONAL] — feature gracefully degrades or falls back
# [DEV-ONLY] — never set in production / preview
# [PUBLIC] — exposed to the browser (NEXT_PUBLIC_ prefix)
# Each entry includes the file(s) that read it so reviewers can trace usage.
# =============================================================================


# ---- Database --------------------------------------------------------------
# [REQUIRED] Postgres in prod (Neon via @prisma/adapter-neon), SQLite locally.
# Prisma tolerates SQLite for dev/push but migrations are Postgres-only.
# Read by: prisma/* and the generated client
DATABASE_URL="postgresql://username:password@hostname:port/database"
# DATABASE_URL="file:./dev.db"

# LMS Development Access - Set to 'true' to bypass auth in development ONLY
# WARNING: Never enable in production!
LMS_DEV_BYPASS=false

# NextAuth.js
# ---- NextAuth.js -----------------------------------------------------------
# [REQUIRED] Secret used to sign session JWTs / encryption.
NEXTAUTH_SECRET="your-secret-key-here"
# [REQUIRED] Canonical site URL NextAuth uses for callback construction.
NEXTAUTH_URL="http://localhost:3000"

# GitHub OAuth (for authentication)

# ---- GitHub OAuth & API ----------------------------------------------------
# [REQUIRED] GitHub OAuth app credentials (sign-in provider).
GITHUB_CLIENT_ID="your-github-client-id"
GITHUB_CLIENT_SECRET="your-github-client-secret"

# GitHub API Access (for fetching org data, repos, etc.)
GITHUB_PAT="your-github-personal-access-token"
# [REQUIRED] Personal access token used for org/repo/PR lookups
# (org-membership gate, profile GitHub stats, etc.).
# Read by: src/lib/github.ts, src/lib/git-api-client.ts
GITHUB_TOKEN="your-github-token"

# [REQUIRED] GitHub org users must belong to in order to sign in.
# Read by: src/pages/api/auth/options.ts
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] Comma-separated GitHub usernames that bypass the org-membership
# check on sign-in. Keep minimal (founders / external admins only).
# Read by: src/pages/api/auth/options.ts
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.
# [DEV-ONLY] When "true" AND NODE_ENV=development, allows any GitHub user
# to sign in regardless of org membership. NEVER set in prod or preview.
# Read by: src/pages/api/auth/options.ts
ALLOW_ANY_GITHUB_USER="false"

# Google Maps API (for location features)
NEXT_PUBLIC_GOOGLE_MAPS_KEY="your-google-maps-api-key"

# 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
# ---- AI providers ----------------------------------------------------------
# [REQUIRED] Primary AI provider for the J0d!e teaching assistant.
# Options: gemini | azure | openai | phi3
# Read by: src/lib/ai-provider.ts
PRIMARY_AI_PROVIDER="gemini"

# Google Gemini (recommended for cost-effectiveness)
# [REQUIRED if PRIMARY_AI_PROVIDER=gemini] Gemini API key for the chat router.
# Read by: src/lib/ai-provider.ts
GOOGLE_GENERATIVE_AI_API_KEY="your-google-ai-api-key"

# Contact Form Spam Filter (Gemini)
# [REQUIRED] Gemini key used by the contact-form spam classifier
# (separate from the chat router so quotas can be split).
# Read by: src/pages/api/contact.ts (classifier)
GEMINI_API_KEY="your-gemini-api-key"

# [OPTIONAL] Gemini model override for the contact classifier.
# Default: gemini-2.5-flash
GEMINI_MODEL="gemini-2.5-flash"

# Azure OpenAI (GPT-4)
AZURE_OPENAI_API_KEY="your-azure-openai-key"
AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
AZURE_OPENAI_DEPLOYMENT="your-gpt4-deployment-name"
# [OPTIONAL] Azure OpenAI fallback for the chat router.
# Required as a set if PRIMARY_AI_PROVIDER=azure or if you want Azure failover.
# Read by: src/lib/ai-provider.ts
AZURE_OPENAI_API_KEY=""
AZURE_OPENAI_ENDPOINT=""
AZURE_OPENAI_DEPLOYMENT=""

# [OPTIONAL] OpenAI fallback for the chat router.
# Required if PRIMARY_AI_PROVIDER=openai.
# Read by: src/lib/ai-provider.ts
OPENAI_API_KEY=""

# [OPTIONAL] Phi-3 endpoint (self-hosted or Azure AI Studio).
# Required as a pair if PRIMARY_AI_PROVIDER=phi3.
# Read by: src/lib/ai-provider.ts
PHI3_ENDPOINT=""
PHI3_API_KEY=""


# ---- J0dI3 backend (Cloud Run) --------------------------------------------
# [REQUIRED] J0dI3 API base URL and key. Server-side only — never prefix with
# NEXT_PUBLIC_. Read by: src/lib/j0di3-client.ts (proxied via src/pages/api/j0di3/*)
J0DI3_API_URL=""
J0DI3_API_KEY=""


# ---- Slack webhooks (form submissions → Slack notifications) --------------
# [OPTIONAL] Each is the path component of a Slack incoming webhook URL
# (the part after https://hooks.slack.com/services/). If unset, the form
# still saves; only the Slack notification is skipped.
# Read by: src/pages/api/{apply,contact,mentor,mentee}.ts
APPLY_WEBHOOK_ID=""
CONTACT_WEBHOOK_ID=""
MENTOR_WEBHOOK_ID=""


# ---- Cloudinary (image hosting & CDN) -------------------------------------
# [REQUIRED][PUBLIC] Cloud name used by browser <Image> URLs.
# Read by: src/lib/cloudinary.ts, src/lib/blog.ts, profile/blog image rendering
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your-cloud-name"

# [REQUIRED] Server-side credentials for uploads and signed URL generation.
# Read by: src/lib/cloudinary.ts, src/pages/api/upload/*
CLOUDINARY_API_KEY="your-api-key"
CLOUDINARY_API_SECRET="your-api-secret"

# OpenAI (GPT-4)
OPENAI_API_KEY="your-openai-api-key"

# Phi-3 (optional - for local/Azure AI Studio deployment)
PHI3_ENDPOINT="your-phi3-endpoint"
PHI3_API_KEY="your-phi3-api-key"
# ---- Email (Resend) --------------------------------------------------------
# [REQUIRED] Resend API key. Required for certificate delivery, contact form
# notifications, mentor matching, etc.
# Read by: src/lib/email.ts
RESEND_API_KEY="your-resend-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"
# [OPTIONAL] Custom "From" address. Requires the sender domain to be verified
# in Resend. Defaults to the Resend sandbox if unset.
EMAIL_FROM="noreply@vetswhocode.io"

# US Census ACS - fallback salary data when Lightcast is unavailable
CENSUS_API_KEY="your-census-api-key"

# Shopify Storefront API (for browsing products/cart)
# ---- Shopify (Storefront + Admin webhooks) --------------------------------
# [REQUIRED for /store] Storefront API credentials.
# Read by: src/lib/shopify.ts
SHOPIFY_STORE_DOMAIN="your-store.myshopify.com"
SHOPIFY_STOREFRONT_ACCESS_TOKEN="your-storefront-access-token"

# Shopify Admin API (optional - for making API calls to Shopify)
SHOPIFY_ADMIN_ACCESS_TOKEN="your-admin-access-token"
# [REQUIRED for webhooks] Shopify webhook signing secret. The handler accepts
# any of the three names below for legacy compatibility — set ONE.
# Read by: src/pages/api/shopify/webhooks/*
SHOPIFY_WEBHOOK_SECRET="your-webhook-secret"
# SHOPIFY_API_SECRET="your-api-secret-key"
# SHOPIFY_CLIENT_SECRET="your-client-secret"

# 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

# Cloudinary (for image uploads and management)
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your-cloud-name"
CLOUDINARY_API_KEY="your-api-key"
CLOUDINARY_API_SECRET="your-api-secret"

# Email Service (Resend - for sending certificate emails)
RESEND_API_KEY="your-resend-api-key"
EMAIL_FROM="noreply@vetswhocode.io" # Optional: Custom from address (requires domain verification)
# ---- Maps / Analytics / Sitemap (browser-public) --------------------------
# [REQUIRED][PUBLIC] Google Maps JS key for location features (event maps).
NEXT_PUBLIC_GOOGLE_MAPS_KEY="your-google-maps-api-key"

# J0dI3 AI Backend (server-side only — never prefix with NEXT_PUBLIC_)
J0DI3_API_URL=
J0DI3_API_KEY=
# [OPTIONAL][PUBLIC] Google Analytics 4 measurement ID. When unset, the GA
# snippet is not rendered.
# Read by: src/pages/_document.tsx
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=""

# [OPTIONAL][PUBLIC] Canonical site URL for next-sitemap. Defaults to
# https://vetswhocode.io.
# Read by: next-sitemap.config.js
NEXT_PUBLIC_SITE_URL="https://vetswhocode.io"


# ---- Labor market data (military-to-tech translator) ----------------------
# [OPTIONAL] Lightcast (Emsi) credentials for live salary / demand / top
# skills. Without these, src/lib/labor-market.ts falls back to Census +
# curated data.
# Read by: src/lib/lightcast-client.ts
LIGHTCAST_CLIENT_ID=""
LIGHTCAST_CLIENT_SECRET=""

# [OPTIONAL] US Census ACS API key — fallback salary data when Lightcast is
# unavailable.
# Read by: src/lib/census-client.ts
CENSUS_API_KEY=""


# ---- Generator scripts (build-time / operator-run only) -------------------
# These are only read by scripts/ under `npm run generate:*` — they are
# never required at runtime.
#
# [OPTIONAL] Alternate Google AI key accepted by the generator scripts as a
# fallback when GOOGLE_GENERATIVE_AI_API_KEY / GEMINI_API_KEY are absent.
# Read by: scripts/generate-* (blog audio, career-pathways, training-pipeline,
# cert-equivalencies, cognitive-skills, military-systems)
GOOGLE_PRIVATE_KEY=""

# [OPTIONAL] Gemini model override for the tech-pathways generator only.
# Default: gemini-2.0-flash
# Read by: scripts/generate-tech-pathways.ts
TECH_PATHWAYS_MODEL=""
Loading