Skip to main content

Environment Variables

All configuration for CivicPulse is managed through environment variables. This page documents every variable for both the backend and frontend.


Backend Variables​

The backend reads from a .env file in the backend/ directory (or from the process environment in production). Variables marked Required will cause the server to exit with an error if not set.

Server​

VariableRequiredDefaultDescriptionExample
PORTNo3001Port the Express server listens on3001
NODE_ENVNodevelopmentRuntime environment; affects logging verbosity and error detailproduction

Authentication​

VariableRequiredDefaultDescriptionExample
JWT_SECRETYesβ€”Secret key for signing and verifying access tokens (JWT HS256). Must be at least 32 characters. Recommend 64-character hex string.a3f9b2c1...
JWT_REFRESH_SECRETYesβ€”Separate secret for signing refresh tokens. Must differ from JWT_SECRET.d7e4a1b8...
GOOGLE_CLIENT_IDYesβ€”Google OAuth 2.0 client ID for verifying ID tokens from the frontend1234567890-abc.apps.googleusercontent.com

Generate strong secrets with:

node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"

AWS​

VariableRequiredDefaultDescriptionExample
AWS_REGIONYesβ€”AWS region where DynamoDB and S3 resources are provisionedap-south-1
AWS_ACCESS_KEY_IDNo*β€”AWS access key. Not required if using IAM instance roles on EC2AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEYNo*β€”AWS secret key. Not required if using IAM instance roleswJalrXUtnFEMI/K7MDENG/...
DYNAMO_TABLEYesβ€”DynamoDB table namecivicpulse-issues
S3_BUCKETYesβ€”S3 bucket name for media uploadscivicpulse-media

*On EC2 with an IAM instance role attached, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not needed β€” the AWS SDK automatically uses the instance role credentials.

CORS​

VariableRequiredDefaultDescriptionExample
CORS_ORIGINYesβ€”Comma-separated list of allowed origins for CORS. In production this should be your frontend domain only.https://test.civicpulseindia.com or http://localhost:5174,https://test.civicpulseindia.com

Multiple origins:

CORS_ORIGIN=https://test.civicpulseindia.com,https://staging.civicpulse.in

Rate Limiting​

VariableRequiredDefaultDescriptionExample
RATE_LIMIT_WINDOW_MSNo900000Rate limit window in milliseconds. Default is 15 minutes.900000
RATE_LIMIT_MAXNo100Max requests per IP per window (general endpoints). Auth endpoints use a separate, lower limit of 20.100

Admin Portal​

VariableRequiredDefaultDescriptionExample
ADMIN_JWT_SECRETYesβ€”Separate secret for signing admin JWTs. Must be distinct from JWT_SECRET. Min 32 chars.e1f2a3b4...
DYNAMODB_ADMINS_TABLENocivicpulse-adminsDynamoDB table for admin accountscivicpulse-admins
DYNAMODB_SITE_CONFIG_TABLENocivicpulse-site-configDynamoDB table for feature flags and site configcivicpulse-site-config
DYNAMODB_DONORS_TABLENocivicpulse-donorsDynamoDB table for donor wall entriescivicpulse-donors

X / Twitter Integration​

VariableRequiredDefaultDescriptionExample
X_BEARER_TOKENNoβ€”X (Twitter) API v2 Bearer Token. Used to fetch live civic-issue mentions for the Social Wall. Without this, the app runs in demo mode with mock mentions. Requires Basic access or higher for search/recent.AAAA...
X_HANDLENocivicpulse16094X handle to monitor for civic-issue mentions (without the @). Override to use your own account. Must match VITE_X_HANDLE in the frontend.civicpulseindia
TWITTER_BEARER_TOKENNoβ€”Legacy name β€” Twitter API v2 Bearer Token for fetching donor profile pictures. Without this, donor profile images will not be fetched.AAAA...

WhatsApp Business Cloud API​

