Files
flyer-crawler.projectium.com/docs/getting-started/ENVIRONMENT.md
Torben Sorensen 45ac4fccf5
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 2m15s
comprehensive documentation review + test fixes
2026-01-28 16:35:38 -08:00

14 KiB

Environment Variables Reference

Complete guide to environment variables used in Flyer Crawler.


Quick Reference

Minimum Required Variables (Development)

Variable Example Purpose
DB_HOST localhost PostgreSQL host
DB_USER postgres PostgreSQL username
DB_PASSWORD postgres PostgreSQL password
DB_NAME flyer_crawler_dev Database name
REDIS_URL redis://localhost:6379 Redis connection URL
JWT_SECRET (32+ character string) JWT signing key
GEMINI_API_KEY AIzaSy... Google Gemini API

Source of Truth

The Zod schema at src/config/env.ts is the authoritative source for all environment variables. If a variable is not in this file, it is not used by the application.


Configuration by Environment

Production

Aspect Details
Location Gitea CI/CD secrets injected at deployment
Path /var/www/flyer-crawler.projectium.com/
File No .env file - all from CI/CD secrets

Test

Aspect Details
Location Gitea CI/CD secrets + .env.test overrides
Path /var/www/flyer-crawler-test.projectium.com/
File .env.test for test-specific values

Development Container

Aspect Details
Location .env.local file in project root
Priority Overrides defaults in compose.dev.yml
File .env.local (gitignored)

Complete Variable Reference

Database Configuration

Variable Required Default Description
DB_HOST Yes - PostgreSQL host
DB_PORT No 5432 PostgreSQL port
DB_USER Yes - Database username
DB_PASSWORD Yes - Database password
DB_NAME Yes - Database name

Environment-Specific Variables (Gitea Secrets):

Variable Environment Description
DB_USER_PROD Production Production database user
DB_PASSWORD_PROD Production Production database pass
DB_DATABASE_PROD Production Production database name
DB_USER_TEST Test Test database user
DB_PASSWORD_TEST Test Test database password
DB_DATABASE_TEST Test Test database name

Redis Configuration

Variable Required Default Description
REDIS_URL Yes - Redis connection URL
REDIS_PASSWORD No - Redis password (optional)

URL Format: redis://[user:password@]host:port

Examples:

# Development (no auth)
REDIS_URL=redis://localhost:6379

# Production (with auth)
REDIS_URL=redis://:${REDIS_PASSWORD_PROD}@localhost:6379

Authentication

Variable Required Min Length Description
JWT_SECRET Yes 32 chars JWT token signing key
JWT_SECRET_PREVIOUS No - Previous key (rotation)
GOOGLE_CLIENT_ID No - Google OAuth client ID
GOOGLE_CLIENT_SECRET No - Google OAuth secret
GITHUB_CLIENT_ID No - GitHub OAuth client ID
GITHUB_CLIENT_SECRET No - GitHub OAuth secret

Generate Secure Secret:

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

AI Services

Variable Required Description
GEMINI_API_KEY Yes* Google Gemini API key
GEMINI_RPM No Rate limit (default: 5)
AI_PRICE_QUALITY_THRESHOLD No Quality threshold (default: 0.5)

*Required for flyer processing. Application works without it but cannot extract flyer data.

Get API Key: Google AI Studio

Google Services

Variable Required Description
GOOGLE_MAPS_API_KEY No Google Maps Geocoding API
GOOGLE_CLIENT_ID No OAuth (see Authentication above)
GOOGLE_CLIENT_SECRET No OAuth (see Authentication above)

UPC Lookup APIs

Variable Required Description
UPC_ITEM_DB_API_KEY No UPC Item DB API key
BARCODE_LOOKUP_API_KEY No Barcode Lookup API key

Application Settings

Variable Required Default Description
NODE_ENV No development Environment mode
PORT No 3001 Backend server port
FRONTEND_URL No - Frontend URL (CORS)
BASE_URL No - API base URL
STORAGE_PATH No (see below) Flyer image storage path

NODE_ENV Values: development, test, staging, production

Default STORAGE_PATH: /var/www/flyer-crawler.projectium.com/flyer-images

Email/SMTP Configuration

Variable Required Default Description
SMTP_HOST No - SMTP server hostname
SMTP_PORT No 587 SMTP server port
SMTP_USER No - SMTP username
SMTP_PASS No - SMTP password
SMTP_SECURE No false Use TLS
SMTP_FROM_EMAIL No - From address for emails

Note: Email functionality degrades gracefully if not configured.

Worker Configuration

Variable Default Description
WORKER_CONCURRENCY 1 Main worker concurrency
WORKER_LOCK_DURATION 30000 Lock duration (ms)
EMAIL_WORKER_CONCURRENCY 10 Email worker concurrency
ANALYTICS_WORKER_CONCURRENCY 1 Analytics worker concurrency
CLEANUP_WORKER_CONCURRENCY 10 Cleanup worker concurrency
WEEKLY_ANALYTICS_WORKER_CONCURRENCY 1 Weekly analytics concurrency