VariableRequiredDefaultDescriptionExample
WHATSAPP_TOKENNoβ€”Meta access token for the WhatsApp Business Cloud API. Without this, the Social Wall WhatsApp tab runs in demo mode with mock messages. Obtain from Meta Developer portal β†’ WhatsApp β†’ API Setup.EAABz...
WHATSAPP_VERIFY_TOKENNocivicpulse_wa_verifySecret string used to verify the webhook URL with Meta. Choose any string β€” it must match what you enter in the Meta Developer portal when registering your webhook.my_secret_token
WHATSAPP_PHONE_NUMBER_IDNodemo_phoneWhatsApp Phone Number ID from Meta Business Suite β†’ WhatsApp β†’ API Setup. Used to identify your business number in API requests.123456789012345

Instagram Graph API​

VariableRequiredDefaultDescriptionExample
IG_ACCESS_TOKENNoβ€”Long-lived user access token for the Instagram Graph API. Without this, the Social Wall Instagram tab runs in demo mode with mock mentions. Obtain from Meta Developer portal β†’ Instagram Graph API β†’ Token Generation.IGQVJWZAk...
IG_USER_IDNoβ€”Instagram Business account user ID. Required alongside IG_ACCESS_TOKEN for live mode. Find via GET /me?fields=id,username with your token.17841400...
IG_HANDLENocivicpulseInstagram handle to display in the Social Wall (without the @). This is display-only β€” the API uses IG_USER_ID for fetching.civicpulseindia

Push Notifications​

VariableRequiredDefaultDescriptionExample
VAPID_PUBLIC_KEYYes (if push enabled)β€”VAPID public key for Web Push. Generate with web-push generate-vapid-keys.BFq3...
VAPID_PRIVATE_KEYYes (if push enabled)β€”VAPID private key. Never expose this to the client.abc1...
VAPID_MAILTOYes (if push enabled)β€”Contact email included in VAPID headermailto:admin@civicpulse.in
DYNAMODB_PUSH_SUBS_TABLENocivicpulse-push-subscriptionsDynamoDB table for push subscription endpointscivicpulse-push-subscriptions

Seeding Superadmin (One-time Script)​

These variables are only used when running node backend/scripts/seed-superadmin.js:

VariableRequiredDescription
SUPERADMIN_EMAILYesEmail address for the initial superadmin
SUPERADMIN_PASSWORDYesPassword (min 12 chars, upper+lower+digit)
SUPERADMIN_NAMEYesDisplay name for the superadmin

Complete Backend .env Example​

# Server
PORT=3001
NODE_ENV=production

# Auth
JWT_SECRET=a3f9b2c1d4e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2
JWT_REFRESH_SECRET=d7e4a1b8c3f2e5d4a9b8c7f6e5d4a3b2c1f0e9d8a7b6c5d4f3e2a1b0c9d8e7f6
GOOGLE_CLIENT_ID=123456789012-abcdefghijklmnop.apps.googleusercontent.com

# Admin Portal
ADMIN_JWT_SECRET=e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2

# AWS
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=<your-access-key>
AWS_SECRET_ACCESS_KEY=<your-secret-key>

# DynamoDB β€” dev tables (civicpulse-dev-*) or prod tables (civicpulse-*)
DYNAMO_TABLE=civicpulse-dev-issues
DYNAMODB_ADMINS_TABLE=civicpulse-dev-admins
DYNAMODB_SITE_CONFIG_TABLE=civicpulse-dev-site-config
DYNAMODB_DONORS_TABLE=civicpulse-dev-donors
DYNAMODB_PUSH_SUBS_TABLE=civicpulse-dev-push-subscriptions

# S3
S3_BUCKET=civicpulse-dev-media

# Twitter API (optional β€” for donor profile pictures)
TWITTER_BEARER_TOKEN=AAAA...your-bearer-token

# Web Push (VAPID)
VAPID_PUBLIC_KEY=BFq3...your-public-key
VAPID_PRIVATE_KEY=abc1...your-private-key
VAPID_MAILTO=mailto:admin@civicpulse.in

# CORS
CORS_ORIGIN=https://test.civicpulseindia.com

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=100

Frontend Variables​

Vite exposes only variables prefixed with VITE_ to the browser bundle. Never put secrets in frontend environment variables β€” they are visible to all users in the built JavaScript.

VariableRequiredDefaultDescriptionExample
VITE_API_URLYesβ€”Full URL of the backend REST API including /api pathhttp://localhost:3001/api
VITE_WS_URLYesβ€”Base URL for the Socket.IO WebSocket connection (no /api suffix)http://localhost:3001
VITE_APP_ENVNodevelopmentEnvironment name for build tagging (see Build Naming below). Also injected as __APP_ENV__ global in the bundle.production
VITE_GOOGLE_CLIENT_IDNoβ€”Google OAuth client ID β€” enables Google sign-in on the admin login page. Without this, only email/password login is shown.1234567890-abc.apps.googleusercontent.com
VITE_GA_MEASUREMENT_IDNoβ€”Google Analytics 4 Measurement ID. Leave unset in development to avoid polluting analytics.G-XXXXXXXXXX
VITE_VAPID_PUBLIC_KEYNoβ€”VAPID public key β€” same value as backend VAPID_PUBLIC_KEY. Required for push notifications.BFq3...
VITE_X_HANDLENocivicpulse16094X handle displayed in the /test-x page and Social Wall (without the @). Should match X_HANDLE in backend.civicpulseindia
VITE_WA_CHANNEL_NAMENoMumbai Civic SenseDisplay name for your WhatsApp channel shown in the Social Wall WhatsApp tab and the /test-whatsapp page. No token needed β€” this is display-only.Bangalore Civic Watch

Build Naming (VITE_APP_ENV)​

The VITE_APP_ENV variable names your builds and git release tags. It is read by both Vite (__APP_ENV__ global) and the increment-build.js prebuild script which writes it to build.json and creates a build/<env>/<N> git tag.

# Development (default) β€” git tag: build/development/3
npm run build

# Staging β€” git tag: build/staging/3
npm run build:staging

# Production β€” git tag: build/production/3
npm run build:production

# Or inline (Unix):
VITE_APP_ENV=production npm run build

The prebuild:staging / prebuild:production lifecycle hooks in package.json pass --env <name> to the script automatically, so no manual VITE_APP_ENV export is needed when using the named scripts.

Complete Frontend .env Example (development)​

VITE_API_URL=http://localhost:3001/api
VITE_WS_URL=http://localhost:3001
# GA and push not set in dev β€” intentional

Complete Frontend .env Example (production β€” test env)​

# For test.civicpulseindia.com β€” API is on same domain, no separate subdomain
VITE_API_URL=https://test.civicpulseindia.com/api
VITE_WS_URL=https://test.civicpulseindia.com
VITE_GA_MEASUREMENT_ID=G-H9SKTTDTRD
VITE_VAPID_PUBLIC_KEY=BFq3...your-public-key
note

In the test environment the frontend is built with VITE_GA_MEASUREMENT_ID baked in at build time inside setup-ec2.sh. There is no separate frontend/.env.production file on the server β€” the variable is passed directly to npm run build.


Environment Variable Loading Order​

Backend (development)​

The backend uses the dotenv package to load .env at startup:

import 'dotenv/config';   // loads backend/.env

Values already present in process.env (set by the shell or OS) take precedence over .env values.

Frontend (Vite)​

Vite automatically loads environment variables from the following files in priority order (highest first):

.env.local          # local overrides β€” gitignored
.env.production # production-only vars
.env.development # development-only vars
.env # base vars β€” committed to repo (no secrets!)

Security Notes​

  • Never commit .env files containing real secrets to version control. Ensure .env is in .gitignore.
  • Rotate JWT_SECRET and JWT_REFRESH_SECRET immediately if they are ever exposed. Rotating these secrets invalidates all active sessions.
  • In production, prefer injecting secrets via your deployment platform's secret management (AWS Secrets Manager, Vercel Environment Variables, GitHub Actions Secrets) rather than .env files on disk.
  • The .env.example file in each package directory documents all variables with placeholder values and is safe to commit.