Error Tracking (Bugsink/Sentry)

Variable Required Default Description
SENTRY_DSN No - Backend Sentry DSN
SENTRY_ENABLED No true Enable error tracking
SENTRY_ENVIRONMENT No NODE_ENV Environment name for errors
SENTRY_DEBUG No false Enable Sentry SDK debug logging
VITE_SENTRY_DSN No - Frontend Sentry DSN
VITE_SENTRY_ENABLED No true Enable frontend error tracking
VITE_SENTRY_DEBUG No false Frontend SDK debug logging

DSN Format: http://[key]@[host]:[port]/[project_id]

Dev Container DSNs:

# Backend (internal)
SENTRY_DSN=http://<key>@localhost:8000/1

# Frontend (via nginx proxy)
VITE_SENTRY_DSN=https://<key>@localhost/bugsink-api/2

Configuration Files

File Purpose
src/config/env.ts Zod schema validation - source of truth
ecosystem.config.cjs PM2 process manager (production)
ecosystem.dev.config.cjs PM2 process manager (development)
.gitea/workflows/deploy-to-prod.yml Production deployment workflow
.gitea/workflows/deploy-to-test.yml Test deployment workflow
.env.example Template with all variables
.env.local Dev container overrides (not in git)
.env.test Test environment overrides (not in git)

Adding New Variables

Checklist

  1. Update Zod Schema - Edit src/config/env.ts
  2. Add to Gitea Secrets - For prod/test environments
  3. Update Deployment Workflows - .gitea/workflows/*.yml
  4. Update PM2 Config - ecosystem.config.cjs
  5. Update .env.example - Template for developers
  6. Update this document - Add to appropriate section

Step-by-Step

1. Update Zod Schema

Edit src/config/env.ts:

const envSchema = z.object({
  // ... existing variables ...
  newSection: z.object({
    newVariable: z.string().min(1, 'NEW_VARIABLE is required'),
  }),
});

// In loadEnvVars():
newSection: {
  newVariable: process.env.NEW_VARIABLE,
},

2. Add to Gitea Secrets

  1. Go to Gitea repository Settings > Secrets
  2. Add NEW_VARIABLE with production value
  3. Add NEW_VARIABLE_TEST if test needs different value

3. Update Deployment Workflows

Edit .gitea/workflows/deploy-to-prod.yml:

env:
  NEW_VARIABLE: ${{ secrets.NEW_VARIABLE }}

Edit .gitea/workflows/deploy-to-test.yml:

env:
  NEW_VARIABLE: ${{ secrets.NEW_VARIABLE_TEST }}

4. Update PM2 Config

Edit ecosystem.config.cjs:

module.exports = {
  apps: [
    {
      env: {
        NEW_VARIABLE: process.env.NEW_VARIABLE,
      },
    },
  ],
};

Security Best Practices

Do

  • Use Gitea Secrets for prod/test
  • Use .env.local for dev (gitignored)
  • Generate secrets with cryptographic randomness
  • Rotate secrets regularly
  • Use environment-specific database users

Do Not

  • Commit secrets to git
  • Use short or predictable secrets
  • Share secrets across environments
  • Log sensitive values

Secret Generation

# Generate secure random secrets (64 hex characters)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Example output:
# a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Database Users by Environment

Environment User Database
Production flyer_crawler_prod flyer-crawler-prod
Test flyer_crawler_test flyer-crawler-test
Development postgres flyer_crawler_dev

Validation

Environment variables are validated at startup via src/config/env.ts.

Startup Validation

If validation fails, you will see:

╔════════════════════════════════════════════════════════════════╗
║           CONFIGURATION ERROR - APPLICATION STARTUP            ║
╚════════════════════════════════════════════════════════════════╝

The following environment variables are missing or invalid:

  - database.host: DB_HOST is required
  - auth.jwtSecret: JWT_SECRET must be at least 32 characters

Please check your .env file or environment configuration.

Debugging Configuration

# Check what variables are set (dev container)
podman exec flyer-crawler-dev env | grep -E "^(DB_|REDIS_|JWT_|SENTRY_)"

# Test database connection
podman exec flyer-crawler-postgres psql -U postgres -d flyer_crawler_dev -c "SELECT 1;"

# Test Redis connection
podman exec flyer-crawler-redis redis-cli ping

Troubleshooting

Variable Not Found

Error: Missing required environment variable: JWT_SECRET

Solutions:

  1. Check .env.local exists and has the variable
  2. Verify variable name matches schema exactly
  3. Restart the application after changes

Invalid Value

Error: JWT_SECRET must be at least 32 characters

Solution: Generate a longer secret value.

Wrong Environment Selected

Check NODE_ENV is set correctly:

Value Purpose
development Local dev container
test CI/CD test server
staging Pre-production testing
production Production server

Database Connection Issues

# Development
podman exec flyer-crawler-postgres psql -U postgres -d flyer_crawler_dev -c "SELECT 1;"

# If connection fails, check:
# 1. Container is running: podman ps
# 2. DB_HOST matches container network
# 3. DB_PASSWORD is correct


Last updated: January 2026